JavaWeb学习总结(十七)AJAX

Posted 理想条件

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaWeb学习总结(十七)AJAX相关的知识,希望对你有一定的参考价值。

JavaWeb学习总结(十七)AJAX

一、概述

  • 什么是 AJAX 请求
    AJAX 即“Asynchronous Javascript And XML”(异步 javascript 和 XML),是指一种创建交互式网页应用的网页开发技术。
  • AJAX 是一种浏览器通过 JavaScript 异步发起请求局部更新页面的技术。
  • AJAX 请求的局部更新,浏览器地址栏不会发生变化
  • 局部更新不会舍弃原来页面的内容

二、JavaScript 原生 Ajax 请求

(一)原生 Ajax 请求的步骤

  1. 我们首先要创建 XMLHttpRequest 对象
  2. 调用 open 方法设置请求参数
  3. 在 send 方法前绑定 onreadystatechange
  4. 调用 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: 请求已完成,且响应已就绪
status200: “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中的九个内置对象(转)

javaweb学习总结十七(web应用组织结构web.xml作用以及配置虚拟主机搭建网站)

GUI学习之二十七——布局管理学习总结

从零开始学深度学习编译器十七,MLIR ODS要点总结下篇

从零开始学深度学习编译器十七,MLIR ODS要点总结下篇