AJAX

BS通信模型

  B/S 结构项目中, 浏览器(Browse)负责把用户的请求和参数通过网络发送给服务器(Server)。

  服务端使用 Servlet(多种服务端技术的一种)接收请求,并将处理结果返回给浏览器。
  浏览器在 html,jsp 上呈现数据,混合使用 css, js 帮助美化页面,或响应事件。


 1.0-全局刷新 和 局部刷新

  全局刷新 整个浏览器被新的数据覆盖。 在网络中传输大量的数据。 浏览器需要加载,渲染页面。

  全局刷新原理:

        1) 必须由浏览器亲自向服务端发送请求协议包。
        2) 这个行为导致服务端直接将【响应包】发送到浏览器内存中
        3) 这个行为导致浏览器内存中原有内容被覆盖掉
        4) 这个行为导致浏览器在展示数据时候,只有响应数据可以展示

  局部刷新 在浏览器的内部,发起请求,获取数据,只改变页面中的部分内容。 其余的页面无需加载和渲染。在网络中数据传输量少, 用户体验效果好。

       (浏览器在展示数据时,此时在窗口既可以看到本次的响应数据, 同时又可以看到浏览器内存中原有数据) 

  局部刷新原理:
        1) 不能由浏览器发送请求给服务端
        2) 浏览器委托浏览器内存中一个脚本对象代替浏览器发送请求.
        3) 这个行为导致导致服务端直接将【响应包】发送脚本对象内存中
        4) 这个行为导致脚本对象内容被覆盖掉,但是此时浏览器内存中绝大部分内容没有收到任何影响.
        5) 这个行为导致浏览器在展示数据时候,同时展示原有数据和响应数据


 2.0-AJAX技术概述

全称:"Asynchronous JavaScript and XML"    "异步的 JavaScript 和 XML"

作用:使用Ajax技术实现局部刷新的功能效果。

原理:通过使用JavaScript 语法创建异步对象 XMLHttpRequest ,并操作 异步对象,向服务器发送请求 或 从获取服务端发送来的XML或JSON格式的数据, 更新页面的dom对象,最后在浏览器中进行解析展示。

说明:ajax请求的目的是需要获取服务器端的数据。

  1)AJAX是在 2005年被Jesse James Garrett提出的新术语,用来描述一种使用现有技术集合混合使用的一种‘新’方法。而并非一门编程语言。 是一种在无需重新加载整个网页的情况下,能够更新部分页面内容(局部更新 )的新方法。AJAX 不仅需要前端的技术,同时需要后端(服务器)的配合。服务器需要提供数据,数据是 AJAX 请求的响应结果。

  2)ajax包含的技术主要包括: HTML 或 XHTML, CSS, JavaScript, DOM, XML, XSLT, 以及最重要的XMLHttpRequest。 核心是javascript 和 xml 。        

     浏览器内建的 XMLHttpRequest 对象  :   ( 负责 从 web 服务器发送请求, 接收响应数据

     JavaScript 和 HTML、 DOM :                 (负责显示或使用数据)

     XML: 是一种在网络中的传输的数据格式。(负责发送和接收的数据格式,现在主流使用 json数据传输格式)

  3)局部刷新使用的核心对象是 XMLHttpRequest【异步对象】。(由该对象负责局部刷新)

  4)异步对象使用JavaScript语法进行创建和使用,异步对象存在于浏览器内存中。

  5)浏览器内存中可以存在多个异步对象。每一个异步对象都可以独自向服务器发送请求,和 从服务器中获取数据。

  6)使用Ajax技术网页应用能够快速地将增量更新呈现在用户界面上,而不需要重载(刷新)整个页面,这使得程序能够更快地回应用户的操作。


百度百科》

  1)Ajax这个术语源自描述从基于 Web 的应用到基于数据的应用。

  2)Ajax 不是一种新的编程语言,而是一种用于创建更好更快以及交互性更强的Web应用程序的技术。

  3)使用 JavaScript 向服务器提出请求并处理响应而不阻塞用户核心对象XMLHttpRequest。通过这个对象,您的 JavaScript 可在不重载页面的情况与 Web 服务器交换数据,即在不需要刷新页面的情况下,就可以产生局部刷新的效果。
  4)Ajax 在浏览器与 Web 服务器之间使用异步数据传输(HTTP 请求),这样就可使网页从服务器请求少量的信息,而不是整个页面。
 
  5)Ajax可使因特网应用程序更小、更快,更友好。
  6)Ajax 是一种独立于 Web 服务器软件的浏览器技术。 
  7)Ajax 基于下列 Web 标准:
    JavaScript、XML、HTMLCSS 在 Ajax 中使用的 Web 标准已被良好定义,并被所有的主流浏览器支持。
    Ajax 应用程序独立于浏览器和平台。
    Web 应用程序较桌面应用程序有诸多优势;它们能够涉及广大的用户,它们更易安装及维护,也更易开发。
    不过,因特网应用程序并不像传统的桌面应用程序那样完善且友好。通过 Ajax,因特网应用程序可以变得更完善,更友好。
                                                  

2.1-AJAX的工作流程

  1. 网页中发生一个事件(页面加载、按钮点击)
  2. 由 JavaScript 创建 XMLHttpRequest 对象
  3. XMLHttpRequest 对象向 web 服务器发送请求
  4. 服务器处理该请求
  5. 服务器将响应发送回网页
  6. 由 JavaScript 读取响应
  7. 由 JavaScript 执行正确的动作(比如更新页面)

3.0-XMLHttpRequest 异步对象概述

概 述

  在局部刷新,需要创建一个对象,代替浏览器发起请求的行为,这个对象存在内存中。
  代替浏览器发起请求并接收响应数据。这个对象叫做异步请求对象。
  全局刷新是同步行为 [浏览器数据会全部更新] 局部刷新是异步行为 [浏览器数据没有全部更新]
  这个异步对象用于在后台与服务器交换数据。XMLHttpRequest 就是我们说的异步对象。

  1)-所有现代的浏览器都支持 XMLHttpRequest 对象。

  2)-XMLHttpRequest 对象用于在后台与服务器交换数据。

  3)-XMLHttpRequest 对象的作用:

  • 在不重新加载页面的情况下更新网页;
  • 在页面已加载后从服务器请求数据;
  • 在页面已加载后从服务器接收数据;
  • 在后台向服务器发送数据; 

详细教程:https://www.w3school.com.cn/xml/xml_http.asp


3.1-XMLHttpRequest 异步对象的属性

readyState属性

———— 表示异步对象请求的状态变化  (有0~4 五个值)

  0: 创建异步对象, 执行new XMLHttpRequest();时。

  1:   初始异步请求对象, 执行xmlHttpRequest.open( );时。

  2: 发送请求, 执行xmlHttpRequest.send();时。

  3:   从服务器端获取了数据,此时是3。 注意3是异步对象内部使用, 表示获取了原始的数据。(开发人员一般不用3这个值)

  4:异步对象把接收的数据处理完成后。 此时开发人员在状态值是4的时候来处理数据。(在4状态时候,开发人员应该做什么 ?—— 拿到数据之后,更新当前页面。)

status属性

———— 表示网络请求的状况的。

  200,当status==200时,表示网络请求是成功的。

  404,当status==404时,表示请求访问不到服务器资源。

  500,当status==500时,表示服务器代码出错。

 responseText属性

———— 获取服务器端返回获的字符串形式的响应数据。

    var data = xmlHttpRequest.responseText; 

 responseXML属性

———— 获得 XML 形式的响应数据。

    var data = xmlHttpRequest.responseXML;


3.2-使用XMLHttpRequest对象的步骤

1) 创建异步对象

// 1)-创建异步对象
var
xmlHttp = new XMLHttpRequest();

2) 给异步对象绑定 onreadystatechange 事件

  onreadystatechange 是一个事件句柄。它的值 (state_Change) 是一个函数的名称,当 XMLHttpRequest 对象的状态发生改变时,会触发此函数。

  状态从 0 (uninitialized) 到 4 (complete) 进行变化。仅在状态为 4 时,我们才执行代码。

  需要为这个事件指定一个函数, 在函数中处理状态的变化。当异步对象发起请求 或 获取了数据都会触发这个事件。

  通过该事件可以获取异步对象发送请求或获取数据的状态。

// 2)-为异步对象绑定onreadystatechange事件,处理请求的状态变化。
xmlHttpRequest.onreadystatechange= function(){     
}

3) 初始异步请求对象

———xmlHttpRequest.open( String method,String url,boolean async);

// 3)-初始异步请求对象。采用get提交方式,访问loginServlet且携带相关的参数
xmlHttpRequest.open("get", "loginServlet?name=james&pwd=123",true);

  method参数:请求的类型;GET 或 POST

  url参数:        服务器端的访问地址。可以携带相关的参数。

  async参数:  true(异步)或 false(同步)。该参数规定请求是否异步处理。默认的true值代表异步请求,false值表示同步请求。

      异步处理请求: 使用异步对象发起请求之后,脚本会在 send() 方法之后继续执行,而不等待来自服务器的响应。即不用等待数据处理完毕,就可以执行其他操作。

     同步处理请求:异步对象必须处理完成请求,从服务端获取数据后,才能执行send()之后的代码。任意时刻只能执行一个请求。onreadystatechange 事件使代码复杂化了。但是这是在没有得到服务器响应的情况下,防止代码停止的最安全的方法。通过把该参数设置为 "false",可省去额外的onreadystatechange代码。若在请求失败时是否执行其余的代码无关紧要,则么可以使用该参数。

4) 使用异步对象发送请求

// 4)-异步对象向服务器发送请求 
xmlHttpRequest.send( );

5) 接收并处理服务端的数据

如需获得来自服务器的响应,请使用 XMLHttpRequest 对象的 responseText 或responseXML 属性。
    responseText:获得字符串形式的响应数据
    responseXML:获得 XML 形式的响应数据

需要注意的是:第5步中的代码需要写在第2步之中。

// 2)-为异步对象绑定onreadystatechange事件,处理请求的状态变化。
xmlHttpRequest.onreadystatechange= function(){    

             //5)-【处理服务器端的数据,更新当前页面】
            //异步对象已成功获取到了服务端的数据 ,且 当网络请求是成功的状态。
    if(xmlHttpRequest.readyState == 4 && xmlHttpRequest.status== 200 ){ 
     
    
      //获取到的是服务端发送来的数据。
     var data = xmlHttpRequest.responseText;         

     //更新页面DOM对象的内容。   
    document.getElementById("name").value= data; 
  }    
    
}            

 提出问题:为何处理数据放在第二步?异步对象涉及到回调函数

  当第四步的send()方法执行之后,将会等待服务端返回数据。服务端数据返回之后,还会执行第二步中的代码(根据判断条件来处理数据)。

  每当请求的状态变化时,异步对象就会自动调用一次onreadystatechange事件对应的函数。


4.1-全局刷新案例:计算用户BMI值

方案1 借助请求域空间进行存储处理数据)

代码思路:BmiServlet的处理数据,借助请求域空间进行存储。并且请求转发到result.jsp页面中,向用户进行数据展示。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>全局刷新计算BMI</title>
  </head>
  <body>
  <p>全局刷新计算BMI</p>
  <form action="bmiServlet" method="post">
    姓名:<input type="text" name="name"/><br/>
    身高:<input type="text" name="height"/>(M)<br/>
    体重:<input type="text" name="weight"/>(KG)<br/>
    <input type="submit" value="计算BMI值" >
  </form>
  </body>
</html>
index.jsp
 1 package com.penguin1024.controller;
 2 
 3 import javax.servlet.ServletException;
 4 import javax.servlet.http.HttpServlet;
 5 import javax.servlet.http.HttpServletRequest;
 6 import javax.servlet.http.HttpServletResponse;
 7 import java.io.IOException;
 8 
 9 public class BmiServlet extends HttpServlet {
10     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
11         // 覆盖此请求体中使用的字符编码的名称。(解决post提交产生的中文请求参数问题)
12         request.setCharacterEncoding("utf-8");
13 
14         // 获取用户提交的请求参数信息
15         String nameStr = request.getParameter("name");
16         String heightStr = request.getParameter("height");
17         String weightStr = request.getParameter("weight");
18 
19         // 需要先将字符串类型的heightStr 和  weightStr ,转为float类型。
20         Float height = Float.valueOf(heightStr);
21         Float weight = Float.valueOf(weightStr);
22 
23         // 再按照公式计算BMI值。  体质指数(BMI)=体重(千克)除以身高(平方米)
24         Float bmi = weight/(height*height);
25 
26 
27         // 准备一个空字符串,用于提示用户信息。
28         String msg = "";
29         // 计算用户BMI值所对应的范围
30         if( bmi <= 18.5) {
31             msg = "您比较瘦";
32         } else if( bmi > 18.5 && bmi <= 23.9 ){
33             msg = "您的bmi是正常的";
34         } else if( bmi >24 && bmi <=27){
35             msg = "您的身体比较胖";
36         } else {
37             msg = "您的身体肥胖";
38         }
39 
40         // 拼接字符串提示信息
41         msg = nameStr + "先生/女士。 您的BMI值是:"+ bmi + " ———— "+ msg;
42 
43         // 将字符串类型msg变量,存储到request域中。(用于让对应的jsp页面使用EL表达式获取,并展示数据给用户)
44         request.setAttribute("msg",msg);
45 
46         // 请求转发到result.jsp页面中
47         request.getRequestDispatcher("/result.jsp").forward(request,response);
48     }
49 
50     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
51         this.doPost(request,response);
52     }
53 }
com.penguin1024.controller.BmiServlet
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>BMI结果界面</title>
</head>
<body>
    <p>显示bmi计算结果</p>
    <h3>${msg}</h3>
</body>
</html>
result.jsp

方案2 (借助标准输出流对象,将提示信息输出到浏览器)

代码思路:BmiPrintServlet不借助域空间存储数据,直接借助标准输出流对象,将提示信息输出到浏览器。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>全局刷新计算BMI</title>
  </head>
  <body>
  <p>全局刷新计算BMI</p>
  <form action="bmiPrintServlet" method="post">
    姓名:<input type="text" name="name"/><br/>
    身高:<input type="text" name="height"/>(M)<br/>
    体重:<input type="text" name="weight"/>(KG)<br/>
    <input type="submit" value="计算BMI值" >
  </form>
  </body>
</html>
index.jsp
 1 package com.penguin1024.controller;
 2 
 3 import javax.servlet.ServletException;
 4 import javax.servlet.http.HttpServlet;
 5 import javax.servlet.http.HttpServletRequest;
 6 import javax.servlet.http.HttpServletResponse;
 7 import java.io.IOException;
 8 import java.io.PrintWriter;
 9 
10 public class BmiPrintServlet extends HttpServlet {
11     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
12         // 覆盖此请求体中使用的字符编码的名称。(解决post提交产生的中文请求参数问题)
13         request.setCharacterEncoding("utf-8");
14 
15         // 获取用户提交的请求参数信息
16         String nameStr = request.getParameter("name");
17         String heightStr = request.getParameter("height");
18         String weightStr = request.getParameter("weight");
19 
20         // 需要先将字符串类型的heightStr 和  weightStr ,转为float类型。
21         Float height = Float.valueOf(heightStr);
22         Float weight = Float.valueOf(weightStr);
23 
24         // 再按照公式计算BMI值。  体质指数(BMI)=体重(千克)除以身高(平方米)
25         Float bmi = weight/(height*height);
26 
27 
28         // 准备一个空字符串,用于提示用户信息。
29         String msg = "";
30         // 计算用户BMI值所对应的范围
31         if( bmi <= 18.5) {
32             msg = "您比较瘦";
33         } else if( bmi > 18.5 && bmi <= 23.9 ){
34             msg = "您的bmi是正常的";
35         } else if( bmi >24 && bmi <=27){
36             msg = "您的身体比较胖";
37         } else {
38             msg = "您的身体肥胖";
39         }
40 
41         // 拼接字符串提示信息
42         msg = nameStr + "先生/女士。 您的BMI值是:"+ bmi + " ———— "+ msg;
43 
44 
45         // 如果尚未提交响应,则设置发送到客户机的响应的内容类型 
46         // 且将发送到客户端的响应的字符编码(MIME字符集)设置为UTF-8。
47         // 能解决响应中的中文乱码问题。
48         response.setContentType("text/html;charset=utf-8");
49 
50         // 获取标准输出流对象,该对象可以向客户端发送字符文本。
51         PrintWriter out = response.getWriter();
52         // 输出数据
53         out.println(msg);
54         // 清空缓存
55         out.flush();
56         // 关闭流
57         out.close();
58         
59     }
60 
61     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
62         this.doPost(request,response);
63     }
64 }
BmiPrintServlet

访问:


 4.2-Ajax局部刷新案例:计算用户BMI值

使用ajax技术实现局部刷新功能效果的代码思路

1-新建index.jsp,创建和使用XMLHttpRequest异步对象。(5个步骤)
    1).创建
    2).绑定事件
    3).初始请求
    4).发送请求
       5).处理服务端发送的数据 
2-创建服务器的BmiAjaxServlet.java,接收并处理来自异步对象发送的请求数据, 并把处理之后的数据通过标准输出流输出给异步对象。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>Ajax局部刷新计算BMI</title>

    <script type="text/javascript">

      // 使用浏览器内存中的异步对象,代替浏览器发起请求。异步对象使用js创建和管理的。
      function doAjax() {
        // 1-创建异步请求对象
        var xmlHttpRequest=  new XMLHttpRequest();

        // 2-绑定onreadystatechange事件
        xmlHttpRequest.onreadystatechange = function () {

          //异步对象已成功获取到了服务端的数据 ,且 当网络请求是成功的状态。
          if (xmlHttpRequest.readyState==4 && xmlHttpRequest.status ==200){

            // 获取服务器发送来的数据
            var data = xmlHttpRequest.responseText;
            // 更新dom对象,更新页面数据
            document.getElementById("mydata").innerText = data;

          }

        }
        // 3-初始异步请求对象 (初始化请求数据)

        // 获取dom对象的value值
        var name = document.getElementById("name").value;
        var height = document.getElementById("height").value;
        var weight = document.getElementById("weight").value;


        // JavaScript 中的encodeURI(String uri) 函数作用:可把字符串作为 URI 进行编码。
        // JavaScript 中的decodeURI(String uri) 函数作用:可对encodeURI(String uri) 编码过的 URI 进行解码。
        name = encodeURI(name);
        alert(name); // 结果是 %E8%83%96%E4%BC%81%E9%B9%85

        // 按照格式拼接需要携带的请求参数
        var parameter = "name="+name+"&height="+height+"&weight="+weight;
        xmlHttpRequest.open("get","${pageContext.request.contextPath}/bmiAjaxServlet?"+parameter,true)

        // 4-向服务器发送请求
        xmlHttpRequest.send();

      }
      
    </script>

  </head>
  <body>
  <p>局部刷新ajax-计算bmi</p>
  <div>
    <!-- ajax局部刷新没有使用<form>提交  -->
    姓名:<input type="text" id="name" /> <br/>
    身高:<input type="text" id="height" /> <br/>
    体重:<input type="text" id="weight" /> <br/>
    <input type="button" value="计算bmi" onclick="doAjax()">
    <br/>
    <br/>
    <div id="mydata">等待加载数据....</div>
  </div>

  </body>
</html>
index.jsp
package com.penguin1024.controller;

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.io.PrintWriter;

public class BmiAjaxServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 覆盖此请求体中使用的字符编码的名称。(解决post提交产生的中文请求参数问题)
        request.setCharacterEncoding("utf-8");

        // 获取用户提交的请求参数信息
        String nameStr = request.getParameter("name");
        String heightStr = request.getParameter("height");
        String weightStr = request.getParameter("weight");

        // 需要先将字符串类型的heightStr 和  weightStr ,转为float类型。
        Float height = Float.valueOf(heightStr);
        Float weight = Float.valueOf(weightStr);

        // 再按照公式计算BMI值。  体质指数(BMI)=体重(千克)除以身高(平方米)
        Float bmi = weight/(height*height);


        // 准备一个空字符串,用于提示用户信息。
        String msg = "";
        // 计算用户BMI值所对应的范围
        if( bmi <= 18.5) {
            msg = "您比较瘦";
        } else if( bmi > 18.5 && bmi <= 23.9 ){
            msg = "您的bmi是正常的";
        } else if( bmi >24 && bmi <=27){
            msg = "您的身体比较胖";
        } else {
            msg = "您的身体肥胖";
        }

        // 拼接字符串提示信息
        msg = nameStr + "先生/女士。 您的BMI值是:"+ bmi + " ———— "+ msg;

        // 如果尚未提交响应,则设置发送到客户机的响应的内容类型
        // 且将发送到客户端的响应的字符编码(MIME字符集)设置为UTF-8。
        // 能解决响应中的中文乱码问题。
        response.setContentType("text/html;charset=utf-8");

        // 获取标准输出流对象,该对象可以向客户端发送字符文本。
        PrintWriter out = response.getWriter();
        // 输出数据 (响应ajax需要的数据,使用HttpServletResponse输出数据)
        out.println(msg);
        // 清空缓存
        out.flush();
        // 关闭流
        out.close();

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}
BmiAjaxServlet.java

 JS代码中的中文请求参数的传输问题?

JavaScript 中的encodeURI(String uri) 函数:可把字符串作为 URI 进行编码。

JavaScript 中的decodeURI(String uri) 函数:可对encodeURI(String uri) 编码过的 URI 进行解码。

 如:alert(encodeURI("胖企鹅"));    的执行结果是 E88396E4BC81E9B985


 4.3-Ajax局部刷新案例:根据省份id获取省份名称,并局部更新界面信息。

1-环境搭建

0)-DOS命令行窗口mysql中文显示乱码问题解决方法:

 产生原因:MySQL的默认编码是Latin1,不支持中文,因此需要修改MySQL的默认编码。只需修改mysql安装目录下的my.ini 配置文件的两处地方即可:

 

1)-创建数据库 fatpenguin

create database fatpenguin;

2)-使用创建好的数据库,并在该数据库中添加两张表:province (省份信息表)  

use fatpenguin;

province省份表:

CREATE TABLE `province` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `name` varchar(255) DEFAULT NULL COMMENT '省份名称',
 `jiancheng` varchar(255) DEFAULT NULL COMMENT '简称',
 `shenghui` varchar(255) DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;

3)-查看province表中的数据

4)-创建javaweb项目  

  在web/WEB-INF目录下手动创建lib目录 和 classes目录。并在lib目录中放置mysql的驱动jar包并打开 Project Structure 进行相关的工程结构设置 。       (参照IDEA设置博客)

2-编写代码

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>ajax根据省份id获取名称</title>

    <script type="text/javascript">
      // 使用浏览器内存中的异步对象,代替浏览器发起ajax请求,传递参数给服务器, 服务器返回数据。

      //1.创建异步对象 (异步对象使用js创建和管理的。)
      function search() {
        // 1-创建异步请求对象
        var xmlHttpRequest=  new XMLHttpRequest();

        // 2-绑定onreadystatechange事件
        xmlHttpRequest.onreadystatechange = function () {

          // 5-对从服务端中返回的数据做相关处理

          // 判断:若 异步对象已成功获取到了服务端的数据 ,且 当网络请求是成功的状态的情况下。
          if (xmlHttpRequest.readyState==4 && xmlHttpRequest.status ==200){

            // 获取服务器发送来的数据
            var data = xmlHttpRequest.responseText;
            // 更新dom对象,更新页面数据
            document.getElementById("proname").value = data;

          }

        }
        // 3-初始异步请求对象 (初始化请求数据)

        //获取proid文本框的值 (用户在界面中输入的值)
        var proid = document.getElementById("proid").value;

        // 使用js中的函数encodeURI(String uri) 对字符串 进行编码  (可以解决JS中的中文参数乱码问题)
        proid = encodeURI(proid); 

        xmlHttpRequest.open("get","${pageContext.request.contextPath}/queryProviceServlet?proid="+proid,true);

        // 4-向服务器发送请求
        xmlHttpRequest.send();
      }

    </script>

  </head>
  <body>
  <p>AJAX根据省份id编号获取省份名称:</p>
  <table>
    <tr>
      <td>省份编号:</td>
      <td><input type="text" id="proid"/>
        <input type="button" value="搜索" onclick="search()" />
      </td>
    </tr>
    <tr>
      <td>省份名称:</td>
      <td><input type="text" id="proname" /></td>
    </tr>
  </table>

  </body>
</html>

index.jsp
index.jsp
package com.penguin1024.utils;
import java.sql.*;
// 定义连接数据库的JDBC工具类
// 注意事项:工具类中的 可能产生异常的代码 不使用try..catch方式处理,一般使用抛出的方式。
// 因为使用try...catch方式进行处理。代码一旦发生异常,工具类的调用者不好定位到发生异常的代码。
public class JdbcUtil {

    // 静态代码块
    static {
        try {
            // 1-在JdbcUtil类加载时,加载mysql数据库的驱动
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    // 声明一个成员变量Connection对象 ,且需定义为静态成员  (该代码由下列方法中的代码思考之后,添加的)
    // 静态方法中只能访问静态成员,不能访问到实例成员。
    static Connection conn = null;


    // 2-定义:获取数据库连接Connection对象的方法
    // 注意:Connection 是java.sal.Connection(接口)。为什么? —— 面向接口编程,好处是不用在乎该连接是由谁实现的
    public static Connection getConnection() throws SQLException {

        String user = "jdbc:mysql://localhost:3306/fatpenguin";
        String url = "root";
        String password = "111";

        //重点注意:
        //思考什么时候需要创建Connection接口对象?每次使用时候都需要创建新的连接吗?
        //当conn = null时,才需要创建一个新的Connection接口对象。


        // Connection conn = null;错误。不能在此处将conn变量定义为局部变量。
        // 这样的写的话,下面的判断结果永远是false值。
        // 因此需要将在类中定义为静态成员: private static Connection conn = null;

        // conn值为null,或conn被关闭时,需要重新创建Connection对象。
        
        // 如果Connection对象为null,或者Connection对象已经被关闭掉的情况下
        if (conn == null || conn.isClosed()  ){
            // 满足以上条件,则创建新的Connection对象。
            conn = DriverManager.getConnection(user, url, password);
        }
        return conn;
    }

    // 3-定义:关闭相关资源
    public static void close(Connection conn, Statement stmt, ResultSet rs) throws SQLException {
        // 关闭资源1
        // 如果conn不等于null,且conn也没有被关闭的情况下。
        if (conn != null && !conn.isClosed()) {
            conn.close(); // 关闭
        }

        // 关闭资源2
        if (stmt != null && !conn.isClosed()) {
            stmt.close(); // 关闭
        }

        // 关闭资源3
        if (rs != null && !conn.isClosed()) {
            rs.close(); // 关闭
        }
    }
}
JdbcUtil.java
JdbcUtil.java
package com.penguin1024.dao;
import com.penguin1024.utils.JdbcUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

// 对数据库中的数据执行相关的操作
public class ProvinceDao {
    // 根据用户输入的省份id,查询出该id值所对应的省份名称
    public String queryProvinceNameById(Integer provinceid){

        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet res = null;

        // 定义一个空字符串,用于接收查询出来的省份名称
        String name = "";

        try {
             // 1-借助编写好的JdbcUtil工具类,获取Connection 数据库连接对象
             conn = JdbcUtil.getConnection();

             // 2-编写SQL语句框架
             String sql = "select name from province where id = ?";

             // 3-对SQL语句框架进行预编译处理 (避免SQL注入情况的产生)
             ps = conn.prepareStatement(sql);

             // 4-对SQL语句框架中的占位符,设置具体的参数值
            ps.setInt(1,provinceid);

            // 5-执行SQL语句,并接收返回的结果集
             res = ps.executeQuery();

             // 6-遍历处理查询结果集
             while (res.next()){
                 // 获取这条数据中,字段名为"name"的值
                  name = res.getString("name");
             }

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {

            try {
                // 7-借助编写好的JdbcUtil工具类,关闭相关资源
                JdbcUtil.close(conn,ps,res);
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }


        // 8-返回省份id编号所对应的省份名称
        return  name;
    }

}

ProvinceDao.java
ProvinceDao.java
package com.penguin1024.controller;

import com.penguin1024.dao.ProvinceDao;

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.io.PrintWriter;

// 执行相关的业务逻辑操作
public class QueryProviceServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // 定义一个字符串类型变量,用于接收查询到的省份名称。
        String provinceName ="默认没有数据";

        // 1-对请求参数做相关处理
        // 覆盖此请求体中使用的字符编码的名称。 (解决post方式的中文乱码问题)
        request.setCharacterEncoding("utf-8");
        // 接收来自Ajax异步对象发送来的请求参数
        String proidStr = request.getParameter("proid");
        // 将字符串类型的省份id编号,转换为Integet类型
        Integer provinceId = Integer.valueOf(proidStr);

        // 2-访问Dao层对象,从数据库中查询数据

        // 判断条件:
        // 用户在查询界面中输入的不是空字符串
        // 且输入的id编号在转换为Integer类型之后的值不为null
        // 且转换为Integer类型的结果是在[1-9]区间的整数
        if(  !"".equals(proidStr.trim()) && provinceId != null && (provinceId>=1 && provinceId<=9)) {
            // 创建dao对象
            ProvinceDao dao = new ProvinceDao();

            //  调用dao对象的方法 — —根据用户添加的省份id编号,到数据库中查找出该编号对应的省份名称
             provinceName = dao.queryProvinceNameById(provinceId);
        }else {
            provinceName = "请输入合法的省份编号!!!";
        }

        // 3-向发送请求的Ajax异步请求对象返回查询到的结果

        //使用HttpServletResponse输出数据
        // servlet返回给浏览器的是文本数据类型, 告诉浏览器采用utf-8字符集进行解码 (解决响应的中文乱码问题)
        response.setContentType("text/html;charset=utf-8");

        // 获取标准输出流
        PrintWriter out = response.getWriter();

        // 往标准输出流中写入的数据,会被响应到发出相应请求的Ajax异步对象中。
        out.println(provinceName);

        // 清空缓存
        out.flush();

        // 关闭流
        out.close();

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}
QueryProviceServlet.java

注意事项:

  1)index.jsp的编写步骤:最先编写登录界面的前端显示内容(body标签中的内容),再搭建好Ajax代码的1-4步代码。  Ajax代码中的第5步骤代码留在最后编写,也就是编写完QueryProviceServlet.java代码之后再进行编写。

  2)mysql建表语句中问题:

    Mysql中如果表和表之间建立的外键约束,则无法删除表及修改表结构。
    解决方法:在Mysql中取消外键约束:  添加代码 SET FOREIGN_KEY_CHECKS=0;  然后将原来表的数据导出到sql语句,重新创建此表后,再把数据使用sql导入,然后再设置外键约束:SET FOREIGN_KEY_CHECKS=1;  

3-测试查询结果

输入合法的1-9的整数编号值,显示结果如下

                                          

若输入1-9之外的整数值,显示结果如下:

                                         

 若在省份编号栏中,输入空字符串 或 中文,则程序会报500错误。(程序抛出异常)

                                         


4.4-Ajax局部刷新案例:根据省份id获取省份信息,并局部更新界面信息。

1-环境搭建

1)创建javaweb项目。

操作:

  在web/WEB-INF目录下手动创建lib目录 和 classes目录。并在lib目录中并添加mysql驱动 以及 json相关的jar包,并打开 Project Structure 进行相关的工程结构设置 。

2)fatpenguin数据库中准备两张表 province表 和 city表。

province表:

CREATE TABLE `province` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `name` varchar(255) DEFAULT NULL COMMENT '省份名称',
 `jiancheng` varchar(255) DEFAULT NULL COMMENT '简称',
 `shenghui` varchar(255) DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8

city表:

CREATE TABLE `city` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `name` varchar(255) DEFAULT NULL,
 `provinceid` int(11) DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;

注意事项:city表中的 provinceid字段作为 外键,代表的是省份表的主键的值

2-代码编写

package com.penguin1024.utils;
import java.sql.*;
// 定义连接数据库的JDBC工具类
// 注意事项:工具类中的 可能产生异常的代码 不使用try..catch方式处理,一般使用抛出的方式。
// 因为使用try...catch方式进行处理。代码一旦发生异常,工具类的调用者不好定位到发生异常的代码。
public class JdbcUtil {

    // 静态代码块
    static {
        try {
            // 1-在JdbcUtil类加载时,加载mysql数据库的驱动
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    // 声明一个成员变量Connection对象 ,且需定义为静态成员  (该代码由下列方法中的代码思考之后,添加的)
    // 静态方法中只能访问静态成员,不能访问到实例成员。
    static Connection conn = null;


    // 2-定义:获取数据库连接Connection对象的方法
    // 注意:Connection 是java.sal.Connection(接口)。为什么? —— 面向接口编程,好处是不用在乎该连接是由谁实现的
    public static Connection getConnection() throws SQLException {

        String user = "jdbc:mysql://localhost:3306/fatpenguin";
        String url = "root";
        String password = "111";

        //重点注意:
        //思考什么时候需要创建Connection接口对象?每次使用时候都需要创建新的连接吗?
        //当conn = null时,才需要创建一个新的Connection接口对象。


        // Connection conn = null;错误。不能在此处将conn变量定义为局部变量。
        // 这样的写的话,下面的判断结果永远是false值。
        // 因此需要将在类中定义为静态成员: private static Connection conn = null;

        // conn值为null,或conn被关闭时,需要重新创建Connection对象。

        // 如果Connection对象为null,或者Connection对象已经被关闭掉的情况下
        if (conn == null || conn.isClosed()  ){
            // 满足以上条件,则创建新的Connection对象。
            conn = DriverManager.getConnection(user, url, password);
        }
        return conn;
    }

    // 3-定义:关闭相关资源
    public static void close(Connection conn, Statement stmt, ResultSet rs) throws SQLException {
        // 关闭资源1
        // 如果conn不等于null,且conn也没有被关闭的情况下。
        if (conn != null && !conn.isClosed()) {
            conn.close(); // 关闭
        }

        // 关闭资源2
        if (stmt != null && !conn.isClosed()) {
            stmt.close(); // 关闭
        }

        // 关闭资源3
        if (rs != null && !conn.isClosed()) {
            rs.close(); // 关闭
        }
    }
}
JdbcUtil.java
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>使用json格式的数据</title>

    <script type="text/javascript">
      // 使用浏览器内存中的异步对象,代替浏览器发起ajax请求,传递参数给服务器, 服务器返回数据。

      //1.创建异步对象 (异步对象使用js创建和管理的。)
      function search() {
        // 1-创建异步请求对象
        var xmlHttpRequest=  new XMLHttpRequest();

        // 2-绑定onreadystatechange事件
        xmlHttpRequest.onreadystatechange = function () {

          // 5-对从服务端中返回的数据做相关处理

          // 判断:若 异步对象已成功获取到了服务端的数据 ,且 当网络请求是成功的状态的情况下。
          if (xmlHttpRequest.readyState==4 && xmlHttpRequest.status ==200){

            // 获取服务器发送来的数据  (在此处,传递过来的是一个json格式的字符串)
            var data = xmlHttpRequest.responseText;

            //JavaScript中的eval(string)函数执行括号中的代码, 把json字符串转为json对象
            var jsonobj = eval("(" + data + ")");

            // 调用自定义的数据处理函数:来更新dom对象,更新页面数据
              callback(jsonobj);

          }

        }
        // 3-初始异步请求对象 (初始化请求数据)

        //获取proid文本框的值 (用户在界面中输入的值)
        var proid = document.getElementById("proid").value;

        // 使用js中的函数encodeURI(String uri) 对字符串 进行编码  (可以解决JS中的中文参数乱码问题)
        proid = encodeURI(proid);

        xmlHttpRequest.open("get","${pageContext.request.contextPath}/queryProviceServlet?proid="+proid,true);

        // 4-向服务器发送请求
        xmlHttpRequest.send();
      }

      // 定义一个函数,来处理服务器端返回的数据
      function callback(json){
          document.getElementById("proname").value = json.name;
          document.getElementById("projiancheng").value=json.jiancheng;
          document.getElementById("proshenghui").value= json.shenghui;
      }


    </script>

  </head>
  <body>
  <p>ajax请求使用json格式的数据</p>
  <table>
    <tr>
      <td>省份编号:</td>
      <td><input type="text" id="proid">
        <input type="button" value="搜索" onclick="search()">
      </td>
    </tr>
    <tr>
      <td>省份名称:</td>
      <td><input type="text" id="proname"></td>
    </tr>
    <tr>
      <td>省份简称:</td>
      <td><input type="text" id="projiancheng"></td>
    </tr>
    <tr>
      <td>省会名称:</td>
      <td><input type="text" id="proshenghui"></td>
    </tr>
  </table>
  </body>
</html>
index.jsp
package com.penguin1024.entity;

// 定义Province实体类
public class Province {
    private Integer id;
    private String name;
    private String jiancheng;
    private String shenghui;

    // 提供无参构造方法
    public Province() {
    }

    // 提供set/get 方法

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getJiancheng() {
        return jiancheng;
    }

    public void setJiancheng(String jiancheng) {
        this.jiancheng = jiancheng;
    }

    public String getShenghui() {
        return shenghui;
    }

    public void setShenghui(String shenghui) {
        this.shenghui = shenghui;
    }
}
Province.java
package com.penguin1024.dao;
import com.penguin1024.entity.Province;
import com.penguin1024.utils.JdbcUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

// 对数据库中的数据执行相关的操作
public class ProvinceDao {
    // 根据用户输入的省份id,查询出该id值所对应的省份信息(返回值是一个完整的实体类Province对象)
    public Province queryProvinceById(Integer provinceid){

        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet res = null;

        // 声明一个Province类型的成员变量
        Province province = null;


        try {
             // 1-借助编写好的JdbcUtil工具类,获取Connection 数据库连接对象
             conn = JdbcUtil.getConnection();

             // 2-编写SQL语句框架
             String sql = "select id,name,jiancheng,shenghui from province where id = ?";

             // 3-对SQL语句框架进行预编译处理 (避免SQL注入情况的产生)
             ps = conn.prepareStatement(sql);

             // 4-对SQL语句框架中的占位符,设置具体的参数值
            ps.setInt(1,provinceid);

            // 5-执行SQL语句,并接收返回的结果集
             res = ps.executeQuery();

             // 6-遍历处理查询结果集


            while (res.next()){
                // 创建实体类Province
                province = new Province();

                // 为实体类的"id"属性 赋值
                province.setId(res.getInt("id"));
                // 为实体类的"name"属性 赋值
                province.setName(res.getString("name"));
                // 为实体类的"jiancheng"属性 赋值
                province.setJiancheng(res.getString("jiancheng"));
                // 为实体类的"shenghui"属性 赋值
                province.setShenghui(res.getString("shenghui"));
             }

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {

            try {
                // 7-借助编写好的JdbcUtil工具类,关闭相关资源
                JdbcUtil.close(conn,ps,res);
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }


        // 8-返回省份id编号所对应的省份信息(即一个完整的Province对象)
        return province;
    }

}
ProvinceDao.java
package com.penguin1024.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.penguin1024.dao.ProvinceDao;
import com.penguin1024.entity.Province;

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.io.PrintWriter;

// 执行相关的业务逻辑操作
public class QueryProviceServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // 定义一个字符串类类型的 默认值 {} :表示json格式的数据
        String jsonStr = "{}";

        // 1-对请求参数做相关处理
        // 覆盖此请求体中使用的字符编码的名称。 (解决post方式的中文乱码问题)
        request.setCharacterEncoding("utf-8");
        // 接收来自Ajax异步对象发送来的请求参数
        String proidStr = request.getParameter("proid");
        // 将字符串类型的省份id编号,转换为Integet类型
        Integer provinceId = Integer.valueOf(proidStr);

        // 2-访问Dao层对象,从数据库中查询数据

        // 用户在查询界面中输入的不是空字符串
        // 且输入的id编号在转换为Integer类型之后的值不为null
        if(  proidStr.trim().length() >0 && provinceId != null ) {
            // 创建dao对象
            ProvinceDao dao = new ProvinceDao();

            //  调用dao对象的方法 — —根据用户添加的省份id编号,到数据库中查找出该编号对应的省份对象
            Province province = dao.queryProvinceById(provinceId);

            //需要使用jackson工具类 把 Provice对象转为json格式的字符串
            ObjectMapper om  = new ObjectMapper();
            jsonStr =  om.writeValueAsString(province);

        }

        // 3-向发送请求的Ajax异步请求对象返回查询到的结果


        //把获取的数据,通过网络传给ajax中的异步对象,响应结果数据
        //指定服务器端(servlet)返回给浏览器的是json格式的数据,并通知浏览器使用使用utf-8编码(解决响应的中文乱码问题)

        response.setContentType("application/json;charset=utf-8");

        // 获取标准输出流
        PrintWriter out = response.getWriter();

        // 往标准输出流中写入的数据,会被响应到发出相应请求的Ajax异步对象的responseText属性中。
        out.println(jsonStr);

        // 清空缓存
        out.flush();

        // 关闭流
        out.close();

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}
QueryProviceServlet.java

3-结果查询

 输入编号,点击搜索,显示出对应的结果:


相关资料:

     《王鹤讲AJAX》

原文地址:https://www.cnblogs.com/penguin1024/p/15501711.html