> 文档中心 > 异步通信技术AJAX | AJAX乱码问题、异步与同步、手动封装一个jQuery库

异步通信技术AJAX | AJAX乱码问题、异步与同步、手动封装一个jQuery库

目录

一:快速搞定AJAX(第三篇)

1、AJAX乱码问题

2、AJAX的异步与同步

3、AJAX代码封装

4、手动封装一个jQuery库


一:快速搞定AJAX(第三篇)

1、AJAX乱码问题

(1)发送ajax get 或者 ajax post请求时下面两种情况?

①发送数据到服务器,服务器获取的数据是否乱码?

②服务器响应给前端的中文,会不会乱码?

(2)以Tomcat9为例:

①前端代码:填数据,发送到服务器

        测试AJAX乱码问题    window.onload = function(){ // -----------------------------------------------ajax get document.getElementById("btn1").onclick = function(){     // 创建对象     var xhr = new XMLHttpRequest();     // 注册回调函数     xhr.onreadystatechange = function (){  if (this.readyState == 4) {      if (this.status == 200) {   document.getElementById("mydiv").innerHTML = this.responseText      }  }     }     // 打开通道     var username = document.getElementById("username").value     xhr.open("GET", "/ajax/ajaxrequest7?username="+username+"&t=" + new Date().getTime(), true)     // 发送请求     xhr.send() } // -----------------------------------------------ajax post document.getElementById("btn2").onclick = function(){     // 创建对象     var xhr = new XMLHttpRequest();     // 注册回调函数     xhr.onreadystatechange = function (){  if (this.readyState == 4) {      if (this.status == 200) {   document.getElementById("mydiv").innerHTML = this.responseText      }  }     }     // 打开通道     xhr.open("POST", "/ajax/ajaxrequest7", true)     xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded")     var username = document.getElementById("username").value     // 发送请求     xhr.send("username=" + username) }    }


②后端代码:先获取数据,然后在把数据响应给服务器

package com.bjpowernode.javaweb.ajax;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;/** * @program: 代码 * @ClassName: AjaxRequest7Servlet * @version: 1.0 * @description: 测试ajax乱码问题 * @author: bjpowernode * @create: 2022-05-15 12:25 **/@WebServlet("/ajaxrequest7")public class AjaxRequest7Servlet extends HttpServlet {    @Override    protected void doGet(HttpServletRequest request, HttpServletResponse response)     throws ServletException, IOException { // 接收的中文会不会乱码----不会 String username = request.getParameter("username"); System.out.println(username); // 响应中文会有乱码吗?----会  response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); out.print(username);    }    @Override    protected void doPost(HttpServletRequest request, HttpServletResponse response)     throws ServletException, IOException { // 接收的中文会不会乱码----会 request.setCharacterEncoding("UTF-8"); String username = request.getParameter("username"); System.out.println(username); // 响应中文会有乱码吗?---会  response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); out.print(username);    }}

(3)测试结果:

对于tomcat10来说,关于字符集,我们程序员不需要干涉,不会出现乱码。

对于tomcat9和之前的版本来说:

①对于GET请求:接收前端的数据输出到控制台不会乱码;把接收到的数据重新发给浏览器,输出打印到浏览器会乱码!

②对于POST请求:接收前端的数据输出到控制台和把接收到的数据重新发给浏览器进行输出两者都会乱码!

😊发送给服务器的数据,服务器接收之后在控制台打印乱码解决

request.setCharacterEncoding("UTF-8");

 😊把接收到的数据响应给浏览器乱码解决

response.setContentType("text/html;charset=UTF-8");

2、AJAX的异步与同步

(1)什么是异步?什么是同步?

①ajax请求1和ajax请求2,同时并发,谁也不用等谁,这就是异步。(a不等b,b也不等a)

②如果ajax请求1在发送的时候需要等待ajax请求2结束之后才能发送,那么这就是同步。(a等待b,或者b等待a,只要发生等待,就是同步)

(2)异步和同步在代码上如何实现?

同步:如果第三个参数是false,这个就表示“ajax请求1”不支持异步,也就是说ajax请求1发送之后,会影响其他ajax请求的发送,只有当我这个请求结束之后,你们其他的ajax请求才能发送。

xhr1.open("请求方式", "URL", false)

异步:如果第三个参数是true,这个就表示“ajax请求2”支持异步请求,也就是说ajax请求2发送之后,不影响其他ajax请求的发送。

xhr.open("请求方式", "URL", true) 

(3)演示异步和同步

①前端代码:编写两个ajax请求,发送的都是GET请求

        演示ajax同步和异步    window.onload = function(){ // --ajax请求1 document.getElementById("btn1").onclick = function (){     var xhr = new XMLHttpRequest();     xhr.onreadystatechange = function (){  if (this.readyState == 4) {      if (this.status == 200) {   document.getElementById("div1").innerHTML = this.responseText      }else{   alert(this.status)      }  }     }     xhr.open("GET", "/ajax/ajaxrequest8?t=" + new Date().getTime(), true)     xhr.send() } // --ajax请求2 document.getElementById("btn2").onclick = function (){     var xhr = new XMLHttpRequest();     xhr.onreadystatechange = function (){  if (this.readyState == 4) {      if (this.status == 200) {   document.getElementById("div2").innerHTML = this.responseText      }else{   alert(this.status)      }  }     }     xhr.open("GET", "/ajax/ajaxrequest9?t=" + new Date().getTime(), true)     xhr.send() }    }

②后端代码:根据两个ajax发送不同的请求编写

ajax1的请求

package com.bjpowernode.javaweb.ajax;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;/** * @program: 代码 * @ClassName: AjaxRequest8Servlet * @version: 1.0 * @description: 测试ajax同步和异步 * @author: bjpowernode * @create: 2022-05-15 13:06 **/@WebServlet("/ajaxrequest8")public class AjaxRequest8Servlet extends HttpServlet {    @Override    protected void doGet(HttpServletRequest request, HttpServletResponse response)     throws ServletException, IOException { try {     // 睡眠10秒     Thread.sleep(10 * 1000); } catch (InterruptedException e) {     e.printStackTrace(); } response.setContentType("text/html;charset=UTF-8"); response.getWriter().print("ajax请求1");    }}

ajax2的请求

package com.bjpowernode.javaweb.ajax;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;/** * @program: 代码 * @ClassName: AjaxRequest8Servlet * @version: 1.0 * @description: 测试ajax同步和异步 * @author: bjpowernode * @create: 2022-05-15 13:06 **/@WebServlet("/ajaxrequest9")public class AjaxRequest9Servlet extends HttpServlet {    @Override    protected void doGet(HttpServletRequest request, HttpServletResponse response)     throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); response.getWriter().print("ajax请求2");    }}

③运行效果

😊为了方便测试展示效果,给第一个ajax1请求睡眠了10秒

😊ajax1的请求是true,说明支持异步,在睡眠10秒之内,也能发送ajax2请求,互不影响!

😊ajax1的请求是false,说明是同步,在睡眠10秒之内整个屏幕相当于是锁死的,不能发送ajax2请求!只能等待睡眠结束,ajax1请求结束,才能发送ajax2请求!

(4)什么情况下用同步? (大部分情况下我们都是使用ajax异步方式,同步很少用)

例如:用户注册

①用户名需要发送ajax请求进行校验。

②邮箱地址也需要发送ajax请求校验。

③其他的也可能需要发送ajax请求...............

④并且最终注册按钮的时候,也是发送ajax请求进行注册。

⑤那么显然,注册的Ajax请求和校验的ajax请求不能异步,必须等待所有的校验ajax请求结束之后,注册的ajax请求才能发!

3、AJAX代码封装

JQuery库的初次封装:根据id获取元素!

(1)AJAX请求相关的代码都是类似的,有很多重复的代码,那么我们不妨把这些重复的代码封装一个工具类。要发送ajax请求的话,就直接调用这个工具类中的相关函数即可。

(2)接下来,手动封装一个工具类,这个工具类我们可以把它看做是一个JS的库。我们把这个JS库起一个名字,叫做jQuery。(封装的jQuery只是一个前端的库,和后端的java没有关系,只是为了方便web前端代码的编写,提高WEB前端的开发效率)

①源码原型

        Title     window.onload = function () {     document.getElementById("mybtn").onclick = function () {  document.getElementById("div").innerHTML = "欢迎登陆"     } }            

②进行优化:优化通过id获取对象

(1)设计思路来自于CSS的语法:可以通过id选择器 #id 获取到这个元素 ,也可以通过类选择器 .class 获取到这个元素。

(2)我们发现通过id获取这个对象代码太长了,不妨封装到一个函数里面!封装一个函数代替原来的document.getElementById,封装到一个函数里面然后返回这个对象即可。做一个标记#,只有这个标记的才会调用document.getElementById获得这个对象;并且参数传进去时要调用substring函数进行截串,把#截取掉!

(3)对于函数名嫌长也可以赋值给一个符号:$ = jQuery。

// 再次进行更改 function jQuery(selector) { // selector只是一个变量     // 获取到第一个字符是不是#     if (selector.charAt(0) == "#") {  // 定义变量获得这个对象  var domObj = document.getElementById(selector.substring(1));  // 返回的dom对象  return domObj     } } // 给函数名赋值 $ = jQuery window.onload = function () {    $("#mybtn").onclick = function () {  $("#div").innerHTML = "欢迎登陆"     } }    

③再次进行优化:页面加载

封装函数,替代window.onload;封装页面加载完毕之后,执行回调函数。

  function jQuery(selector) { // selector只是一个变量     // 如果传过来的是一个字符串string     if (typeof selector == "string") {  // 获取到第一个字符是不是#  if (selector.charAt(0) == "#") {      // 直接使全局变量      var domObj = document.getElementById(selector.substring(1));      // 返回的dom对象      return domObj  }     }     // 如果传过来的是一个函数:页面加载完毕,注册回调函数     if (typeof selector == "function") {  window.onload = selector;     } } // 给函数名赋值 $ = jQuery // 把函数直接传进去 // $(function(){})的作用是:页面加载完毕,就执行里面的回调函数 // 把整个函数当做参数直接传进去 $(function () {     $("#mybtn").onclick = function () {  $("#div").innerHTML = "欢迎登陆"     } })    

 ④继续优化

(1)首先回顾javascript中的类的定义,对象的创建,属性的访问,方法的访问!

(2)对于类的创建实际上是和函数的定义是一样的,如果使用new就表示这是一个类;如果没有使用new表示这是一个函数。

(3)注意:最重要的就是prototype属性,可以用来扩展类的属性或者方法,语法格式如下:类.prototype.属性/方法 =  function(){}

(4)注意:对于静态方法的调用,虽然也是使用的 "类名.静态方法" 但是前提还是要先new对象,不然还是会当做普通函数的调用!

        回顾javascript中的类的定义,对象的创建。属性的访问,方法的访问。    // 1、在JS当中定义类 /*   这种创建类的方式也可以    User = function (usercode,username) {    }*/    function  User(usercode,username) { // 属性 this.usercode = usercode; this.username = username; // 实例方法 this.doSome = function () {     alert(username+"doSome......"); } // 静态方法 User.doOther = function () {     alert(username+"doOther......") }    }    //2、创建对象    // User(); 直接这样调用,你只是把它当做一个普通的函数去执行,不会创建对象,在堆中没有这个对象。    // new User(); 这样调用的话,其实就是调用该类的构造方法,创建对象,并且在堆中分配空间。    var user = new User("111","zhangsan");    // 访问属性    alert(user.usercode+" , "+user.username);    // 调用实例方法    user.doSome();    // 调用静态方法    User.doOther();    //3、后期新增一个fly方法,使用prototype属性    User.prototype.fly = function () { alert("飞翔.............")    }    // 调用扩展的方法    user.fly();

继续进行改造:把onclick和innerHTML封装成click()和html()函数,一定要封装彻底!

先封装innerHTML属性

(1)把innerHTML属性封装成一个html方法,然后把参数传进去即可。

(2)要搞明白是哪个对象进行条用,对于html方法,肯定还是封装子啊jQuery对象里面,所以只能这个对象才能调用;而下面的$("#mydiv")我们原来返回的是一个domobj对象;所以要进行修改,返回一个new jQuery。

(3)并封装好html方法,传一个字符串,把这个字符串传给domObj.innerHTML;但是问题又来了原来写的domObj对象是局部变量,外面并不能调用,所以要把var去掉变成全局变量

        Title    function jQuery(selector) { // 如果是字符串 if (typeof selector == "string") {     // 看开头是不是#     if (selector.charAt(0) == "#") {  //截掉#,然后传进去  // 去掉var改为全局变量  domObj = document.getElementById(selector.substring(1));  // 返回一个jQuery对象,下面才能正常调用html方法  return new jQuery();     } } // 如果是一个函数:页面加载完毕,注册回调函数 if (typeof selector == "function") {     window.onload = selector } // 封装html方法,代替domObj.innerHTML = "" this.html = function (htmlStr) {     domObj.innerHTML = htmlStr }    }    // 把函数名赋给一个变量    $ = jQuery;    $(function () { $("#mybtn").onclick = function () {     // 此时会有一个问题,domObj下没有html方法     // 所以在jQuery中封装一个html方法,返回一个jQuery即可     $("#mydiv").html("Hello"); }    })

在封装onclick属性

既然我们返回的是jQuery属性,所以$("#mybtn").onclick肯定会有问题,只有domObj这个对象才有onclick属性,所以要对onclick属性进行封装,封装要彻底!

        Title     function jQuery(selector) { // 如果是字符串 if (typeof selector == "string") {     // 看开头是不是#     if (selector.charAt(0) == "#") {  //截掉#,然后传进去  // 去掉var改为全局变量  domObj = document.getElementById(selector.substring(1));  // 返回一个jQuery对象,下面才能正常调用html方法  return new jQuery();     } } // 如果是一个函数:页面加载完毕,注册回调函数 if (typeof selector == "function") {     window.onload = selector } // 封装html方法,代替domObj.innerHTML = "" this.html = function (htmlStr) {     domObj.innerHTML = htmlStr } // 封装onclick方法,直接传一个函数,代替:domObj.onclick = function(){} this.click = function (fun) {     domObj.onclick = fun }    }    // 把函数名赋给一个变量    $ = jQuery;    $(function () { // 把整个函数直接传过去 $("#mybtn").click(function () {     // 此时会有一个问题,domObj下没有html方法     // 所以在jQuery中封装一个html方法,返回一个jQuery即可     $("#mydiv").html("Hello"); })    })            

⑤将jQuery单独写到js文件中使用时引入库

在web目目下创建一个js目录,把我们前面封装好的代码放到一个.js文件,然后扔进js目录下;并且使用这个之前,需要先把它引进去!

function jQuery(selector){    if (typeof selector == "string") { if (selector.charAt(0) == "#") {     domObj = document.getElementById(selector.substring(1))     return new jQuery() }    }    if (typeof selector == "function") { window.onload = selector    }    this.html = function(htmlStr){ domObj.innerHTML = htmlStr    }    this.click = function(fun){ domObj.onclick = fun    }    this.focus = function (fun){ domObj.onfocus = fun    }    this.blur = function(fun) { domObj.onblur = fun    }    this.change = function (fun){ domObj.onchange = fun    }    this.val = function(v){ if (v == undefined) {     return domObj.value }else{     domObj.value = v }    }  

使用封装好的函数进行调用

        测试自己编写的jQuery              // 常规写法  window.onload = function(){     document.getElementById("btn").onclick = function () {  alert("hello1")     } } // 使用我们自己写的库 $(function () {     $("#btn").click(function () {  //alert("hello2");  // 获取文本框的内容  alert($("#username").val())  // 修改文本框的value  $("#username").val("张三")  // 设置div的内容  $("#mydiv").html("你好")     }) })        
用户名:

4、手动封装一个jQuery库

①将整个Ajax请求的步骤封装到jQuery-1.0.0.js当中

只针对传过来的数据是JSON格式的数据来封装!

②原型代码:

前端

        将AJAX代码进行封装,封装到jQuery库当中         window.onload = function () {     document.getElementById("btn").onclick = function () {  // 创建对象  var xhr = new XMLHttpRequest();  // 注册回调函数  xhr.onreadystatechange = function () {      if (this.readyState == 4) {   if (this.status == 200) {// 只针对JSON格式的数据var jsonObj = JSON.parse(this.responseText);// 把数据放入到div里document.getElementById("mydiv").innerHTML = jsonObj.username   }else {alert(this.status)   }      }  }  // 打开通道  xhr.open("POST","/ajax/ajaxrequest10",true)  xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");  // 发送请求  var username = document.getElementById("username").value;  xhr.send("username="+username);     } }        
用户名:

后端 

package com.bjpowernode.javaweb.ajax;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;/** * @Author:朗朗乾坤 * @Package:com.bjpowernode.javaweb.ajax * @Project:ajax * @name:AjaxRequest10Servlet * @Date:2022/12/10 15:59 */@WebServlet("/ajaxrequest10")public class AjaxRequest10Servlet extends HttpServlet {    @Override    protected void doPost(HttpServletRequest request, HttpServletResponse response)     throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); request.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter(); // 获取前端提交的数据 String username = request.getParameter("username"); // 以JSON格式数据提交 out.print(" {\"username\" : \""+username+"\"}");    }}

我们发现原型代码很多重复的,不够简练,所以下面进行封装一下

③使用封装好的jQuery-1.0.0.js:

这个库封装好以后,要想调用,必须先使用src属性引入,例如:

手动封装一个jQuery库

function jQuery(selector){    if (typeof selector == "string") { if (selector.charAt(0) == "#") {     domObj = document.getElementById(selector.substring(1))     return new jQuery() }    }    if (typeof selector == "function") { window.onload = selector    }    this.html = function(htmlStr){ domObj.innerHTML = htmlStr    }    this.click = function(fun){ domObj.onclick = fun    }    this.focus = function (fun){ domObj.onfocus = fun    }    this.blur = function(fun) { domObj.onblur = fun    }    this.change = function (fun){ domObj.onchange = fun    }    this.val = function(v){ if (v == undefined) {     return domObj.value }else{     domObj.value = v }    }    // 静态的方法,发送ajax请求    /**     * 分析:使用ajax函数发送ajax请求的时候,需要程序员给我们传过来什么?     *      请求的方式(type):GET/POST     *      请求的URL(url):url     *      请求时提交的数据(data):data     *      请求时发送异步请求还是同步请求(async):true表示异步,false表示同步。     */    jQuery.ajax = function(jsonArgs){ // 接收前端代码传过来的json数据 // 创建对象 var xhr = new XMLHttpRequest(); // 注册回调函数 xhr.onreadystatechange = function () {     if (this.readyState == 4) {  if (this.status == 200) {      // 只针对JSON格式的数据,这个是服务器响应回来的JSON格式代码      var jsonObj = JSON.parse(this.responseText);      // 把数据放入到div里      // 调用函数      jsonArgs.success(jsonObj)  }else {      alert(this.status)  }     } } // 打开通道,看是那种请求方式 if (jsonArgs.type.toUpperCase() == "POST") {// 如果是POST请求     xhr.open("POST",jsonArgs.url,jsonArgs.async)     xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");     // 发送请求     xhr.send(jsonArgs.data); } if (jsonArgs.type.toUpperCase() == "GET") {// 如果是GET请求     xhr.open("GET",jsonArgs.url+"?"+jsonArgs.data,jsonArgs.async)     // 发送请求     xhr.send(); }    }}$ = jQuery// 细节:执行这个目的是为了让上面的静态方法ajax生效。new jQuery()

前端代码:前端在编写Ajax四步就可以前不一样了,直接调用jQuery库中封装好的函数传过去JSON数据即可

        将AJAX代码进行封装,封装到jQuery库当中    $(function () { $("#btn").click(function () {     // 调用jQuery的工具类中的ajax方法来发送ajax请求     /*var username = document.getElementById("username").value     $.ajax({  type : "POST",  url : "/ajax/request10",  data : "username=" + username,  async : true,  // 程序响应回来之后,对于客户端来说要拿到响应的数据,然后解析这个数据,展示到页面上。  success : function(json){      document.getElementById("mydiv").innerHTML = json.uname  }     })*/      // 进一步优化      $.ajax({  type : "POST",  url : "/ajax/request10",  data : "username=" + $("#username").val(),  async : true,  // 程序响应回来之后,对于客户端来说要拿到响应的数据,然后解析这个数据,展示到页面上。  success : function(json){      $("#mydiv").html( json.uname)  }     })})    })
用户名:

后端代码:得到前端发送的数据后,也响应回去一个JSON格式的数据

package com.bjpowernode.javaweb.ajax;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;/** * @Author:朗朗乾坤 * @Package:com.bjpowernode.javaweb.ajax * @Project:ajax * @name:AjaxRequest10Servlet * @Date:2022/12/10 15:59 */@WebServlet("/request10")public class AjaxRequest10Servlet extends HttpServlet {    @Override    protected void doPost(HttpServletRequest request, HttpServletResponse response)     throws ServletException, IOException { // 设置响应的类型 request.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); // 获得前端提交的数据 String username = request.getParameter("username"); // 响应给浏览器out.print("{\"uname\" : \""+username+"\"}");    }}