JavaWeb学习总结(十七)AJAX
Posted 理想条件
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaWeb学习总结(十七)AJAX相关的知识,希望对你有一定的参考价值。
JavaWeb学习总结(十七)AJAX
一、概述
- 什么是 AJAX 请求
AJAX 即“Asynchronous Javascript And XML”(异步 javascript 和 XML),是指一种创建交互式网页应用的网页开发技术。 - AJAX 是一种浏览器通过 JavaScript 异步发起请求,局部更新页面的技术。
- AJAX 请求的局部更新,浏览器地址栏不会发生变化
- 局部更新不会舍弃原来页面的内容
二、JavaScript 原生 Ajax 请求
(一)原生 Ajax 请求的步骤
- 我们首先要创建 XMLHttpRequest 对象
- 调用 open 方法设置请求参数
- 在 send 方法前绑定 onreadystatechange
- 调用 send 方法发送请求
(二)XMLHttpRequest
- XMLHttpRequest 是 AJAX 的基础
- XMLHttpRequest 用于在后台与服务器交换数据。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新
- 如需将请求发送到服务器,我们使用 XMLHttpRequest 对象的 open() 和 send() 方法:
方法 | 描述 |
---|---|
open(method,url,async) | 规定请求的类型、URL 以及是否异步处理请求。 method:请求的类型;GET 或 POST url:文件在服务器上的位置 async:true(异步)或 false(同步) |
send(string) | 将请求发送到服务器。 string:仅用于 POST 请求 |
- XMLHttpRequest 对象如果要用于 AJAX 的话,其 open() 方法的 async 参数必须设置为 true
(三)服务器响应
如需获得来自服务器的响应,请使用 XMLHttpRequest 对象的 responseText 或 responseXML 属性。
属性 | 描述 |
---|---|
responseText | 获得字符串形式的响应数据。 |
responseXML | 获得 XML 形式的响应数据。 |
开发中我们一般使用responseText
(四)onreadystatechange 事件
- 当请求被发送到服务器时,我们需要执行一些基于响应的任务。
- 每当 readyState 改变时,就会触发 onreadystatechange 事件。
- readyState 属性存有 XMLHttpRequest 的状态信息。
- 下面是 XMLHttpRequest 对象的三个重要的属性:
属性 | 描述 |
---|---|
onreadystatechange | 存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数。 |
readyState | 存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。 0: 请求未初始化 1: 服务器连接已建立 2: 请求已接收 3: 请求处理中 4: 请求已完成,且响应已就绪 |
status | 200: “OK” 404: 未找到页面 |
在 onreadystatechange 事件中,我们规定当服务器响应已做好被处理的准备时所执行的任务。
当 readyState 等于 4 且状态为 200 时,表示响应已就绪
(五)案例演示
ajax.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript">
// 在这里使用javaScript语言发起Ajax请求,访问服务器AjaxServlet中的javaScriptAjax()
function ajaxRequest()
//1、我们首先要创建XMLHttpRequest
var xmlHttpRequest = new XMLHttpRequest();
//2、调用open方法设置请求参数
xmlHttpRequest.open("GET","http://localhost:8080/WebStudy/ajaxServlet?action=javaScriptAjax",true);
//3、在send方法前绑定onreadystatechange事件,处理请求完成、响应就绪后的操作。
xmlHttpRequest.onreadystatechange=function()
//当xmlHttpRequest.readyState == 4,证明请求已完成,且响应已就绪
if (xmlHttpRequest.readyState == 4 && xmlHttpRequest.status == 200)
var jsonObj=JSON.parse(xmlHttpRequest.responseText);//responseText即服务器响应的JSON字符串
// 把响应的数据局部更新在页面上
document.getElementById("div01").innerHTML = "编号:" + jsonObj.id + " , 姓名:" + jsonObj.name;
//4、调用send方法发送请求
xmlHttpRequest.send();
</script>
</head>
<body>
<button onclick="ajaxRequest()">ajax请求</button>
<div id="div01"></div>
</body>
</html>
AjaxServlet:
import com.fox.bean.Person;
import com.google.gson.Gson;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
public class AjaxServlet extends HttpServlet
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
doPost(req, resp);
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
// 解决post请求中文乱码问题
// 一定要在获取请求参数之前调用才有效
req.setCharacterEncoding("UTF-8");
// 解决响应中文乱码
resp.setContentType("text/html; charset=UTF-8");
String action = req.getParameter("action");
try
// 获取action业务鉴别字符串,获取相应的业务 方法反射对象
Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
// 调用目标业务方法
method.invoke(this, req, resp);
catch (Exception e)
e.printStackTrace();
protected void javaScriptAjax(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
System.out.println("Ajax请求过来了");
Person person = new Person(1, "小明");
// json格式的字符串
Gson gson = new Gson();
String personJsonString = gson.toJson(person);
//服务器响应
response.getWriter().write(personJsonString);
//响应完成后,客户端怎么接收呢,这就要用到xmlHttpRequest中的responseText
web.xml:
<servlet>
<servlet-name>AjaxServlet</servlet-name>
<servlet-class>com.fox.servlet.AjaxServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AjaxServlet</servlet-name>
<url-pattern>/ajaxServlet</url-pattern>
</servlet-mapping>
这样就实现了页面的局部更新,而不是响应完成后跳转到新的页面
(六)异步请求
对于 web 开发人员来说,发送异步请求是一个巨大的进步。很多在服务器执行的任务都相当费时。AJAX 出现之前,这可能会引起应用程序挂起或停止。
但有了 AJAX,JavaScript 无需等待服务器的响应,而是:
- 在等待服务器响应时执行其他脚本
- 当响应就绪后才对响应进行处理
例如一个网页中有许多按钮,点击了按钮A,在服务器完成响应按钮A之前,无法点击其他按钮,这叫做同步;而点击了按钮A,无需等待A响应,依旧可以接着点击其他按钮,这叫做异步,能够提升用户的体验。
案例:
上例中的代码做以下改动:
function ajaxRequest()
//1、我们首先要创建XMLHttpRequest
var xmlHttpRequest = new XMLHttpRequest();
//2、调用open方法设置请求参数
xmlHttpRequest.open("GET","http://localhost:8080/WebStudy/ajaxServlet?action=javaScriptAjax",true);
//3、在send方法前绑定onreadystatechange事件,处理请求完成、响应就绪后的操作。
xmlHttpRequest.onreadystatechange=function()
if (xmlHttpRequest.readyState == 4 && xmlHttpRequest.status == 200)
var jsonObj=JSON.parse(xmlHttpRequest.responseText);//responseText即服务器响应的JSON字符串
// 把响应的数据局部更新在页面上
document.getElementById("div01").innerHTML = "编号:" + jsonObj.id + " , 姓名:" + jsonObj.name;
//4、调用send方法发送请求
xmlHttpRequest.send();
alert("我是最后一行的代码");
protected void javaScriptAjax(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
System.out.println("Ajax请求过来了");
Person person = new Person(1, "小明");
//延时3秒
try
Thread.sleep(3000);
catch (InterruptedException e)
e.printStackTrace();
// json格式的字符串
Gson gson = new Gson();
String personJsonString = gson.toJson(person);
//服务器响应
response.getWriter().write(personJsonString);
//响应完成后,客户端怎么接收呢,这就要用到xmlHttpRequest中的responseText
结果先执行完ajax.html所有脚本:
三秒后响应就绪,才局部更新:
结论:有了 AJAX,JavaScript 无需等待服务器的响应,而是在等待服务器响应时执行其他脚本,当响应就绪后才对响应进行处理
三、jQuery中 的 Ajax 请求
通过上面的代码我们发现。编写原生的 JavaScript 我们自己要写很多的代码。而且还要考虑浏览器兼容问题。所以使用起来非常的不方便。那我们工作之后怎么处理 Ajax 请求呢?我们前面学到的 jQuery 框架,它就有很好的 Ajax 解决方案。
JQuery 的 Ajax 请求一般涉及到五个方法:
-
四个 Ajax 请求方法
:
- $.ajax 方法
- $.get 方法
- $.post 方法
- $.getJSON 方法
-
一个表单序列化方法
:
- serialize()表单序列化方法
(一)$.ajax 方法
$.ajax方法参数:
-
url 表示请求的地址
-
type 表示请求的类型 GET 或 POST 请求
-
data
表示发送给服务器的数据,格式有两种:
key1=value1&key2=value2
key1: 'value1', key2: 'value2'
-
success 请求成功后响应的回调函数,传入返回后的数据,以及包含成功代码的字符串。
-
dataType
响应的数据类型,常用的数据类型有:
- text 表示纯文本
- xml 表示 xml 数据
- json 表示 json 对象
案例:
ajax.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="script/jquery-1.7.2.js"></script>
<script type="text/javascript">
$(function ()
$("#ajaxBtn").click(function ()
$.ajax(
url:"http://localhost:8080/WebStudy/ajaxServlet",
data:"action=jQueryAjax",
//或者data:action:"jQueryAjax",
type:"GET",
success:function (msg) //这个参数msg是由服务器返回,并根据dataType参数进行处理后的数据
//由于dataType是text,因此msg是text,我们要将其转换成json对象
var jsonObj=JSON.parse(msg);
$("#div01").html("编号:"+jsonObj.id+",姓名:"+jsonObj.name);
,
dataType:"text"
);
);
);
</script>
</head>
<body>
<button id="ajaxBtn">$.ajax请求</button>
<div id="div01"></div>
</body>
</html>
AjaxServlet:
import com.fox.bean.Person;
import com.google.gson.Gson;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
public class AjaxServlet extends HttpServlet
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
doPost(req, resp);
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
// 解决post请求中文乱码问题
// 一定要在获取请求参数之前调用才有效
req.setCharacterEncoding("UTF-8");
// 解决响应中文乱码
resp.setContentType("text/html; charset=UTF-8");
String action = req.getParameter("action");
try
// 获取action业务鉴别字符串,获取相应的业务 方法反射对象
Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
// 调用目标业务方法
method.invoke(this, req, resp);
catch (Exception e)
e.printStackTrace();
protected void jQueryAjax(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
Person person = new Person(1, "小明");
// json格式的字符串
Gson gson = new Gson();
String personJsonString = gson.toJson(person);
//服务器响应
response.getWriter().write(personJsonString);
web.xml:
<servlet>
<servlet-name>AjaxServlet</servlet-name>
<servlet-class>com.fox.servlet.AjaxServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AjaxServlet</servlet-name>
<url-pattern>/ajaxServlet</url-pattern>
</servlet-mapping>
从本例我们发现,如果dataType设置为text,那么还要多加一步:var jsonObj=JSON.parse(msg);
。因此我们可以直接将dataType设置为json,如下:
$.ajax(
url:"http://localhost:8080/WebStudy/ajaxServlet",
data:"action=jQueryAjax",
//或者data:action:"jQueryAjax",
type:"GET",
success:function (msg) //这个参数msg是由服务器返回,并根据dataType参数进行处理后的数据
$("#div01").html("编号:"+msg.id+",姓名:"+msg.name);
,
dataType:"json"
);
(二) . g e t 方法和 .get 方法和 .get方法和.post 方法
这是一个简单的 GET 请求功能和简单的 POST请求功能以取代复杂的 $.ajax 。请求成功时可调用回调函数。如果需要在出错时执行函数,请使用 $.ajax。
. g e t 方法和 .get 方法和 .get方法和.post 方法参数:
- url 请求的 url 地址
- data 发送的数据
- callback 成功的回调函数
- type 返回的数据类型
其实就是比 . a j a x 少了一个请求类型参数,因为 .ajax少了一个请求类型参数,因为 .ajax少了一个请求类型参数,因为.get方法和$.post 方法已经确定了请求类型是GET或POST
案例:
ajax.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="script/jquery-1.7.2.js"></script>
<script type="text/javascript">
$(function ()
$("#getBtn").click(function ()
$.get("http://localhost:8080/WebStudy/ajaxServlet"javaweb学习总结(四十七)——监听器(Listener)在开发中的应用
监听器在JavaWeb开发中用得比较多,下面说一下监听器(Listener)在开发中的常见应用
一、统计当前在线人数
在JavaWeb应用开发中,有时候我们需要统计当前在线的用户数,此时就可以使用监听器技术来实现这个功能了。
1 package me.gacl.web.listener;
2
3 import javax.servlet.ServletContext;
4 import javax.servlet.http.HttpSessionEvent;
5 import javax.servlet.http.HttpSessionListener;
6
7 /**
8 * @ClassName: OnLineCountListener
9 * @Description: 统计当前在线用户个数
10 * @author: 孤傲苍狼
11 * @date: 2014-9-10 下午10:01:26
12 *
13 */
14 public class OnLineCountListener implements HttpSessionListener {
15
16 @Override
17 public void sessionCreated(HttpSessionEvent se) {
18 ServletContext context = se.getSession().getServletContext();
19 Integer onLineCount = (Integer) context.getAttribute("onLineCount");
20 if(onLineCount==null){
21 context.setAttribute("onLineCount", 1);
22 }else{
23 onLineCount++;
24 context.setAttribute("onLineCount", onLineCount);
25 }
26 }
27
28 @Override
29 public void sessionDestroyed(HttpSessionEvent se) {
30 ServletContext context = se.getSession().getServletContext();
31 Integer onLineCount = (Integer) context.getAttribute("onLineCount");
32 if(onLineCount==null){
33 context.setAttribute("onLineCount", 1);
34 }else{
35 onLineCount--;
36 context.setAttribute("onLineCount", onLineCount);
37 }
38 }
39 }
二、自定义Session扫描器
当一个Web应用创建的Session很多时,为了避免Session占用太多的内存,我们可以选择手动将这些内存中的session销毁,那么此时也可以借助监听器技术来实现。
1 package me.gacl.web.listener;
2
3 import java.util.Collections;
4 import java.util.LinkedList;
5 import java.util.List;
6 import java.util.ListIterator;
7 import java.util.Timer;
8 import java.util.TimerTask;
9 import javax.servlet.ServletContextEvent;
10 import javax.servlet.ServletContextListener;
11 import javax.servlet.http.HttpSession;
12 import javax.servlet.http.HttpSessionEvent;
13 import javax.servlet.http.HttpSessionListener;
14
15 /**
16 * @ClassName: SessionScanerListener
17 * @Description: 自定义session扫描器
18 * @author: 孤傲苍狼
19 * @date: 2014-9-10 下午10:16:42
20 *
21 */
22 public class SessionScanerListener implements HttpSessionListener,ServletContextListener {
23
24 /**
25 * @Field: list
26 * 定义一个集合存储服务器创建的HttpSession
27 * LinkedList不是一个线程安全的集合
28 */
29 /**
30 * private List<HttpSession> list = new LinkedList<HttpSession>();
31 * 这样写涉及到线程安全问题,SessionScanerListener对象在内存中只有一个
32 * sessionCreated可能会被多个人同时调用,
33 * 当有多个人并发访问站点时,服务器同时为这些并发访问的人创建session
34 * 那么sessionCreated方法在某一时刻内会被几个线程同时调用,几个线程并发调用sessionCreated方法
35 * sessionCreated方法的内部处理是往一个集合中添加创建好的session,那么在加session的时候就会
36 * 涉及到几个Session同时抢夺集合中一个位置的情况,所以往集合中添加session时,一定要保证集合是线程安全的才行
37 * 如何把一个集合做成线程安全的集合呢?
38 * 可以使用使用 Collections.synchronizedList(List<T> list)方法将不是线程安全的list集合包装线程安全的list集合
39 */
40 //使用 Collections.synchronizedList(List<T> list)方法将LinkedList包装成一个线程安全的集合
41 private List<HttpSession> list = Collections.synchronizedList(new LinkedList<HttpSession>());
42 //定义一个对象,让这个对象充当一把锁,用这把锁来保证往list集合添加的新的session和遍历list集合中的session这两个操作达到同步
43 private Object lock = new Object();
44
45 @Override
46 public void sessionCreated(HttpSessionEvent se) {
47 System.out.println("session被创建了!!");
48 HttpSession session = se.getSession();
49
50 synchronized (lock){
51 /**
52 *将该操作加锁进行锁定,当有一个thread-1(线程1)在调用这段代码时,会先拿到lock这把锁,然后往集合中添加session,
53 *在添加session的这个过程中假设有另外一个thread-2(线程2)来访问了,thread-2可能是执行定时器任务的,
54 *当thread-2要调用run方法遍历list集合中的session时,结果发现遍历list集合中的session的那段代码被锁住了,
55 *而这把锁正在被往集合中添加session的那个thread-1占用着,因此thread-2只能等待thread-1操作完成之后才能够进行操作
56 *当thread-1添加完session之后,就把lock放开了,此时thread-2拿到lock,就可以执行遍历list集合中的session的那段代码了
57 *通过这把锁就保证了往集合中添加session和变量集合中的session这两步操作不能同时进行,必须按照先来后到的顺序来进行。
58 */
59 list.add(session);
60 }
61 }
62
63 @Override
64 public void sessionDestroyed(HttpSessionEvent se) {
65 System.out.println("session被销毁了了!!");
66 }
67
68 /* Web应用启动时触发这个事件
69 * @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
70 */
71 @Override
72 public void contextInitialized(ServletContextEvent sce) {
73 System.out.println("web应用初始化");
74 //创建定时器
75 Timer timer = new Timer();
76 //每隔30秒就定时执行任务
77 timer.schedule(new MyTask(list,lock), 0, 1000*30);
78 }
79
80 @Override
81 public void contextDestroyed(ServletContextEvent sce) {
82 System.out.println("web应用关闭");
83 }
84 }
85
86 /**
87 * @ClassName: MyTask
88 * @Description:定时器要定时执行的任务
89 * @author: 孤傲苍狼
90 * @date: 2014-9-11 上午12:02:36
91 *
92 */
93 class MyTask extends TimerTask {
94
95 //存储HttpSession的list集合
96 private List<HttpSession> list;
97 //存储传递过来的锁
98 private Object lock;
99 public MyTask(List<HttpSession> list,Object lock){
100 this.list = list;
101 this.lock = lock;
102 }
103 /* run方法指明了任务要做的事情
104 * @see java.util.TimerTask#run()
105 */
106 @Override
107 public void run() {
108 //将该操作加锁进行锁定
109 synchronized (lock) {
110 System.out.println("定时器执行!!");
111 ListIterator<HttpSession> it = list.listIterator();
112 /**
113 * 迭代list集合中的session,在迭代list集合中的session的过程中可能有别的用户来访问,
114 * 用户一访问,服务器就会为该用户创建一个session,此时就会调用sessionCreated往list集合中添加新的session,
115 * 然而定时器在定时执行扫描遍历list集合中的session时是无法知道正在遍历的list集合又添加的新的session进来了,
116 * 这样就导致了往list集合添加的新的session和遍历list集合中的session这两个操作无法达到同步
117 * 那么解决的办法就是把"list.add(session)和while(it.hasNext()){//迭代list集合}"这两段代码做成同步,
118 * 保证当有一个线程在访问"list.add(session)"这段代码时,另一个线程就不能访问"while(it.hasNext()){//迭代list集合}"这段代码
119 * 为了能够将这两段不相干的代码做成同步,只能定义一把锁(Object lock),然后给这两步操作加上同一把锁,
120 * 用这把锁来保证往list集合添加的新的session和遍历list集合中的session这两个操作达到同步
121 * 当在执行往list集合添加的新的session操作时,就必须等添加完成之后才能够对list集合进行迭代操作,
122 * 当在执行对list集合进行迭代操作时,那么必须等到迭代操作结束之后才能够往往list集合添加的新的session
123 */
124 while(it.hasNext()){
125 HttpSession session = (HttpSession) it.next();
126 /**
127 * 如果当前时间-session的最后访问时间>1000*15(15秒)
128 * session.getLastAccessedTime()获取session的最后访问时间
129 */
130 if(System.currentTimeMillis()-session.getLastAccessedTime()>1000*30){
131 //手动销毁session
132 session.invalidate();
133 //移除集合中已经被销毁的session
134 it.remove();
135 }
136 }
137 }
138 }
139 }
以上就是监听器的两个简单应用场景。
以上是关于JavaWeb学习总结(十七)AJAX的主要内容,如果未能解决你的问题,请参考以下文章
javaweb学习总结(三十七)——获得MySQL数据库自动生成的主键
JavaWeb学习总结(十七)——JSP中的九个内置对象(转)