Bootstrap

AJAX:实现局部刷新

开始时间:2021-09-04

AJAX

全局刷新和局部刷新

  • 全局刷新:整个浏览器被新的数据覆盖。在网络中传输大量的数据。浏览器需要加载,渲染页面.
  • 部分刷新:在浏览器器的内部,发起请求,获取数据,改变页面中的部分内容。其余的页面无需加载和渲染。网络中数据传输量少,给用户的感受好。

Ajax用来做异步刷新,局部刷新使用的核心对象是异步对象(XMLHttpRequest)

AJAX概念

AJAX=Asynchronous JavaScript and XML(异步的JavaScript和 XML)。
XML是一种数据格式,之前配置Servlet就是在web.xml中配置的

AJAX是一种做局部刷新的方法,不是一种语言。AJAX包含的技术主要有Javascript,dom , css, xml等等。核心是javascript和xml .

  • Javascript:负责创建异步对象,发送请求,更新页面的dom对象。
  • AJAX请求需要服务器端的数据。
  • xml:网络中的传输的数据格式。使用json替换了xml .
    在这里插入图片描述

XMLHttpRequest对象

ajax中使用XMLHttpRequest对象

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

给异步对象绑定事件。

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

  btn.onclick = fun1()
    function fun1(){
     alert("按钮单击");
    }

例如:

   
    xmlHttp.onreadystatechange= function(){
       处理请求的状态变化。
		 if(xmlHttp.readyState == 4 && xmlHttp.status== 200 ){
           //拿到服务器返回的数据,可以处理服务器端的数据,更新当前页面
			  var data = xmlHttp.responseText;
			  document.getElementById("name").value= data;
		 }
    }

异步对象的属性 readyState 表示异步对象请求的状态变化
0:创建异步对象时, new XMLHttpRequest();
1: 初始异步请求对象, xmlHttp.open()
2:发送请求, xmlHttp.send()
3: 从服务器端获取了数据,此时3, 注意3是异步对象内部使用, 获取了原始的数据。
4:异步对象把接收的数据处理完成后。 此时开发人员在4的时候处理数据。
在4的时候,开发人员做什么 ? 更新当前页面。

异步对象的status属性,表示网络请求的状况的(状态码参考博客), 200, 404, 500, 需要是当status==200
时,表示网络请求是成功的。
上面1-4步每一步状态变化都会调用上面写的函数,通过查看readyState可以看到对应数字

alert("readyState属性值" + xmlHttp.readyState);

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

初始异步请求对象

 异步的方法open().
  xmlHttp.open(请求方式get或者是post, "服务器端的访问地址", 同步或者异步请求(默认是true,异步请求))
  例如下面的语句,分别对应上面三个部分 方式 地址 请求
	  xmlHttp.open("get", "loginServlet?name=zs&pwd=123",true);

使用异步对象发送请求

 xmlHttp.send()

全局刷新示例

写一个Servlet

package controller;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class BmiServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //接收请求参数
        String name = request.getParameter("name");
        String height = request.getParameter("height");
        String weight = request.getParameter("weight");
        //计算Bmi
        float h = Float.valueOf(height);
        float w = Float.valueOf(weight);
        float bmi = w / (h * h);
        System.out.println("ni好");
        //bmi分级
        String flag = "";
        if (bmi >= 18 && bmi <= 24) {
            flag = "正常体重";
        } else if (bmi > 24 && bmi <= 28) {
            flag = "轻微肥胖";
        } else if (bmi > 28) {
            flag = "比较肥胖";
        } else {
            flag = "偏瘦";
        }
        System.out.println("身体情况为:" + flag);
        flag = "你好," + name + "先生" + "你的BMI指数为" + bmi + "身体情况为" + flag;
        request.setAttribute("key", flag);
        request.getRequestDispatcher("/result.jsp").forward(request, response);

    }
}

再写两个jsp界面

<html>
<head>
    <title>全局刷新</title>
</head>
<body>
<form action="Bmi" method="get">

    姓名<input type="text" name="name"><br/>
    体重(kg)<input type="text" name="weight"><br/>
    身高(m)<input type="text" name="height"><br/>
    <input type="submit" value="提交">
</form>
</body>
</html>
<html>
<head>
    <title>结果页面</title>
</head>
<body>
<p>显示结果</p>
<h>${key}</h>
</body>
</html>

在这里插入图片描述

这里又出现了一次乱码,应该是新建工程的时候用的Gradle,如果选择Maven则不会报错,因为之前也有这个问题,所以统一说明一下。

局部刷新示例

写一个新的Servlet

package 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 BmiPrintServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("能够响应AJAX的请求");

        //接收请求参数,传参用的就是h和w
        String name = request.getParameter("name");
        String height = request.getParameter("h");
        String weight = request.getParameter("w");

        //计算Bmi
        float h = Float.valueOf(height);
        float w = Float.valueOf(weight);
        float bmi = w / (h * h);

        //bmi分级
        String flag = "";
        if (bmi >= 18 && bmi <= 24) {
            flag = "正常体重";
        } else if (bmi > 24 && bmi <= 28) {
            flag = "轻微肥胖";
        } else if (bmi > 28) {
            flag = "比较肥胖";
        } else {
            flag = "偏瘦";
        }
        System.out.println("身体情况为:" + flag);
        flag = "你好," + name + "先生" + "你的BMI指数为" + bmi + "身体情况为" + flag;

        //响应AJAX需要的数据,把数据传回去

        response.setContentType("text/html;charset=utf-8");
        PrintWriter pw = response.getWriter();
        pw.println(flag);
        pw.flush();
        pw.close();

    }
}

再写一个index界面

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
    <title>全局刷新</title>
</head>
<script type="text/javascript">
    function doAJAX() {
        //创建异步对象
        var xmlHttp = new XMLHttpRequest();
        //给异步对象绑定事件
        xmlHttp.onreadystatechange = function () {
            //处理服务器返回的数据,更新当前页面
            alert("readyState属性值" + xmlHttp.readyState + "|Status:" + xmlHttp.status);
            if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
                // alert(xmlHttp.responseText);
                var data = xmlHttp.responseText;
                document.getElementById("data").innerHTML = data;
            }
        }
        //初始异步请求对象
        var name = document.getElementById("name").value;
        var w = document.getElementById("weight").value;
        var h = document.getElementById("height").value;

        //bmiPrint?name=李四&w=82&h=1.8 此处为传参格式
        var param = "name=" + name + "&w=" + w + "&h=" + h;
        alert("param:" + param);
        //open里面就要写传参格式,方式,地址和异步
        xmlHttp.open("get", "Print?" + param, true);
        //使用异步对象发送请求
        xmlHttp.send();
    }


</script>
<body>
姓名<input type="text" id="name"><br/>
体重(kg)<input type="text" id="weight"><br/>
身高(m)<input type="text" id="height"><br/>


<div id="data">
    <br/>
    等待加载资源...
    <br/>
</div>
<!--不需要form-->
<br/>
<input type="button" value="计算BMI" onclick="doAJAX()">
</body>
</html>

看一下效果
输入信息,然后计算,点击计算整个页面是没有刷新的
请添加图片描述
上面的open()和send()对应 1 2 两个状态

通过PrintWriter那边,返回数据给jsp文件,然后执行3和4
3: 从服务器端获取了数据,此时3, 注意3是异步对象内部使用, 获取了原始的数据。
4:异步对象把接收的数据处理完成后。 此时开发人员在4的时候处理数据。
这四部分每次触发,都得到对应数字的状态码
请添加图片描述

根据省份编号获取省份名称

首先需要建表
建表就用Navicat里面建一个就行
在这里插入图片描述
主要的两个sql文件,一个就是省份的,一个是城市的,这两个从动力节点的官网上找AJAX部分可以下载资源
找到表,右键,运行SQL文件
在这里插入图片描述
刷新一下

在这里插入图片描述

SET FOREIGN_KEY_CHECKS=0;

DROP TABLE IF EXISTS `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;


INSERT INTO `city` VALUES ('1', '石家庄市', '1');
INSERT INTO `city` VALUES ('2', '秦皇岛', '1');
INSERT INTO `city` VALUES ('3', '保定市', '1');
INSERT INTO `city` VALUES ('4', '张家口', '1');
INSERT INTO `city` VALUES ('5', '南昌市', '9');
INSERT INTO `city` VALUES ('6', '九江市', '9');
INSERT INTO `city` VALUES ('7', '宜春市', '9');
INSERT INTO `city` VALUES ('8', '福州市', '8');
INSERT INTO `city` VALUES ('9', '厦门市', '8');
INSERT INTO `city` VALUES ('10', '泉州市', '8');
INSERT INTO `city` VALUES ('11', '龙岩市', '8');
INSERT INTO `city` VALUES ('12', '太原', '2');
INSERT INTO `city` VALUES ('13', '大同', '2');
INSERT INTO `city` VALUES ('14', '呼和浩特', '3');
INSERT INTO `city` VALUES ('15', '包头', '3');
INSERT INTO `city` VALUES ('16', '呼伦贝尔', '3');

SET FOREIGN_KEY_CHECKS=0;


DROP TABLE IF EXISTS `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;


INSERT INTO `province` VALUES ('1', '河北', '冀', '石家庄');
INSERT INTO `province` VALUES ('2', '山西', '晋', '太原市');
INSERT INTO `province` VALUES ('3', '内蒙古', '蒙', '呼和浩特市	');
INSERT INTO `province` VALUES ('4', '辽宁', '辽', '沈阳');
INSERT INTO `province` VALUES ('5', '江苏', '苏', '南京');
INSERT INTO `province` VALUES ('6', '浙江', '浙', '杭州');
INSERT INTO `province` VALUES ('7', '安徽', '皖', '合肥');
INSERT INTO `province` VALUES ('8', '福建', '闽', '福州');
INSERT INTO `province` VALUES ('9', '江西', '赣', '南昌');

这一个程序主要是多了用JDBC连接数据库的过程。

写好了一个DAO类,DAO复习参考博客

package dao;
//封装JDBC

import java.sql.*;

//使用jdbc访问数据库
public class ProvinceDao {

    //根据id获取名称
    public String queryProviceNameById(Integer proviceId) {
        Connection conn = null;
        PreparedStatement pst = null;
        ResultSet rs = null;
        String sql = "";

        String url = "jdbc:mysql://localhost:3306/springdb";
        String username = "root";
        String password = "333";

        String name = "";
        //加载驱动
        try {
            //这里的包用的老版本,所以不是
            //com.mysql.cj.jdbc.Driver
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection(url, username, password);
            //创建PreparedStatement
            sql = "select  name from province where id=?";
            pst = conn.prepareStatement(sql);
            //设置参数值
            pst.setInt(1, proviceId);
            //执行sql
            rs = pst.executeQuery();
            //遍历rs
            /*while(rs.next()){ //当你的rs中有多余一条记录时。
               name =  rs.getString("name");
            }*/

            if (rs.next()) {
                name = rs.getString("name");
            }

        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }
                if (pst != null) {
                    pst.close();
                }
                if (conn != null) {
                    conn.close();
                }

            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        return name;
    }

Servlet

package controller;

import dao.ProvinceDao;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;

public class QueryProvinceServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String Proid = request.getParameter("proid");
        System.out.println("Proid:" + Proid);
        String name = "";
        //访问dao
        if (Proid != null && !"".equals(Proid.trim())) {
            ProvinceDao dao = new ProvinceDao();
            name = dao.queryProviceNameById(Integer.valueOf(Proid));
        }
        //输出数据
        response.setContentType("text/html;charset=utf-8");
        PrintWriter pw = response.getWriter();
        pw.println(name);
        pw.flush();
        pw.close();
    }
}

还会要写一个index.jsp

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
    <title>JSP - Hello World</title>
</head>
<script type="text/javascript">
    function search() {
        //发起ajax请求,传递参数给服务器, 服务器返回数据
        //1.创建异步对象
        var xmlHttp = new XMLHttpRequest();
        //2.绑定事件
        xmlHttp.onreadystatechange = function () {
            if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
                alert(xmlHttp.responseText)
                //更新页面,就是更新dom对象
                document.getElementById("proname").value = xmlHttp.responseText;

            }
        }
        //3.初始异步对象
        //获取proid文本框的值
        var proid = document.getElementById("proid").value;
        xmlHttp.open("get", "query?proid=" + proid, true);

        //4.发送请求
        xmlHttp.send();
    }

</script>
<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>

查看效果
输入河北的编号1
请添加图片描述
输入山西的编号2

请添加图片描述
输入没有入库的编号

请添加图片描述

使用JSON作为数据交换格式

AJAX发送请求,返回一个JSON格式的字符串

JSON工具库

名称备注
gsongoogle
fastjson速度快,但不是最符合JSON规范
Jackson性能好,规范
JSON-lib性能差依赖多
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import entity.Province;

public class TestJson {
    public static void main(String[] args) throws JsonProcessingException {
        Province p = new Province(1, "河北", "冀", "石家庄");
        //使用Jackson把p转为Json
        ObjectMapper om = new ObjectMapper();

        //把参数的Java对象转为JSON格式的字符串
        String json = om.writeValueAsString(p);
        System.out.println("转换后的JSON:" + json);
    }
}

输出

转换后的JSON:{"id":1,"name":"河北","jiancheng":"冀","shenghui":"石家庄"}

测试成功,能够正常使用

那么我们做一个完整的测试
先写一个Servlet

package controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import dao.ProvinceDao;
import entity.Province;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;

public class QueryJsonServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String proid = request.getParameter("proid");
        //默认值也设置为一个JSON格式的样子
        String json = "{}";
        if (proid != null && proid.trim().length() > 0) {
            ProvinceDao dao = new ProvinceDao();
            Province p = dao.queryProviceById(Integer.valueOf(proid));
            //Province转为Jackson
            ObjectMapper om = new ObjectMapper();
            json = om.writeValueAsString(p);

        }
        //返回json格式数据
        response.setContentType("application/json;charset=utf-8");
        PrintWriter pw = response.getWriter();
        pw.println(json);
        pw.flush();
        pw.close();
    }


}

然后写一个DAO类

package dao;
//封装JDBC

import entity.Province;

import java.sql.*;

//使用jdbc访问数据库
public class ProvinceDao {
    //根据id获取一个完整的Province对象
    public Province queryProviceById(Integer proviceId) {
        Connection conn = null;
        PreparedStatement pst = null;
        ResultSet rs = null;
        String sql = "";

        String url = "jdbc:mysql://localhost:3306/springdb";
        String username = "root";
        String password = "333";

        Province province = null;
        //加载驱动
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection(url, username, password);
            //创建PreparedStatement
            sql = "select id, name, jiancheng, shenghui  from province where id=?";
            pst = conn.prepareStatement(sql);
            //设置参数值
            pst.setInt(1, proviceId);
            //执行sql
            rs = pst.executeQuery();
            //遍历rs
            /*while(rs.next()){ //当你的rs中有多余一条记录时。
               name =  rs.getString("name");
            }*/

            if (rs.next()) {
                province = new Province();
                province.setId(rs.getInt("id"));
                province.setName(rs.getString("name"));
                province.setJiancheng(rs.getString("jiancheng"));
                province.setShenghui(rs.getString("shenghui"));
            }

        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }
                if (pst != null) {
                    pst.close();
                }
                if (conn != null) {
                    conn.close();
                }

            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        return province;
    }
}

index界面
设计到用了一个eval函数,参考博客

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
    <title>JSP - Hello World</title>
</head>
<script type="text/javascript">
    function search() {
        //发起ajax请求,传递参数给服务器, 服务器返回数据
        //1.创建异步对象
        var xmlHttp = new XMLHttpRequest();
        //2.绑定事件
        xmlHttp.onreadystatechange = function () {
            if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
                alert(xmlHttp.responseText)
                //更新页面,就是更新dom对象
                var data = xmlHttp.responseText;
                var jsonobj = eval("(" + data + ")");
                //先获取,再填充
                document.getElementById("proname").value = jsonobj.name;
                document.getElementById("projiancheng").value = jsonobj.jiancheng;
                document.getElementById("proshenghui").value = jsonobj.shenghui;

            }
        }
        //3.初始异步对象
        //获取proid文本框的值
        var proid = document.getElementById("proid").value;
        //true 异步处理,send发出去后不用等待,继续执行代码,收到返回的请求后再执行上面的函数
        xmlHttp.open("get", "queryjson?proid=" + proid, true);

        //4.发送请求
        xmlHttp.send();
        //立刻执行alert,无需等待
        alert("after send");
    }

</script>
<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>
    <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>

看看效果

请添加图片描述
结束时间 2021-09-06

;