【第48天】AJAX在原生JS中的使用,处理XML数据以及DBUtils的使用,假删除(标记删除)

1 介绍

       AJAX(Asynchronized Javascript And Xml,异步的JS与XML)。

1.1 同步和异步

       同步和异步是B/S架构的两种重要模式,异步多了一个JS发出请求的函数和一个接收响应的回调(callback)函数,耗资源大但是效率较高。而同步虽然低效,但是耗资源少。异步与同步配合工作。

同步
用户发出请求,必须等待响应的返回,在响应返回前,用户必须等待,
不能进行任何操作,当响应返回整个页面全部刷新

异步
用户发出请求,不需要等待响应的返回,用户可以继续自己的操作,在未来的
一个时间段,响应应该返回,返回之后不影响用户当前的操作,页面部分更新
1.1.1 基于AJAX的异步传输与传统同步传输的对比

在这里插入图片描述

       大多数情况下,传统同步传输尽管可能只改变了一行文本或者一个图像,但还是不能避免完全的页面刷新。如图:
在这里插入图片描述

       使用基于AJAX的异步传输,用户不必等候页面长时间加载,甚至服务器处理请求时,用户还可以继续使用页面。如图:
在这里插入图片描述

1.1.2 使用时间线表示同步和异步在过程上的区别
  • 同步:
    在这里插入图片描述

  • 异步:
    在这里插入图片描述

1.2 JS与AJAX的关系

       JS中并没有异步相关的技术,AJAX是使用JS语法的一个衍生技术,专门用来实现异步操作,严格地说AJAX不能算是JS的类库之一。

  • 常见的JS类库
    protoType YUI ExtJs jQuery dojo node.js Angular React VUE

1.3 AJAX用到的技术

  • 核心语法 JS
  • 用来封装和解析数据 XML
  • 解析XML DOM4j
  • 封装大量数据 JSON
  • 动态页面表现技术囊括了CSS XHTML HTML5等前端技术 DHTML

1.4 AJAX支持的三种数据类型(MIME)

  • 字符串 text/plain
  • JSON text/plain
  • XML text/xml

2 在原生JS中使用AJAX的步骤

       以查重这个应用为例,学习在原生JS中使用AJAX的步骤。

checkName.html

<!DOCTYPE html>
<html>
  <head>
    <title>查重</title>	
    <meta charset="utf-8" />
  </head>
  <body>
	<form action="#" method="get">
		<label for="nameid">用户姓名:</label>
		<input type="text" name="name" required 
		id="nameid" onblur="checkName(this.value)" />
		<span id="name_msg"></span>
		<br />
		<input type="submit" value="提交" id="sub" disabled />
	</form>
	<script>
		//1):创建异步请求
		let request;
		function create(){
			/*
				以下写法为level2版本的创建异步请求的方式
				如果遇到较为陈旧的浏览器 例如IE6 7 8 甚至更老的浏览器
				推荐使用level1版本的创建方式
				if(window.XMLHttpRequest){
					request = new XMLHttpRequest();
				}else{
					request = new ActiveXObject("Microsoft.XMLHttp");
				}
			*/
			request = new XMLHttpRequest();
		}
		
		//2):此函数为主函数,用来发送异步请求
		function checkName(value){
			
			//a:创建异步请求
			create();
			
			//b:设置发送异步请求的目的地
			//request.open(method, url, async, user, password)
			/*
				method:异步请求的提交方式 get或者post
				
				url:提交到哪里,注意如果是get方式则从此处传递值 url?key=value
				
				async:表示是否使用异步,默认为true使用异步,如果更改为
				false则使用同步,请求发出之后响应返回前浏览器锁死等待响应返回
				
				user与password:表示是否开启服务器安全策略,如果不填写表示不开启,
				tocmat等WEB服务器默认不开启
			*/
			request.open("post","servlet/Check",true);
			
			//c:如果请求方式为post,则必须指定字符流来传递数据(request.send())
			//get请求方式不需要书写此句
			//因为get传递的参数在地址后面拼(虚拟地址),直接以字符解析
			request.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
			
			//d:声明回调函数
			//这里的函数名为callback也可以随意书写但是注意不能添加括号,
			//添加括号表示调用,不加表示声明
			request.onreadystatechange = callback;
			//另外一种写法,直接等于一个匿名方法
			/*
			request.onreadystatechange = function(){
			}
			*/
			
			//e:如果请求方式为post,在此处传递值,即使不传递值也必须书写此句,内部填写null即可
			request.send("name="+value);
		}
		
		//回调函数的写法之一,另外一种可以直接把这个方法匿名地写在
		//onreadystatechange的等号后面
		function callback(){
			//保证返回的响应完整
			if(request.readyState==4){
				//保证服务器没有任何异常
				if(request.status==200){
					//接受服务器返回的数据
					let value = request.responseText;
					//拿取span
					let dom_sp = document.getElementById("name_msg");
					//拿取submit
					let dom_sub = document.getElementById("sub");
					
					//根据响应数据显示span和submit按钮的内容
					if(value=="exist"){
						dom_sp.innerHTML="用户名已经被占用";
						dom_sp.style.color="red";
						dom_sub.disabled = true;
						return;
					}
					dom_sp.innerHTML="用户名可以使用";
					dom_sp.style.color="green";
					dom_sub.disabled = false;
				}
			}
		}			
	</script>
  </body>
</html>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>AjaxDay1_check</display-name>
  <servlet>
    <servlet-name>Check</servlet-name>
    <servlet-class>com.test.servlet.Check</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>Check</servlet-name>
    <url-pattern>/servlet/Check</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
</web-app>

servlet/Check.java

package com.test.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Check extends HttpServlet {

	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		response.setContentType("text/plain;charset=utf-8");
		request.setCharacterEncoding("utf-8");
		PrintWriter out = response.getWriter();
		
		String value = request.getParameter("test");
		System.out.println("接受过来的用户名是:"+value);
		if(value.trim().equals("eric")){
			//返回响应给回调函数
			/*
			 * 注意
			 * 1.out.print在这里并不是输出页面,而是给回调函数返回响应
			 * 2.不能使用println,否则返回的字符串会自动添加“\n”
			 * */
			out.print("exist");
			out.close();
			return;
		}
		out.print("suc");
		out.close();
	}
}
  • 效果图:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.1 以上代码中需要注意的部分

2.1.1 AJAX回调函数

       只要readystate参数从2到4发生变化就执行一次回调函数。在这里readystate到4条件判断才执行,其实值为234时也执行了,只不过这里在上面的程序中没有代码执行。结合AJAX执行顺序见图:

在这里插入图片描述

  • 注释:
    • c、d、e步骤:
      c(视请求方式而定).如果请求方式为post,则必须指定字符流来传递数据,指定Content-Type。get请求方式不需要书写此句,因为get只传递字符。

      request.setRequestHeader(“Content-Type”,“application/x-www-form-urlencoded”);

      d.声明回调函数,两种方式,见上面源码。
      e.如果请求方式为post,在此处传递值,即使不传递值也必须书写此句,内部填写null即可。

      request.send(“name=”+value); //这是当post传值时,不传值时填写null

  • 状态码指令集:

1xx 返回消息
2xx 成功
3xx 重定向
4xx 请求错误 如401 403 404 405
5xx 服务器内部错误 如500

2.1.2 Content-Type(setRequestHeader()中的参数)(了解)

       注意:需要先调用open方法,之后再调用setRequestHeader方法!

  • 为何要用到setRequestHeader
    在HTTP协议里,客户端向服务器请求取得某个网页的时候,必须发送一个HTTP协议的头文件,告诉服务器客户端要下载什么信息以及相关的参数。 而XMLHTTP就是通过HTTP协议取得网站上的文件数据的,所以也要发送HTTP头给服务器。 但XMLHTTP默认的情况下有些参数可能没有说明在HTTP头里,当我们需要修改或添加这些参数时就用到了setRequestHeader方法。

  • setRequestHeader参数详解
    使用GET下列参数XMLObject.setRequestHeader (“CONTENT-TYPE”, “application/x-www-form-urlencoded” ),得到HTTP头:

POST /bb.asp HTTP/1.1
Accept: /
Accept-Language: zh-cn
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)
CONTENT-TYPE:application/x-www-form-urlencoded
Host: ourys.com
Content-length: 8
Connection: close
Cookie:%C3%F7%CC%EC=%B0%CB;ASPSESSIONIDASDBSDRR=BLEDBIBBCGKBJAKJCFEJKGII

注:

  1. CONTENT-TYPE: application/x-www-form-urlencoded含义是表示客户端提交给服务器文本内容的编码方式是URL编码,即除了标准字符外,每字节以双字节16进制前加个“%”表示。当然还有其他编码方式,如CONTENT-TYPE:multipart/form-data。
  2. Content-length:表示提交的数据字节大小,GET方式是没有提交内容的,GET传参通过虚拟地址传送,如GET /bb.asp?www=1234 HTTP/1.1,参数全部就只有 “www=1234” 这么多。所以 CONTENT-TYPE、Content-length在GET模式下是无效的。如果用POST的话就有些不同,POST将参数放到HTTP后面,以上面的HTTP为例,用POST的方法传参数“www=1234”时,发请求时需要声明编码方式,报头中出现Content-length大小了。
  3. Connection: Close,很明显英文的意思是连接:关闭,只是客户端在提交数据时告诉服务器让谁先关闭连接而已。

本节文字摘自Zero28093@CSDN,感谢大佬分享!

3 在原生JS中使用AJAX处理XML数据以及DBUtils的使用

       不再赘述数据库设计以及web.xml、Factory类、po层、dao层的接口,前面的文章中有写。在dao层的实现类代码中介绍DBUtils的使用。

3.1 例:使用AJAX异步请求读取数据库信息画出表格并填入信息

dao/StudentDaoImpl.java

package com.test.dao;

import com.test.factory.Factory;
import com.test.po.Student;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import java.sql.Connection;
import java.util.List;

public class StudentDaoImpl implements StudentDaoIf{

    Connection con;
    //引入DBUtils的查询执行器,QueryRunner是DBUtils框架的核心类
    QueryRunner qr = new QueryRunner();

    @Override
    public List<Student> queryAll() {
        try{
            String sql = "select * from student";
            con = Factory.getCon();
            /*
             * 进行查询操作,使用DBUtil,减轻增删改查的工作量
             * 被操作的实体类对应数据库的表,且有空参和全参构造函数
             * 否则会造成无法取出或取出的字段不全
             * 不需要再关连接,DBUtils自动关闭。
             *
             * qr.query(con,sql,ResultSetHandler)
             * con:表示数据源
             * sql:表示sql语句
             * ResultSetHandler:接口 可以通过调用此接口的子接口
             * 根据不同的sql语句进行操作
             * 返回 独立实体类       new BeanHandler<实体类名>(实体类名.class)
             * 返回 多个实体类集合   new BeanListHandler<实体类名>(实体类名.class)
             * 返回 long类型变量     new scalarHandler(); 返回的query为long类型,
             *                      若方法返回值为int,需要转换
             * */     
            return qr.query(con,sql,new BeanListHandler<Student>(Student.class));
        }catch(Exception ex){
            ex.printStackTrace();
            return null;
        }
    }

    @Override
    public boolean delStuById(Integer id) {
        try{
            con = Factory.getCon();
            String sql = "delete from student where id = ?";
            //增删改均用update方法
            return qr.update(con,sql,id)==1;
        }catch(Exception ex){
            ex.printStackTrace();
            return false;
        }
    }
}

servlet/ShowStudent.java

package com.test.servlet;

import com.test.dao.StudentDaoIf;
import com.test.dao.StudentDaoImpl;
import com.test.po.Student;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

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;
import java.util.List;

public class ShowStudent extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/xml;charset=utf-8");

        //以字符流将后面定义的XML输出到response中响应到客户端供AJAX解析
        PrintWriter out = response.getWriter();

        StudentDaoIf dao = new StudentDaoImpl();
        List<Student> list = dao.queryAll();

        //创建一个文档数据模型(document模型)
        Document doc = DocumentHelper.createDocument();
        //创建一个根元素
        /*
         *   <root></root>
         * */
        Element root = doc.addElement("root");

        for(Student stu : list){
            //以根元素root为根,创建多个一级子元素
            /*
             *   <root>
             *       <student></student>
             *       <student></student>
             *       <student></student>
             *       ***
             *   </root>
             *
             * */
            Element student = root.addElement("student");

            //在student标签中创建属性
            /*
             *   <root>
             *       <student id="" name=""></student>
             *       <student id="" name=""></student>
             *       <student id="" name=""></student>
             *       ***
             *   </root>
             *
             * */
            student.addAttribute("id", stu.getId() + "");
            student.addAttribute("name", stu.getName());

            //以一级子元素student为根,创建二级子元素
            /*
             *   <root>
             *       <student id="" name="">
             *          <email>***</email>
             *          <phone>***</phone>
             *       </student>
             *       <student id="" name="">
             *          <email>***</email>
             *          <phone>***</phone>
             *       </student>
             *       <student id="" name="">
             *          <email>***</email>
             *          <phone>***</phone>
             *       </student>
             *       ***
             *   </root>
             *
             * */
            Element email = student.addElement("email");
            email.setText(stu.getEmail());
            Element phone = student.addElement("phone");
            phone.setText(stu.getPhone());
        }

        //直接将document模型转换为XML输出到响应中
        out.print(doc.asXML());
        System.out.println(doc.asXML());
        out.close();
    }
}

xmlOperation.html

<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title>使用xml处理批量数据</title>
        <style>
            table{
                width: 500px;
                border-collapse: collapse;
            }
            table,tr,td{
                border:solid 2px silver;
            }

        </style>
    </head>

    <!--页面加载完成后就执行showAll()-->
    <body onload="showAll()">
        <!--定义一个空的div,后面使用原生JS写表格和数据到其中-->
        <div id="show"></div>
        <script>
            let request;
            function create(){
                request = new XMLHttpRequest();
            }

            function showAll(){
                create();
                request.open("post", "showStudent", true);
                request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
                //匿名回调函数
                request.onreadystatechange = function(){
                    //前面写到的readyState过程
                    if(request.readyState==4) {
                        if (request.status == 200) {
                            //返回一个xml标准格式的文档数据模型
                            let doc = request.responseXML;
                            /*
                             *   <root>
                             *       <student id="" name="">
                             *          <email>***</email>
                             *          <phone>***</phone>
                             *       </student>
                             *       <student id="" name="">
                             *          <email>***</email>
                             *          <phone>***</phone>
                             *       </student>
                             *       <student id="" name="">
                             *          <email>***</email>
                             *          <phone>***</phone>
                             *       </student>
                             *       ***
                             *   </root>
                             *
                             * */
                            //根据标签名拿取多个元素
                            let array = doc.getElementsByTagName("student");

                            //在页面显示表格,先画表头
                            let table = "<table><tr><td>ID</td><td>姓名</td><td>邮箱</td><td>手机</td><td>操作</td></tr>";

                            for (let i = 0; i < array.length; i++) {
                                //逐个拿取student标签
                                let student = array[i];
                                //拿取student标签中的id属性
                                let id = student.getAttribute("id");
                                //拿取同上的name属性
                                let name = student.getAttribute("name");
                                //拿取student内部email元素内部的值,
                                //这种取法虽然啰嗦但是浏览器适配性高(里面就一个文本内容但还要以第一个子元素的身份取,还要再获取一下节点值)
                                let email = student.getElementsByTagName("email")[0].firstChild.nodeValue;
                                let phone = student.getElementsByTagName("phone")[0].firstChild.nodeValue;

                                //画表格,将获取到的值画在表格体中,相当于拼字符串
                                table += "<tr><td>" + id + "</td><td>" + name + "</td><td>"
                                    + email + "</td><td>" + phone + "</td><td><label onclick='delStu(" + id + ")' style='cursor:pointer'>删除</label></td></tr>";

                            }
                            table += "</table>";
                            document.getElementById("show").innerHTML = table;
                        }
                    }
                };
                request.send(null);
            }
        </script>
    </body>
</html>

效果图:
在这里插入图片描述

3.2 例:使用AJAX异步请求实现假删除(标记删除)

       所谓的假删除是只在页面上删除,而数据库中依然存在。这就要求在数据库实体类对应的表中新增一个默认为0(也可以默认为其他数字)的字段,当用户删除一条信息时即更新这个字段为1,表示已删除。指定dao层SQL语句中查询全部数据并显示的方法加入过滤条件,当这个字段为0时可以查出,1时表示已删除不能显示。

更新3.1中dao层实现类的queryAll方法中的SQL语句

String sql = “select * from student where isdeleted = 0”;

新增3.1中dao层实现类delStuById方法

    @Override
    public boolean delStuById(Integer id) {
        try{
            con = Factory.getCon();
            String sql = "update student set isdeleted = 1 where id = ?";
            QueryRunner qr = new QueryRunner();
            //增删改均用update方法
            return qr.update(con,sql,id)==1;
        }catch(Exception ex){
            ex.printStackTrace();
            return false;
        }
    }

更新xmlOperation.html中的JS函数

   function delStu(id){
        if(confirm("确定删除这条数据吗?")){
            create();
            request.open("post", "del", true);
            request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            request.onreadystatechange = function(){
                if(request.readyState == 4){
                    if(request.status == 200){
                        let value = request.responseText;
                        if(value == "suc"){
                            //执行上面的显示方法再次异步查询显示数据
                            showAll();
                            return;
                        }
                        alert("删除失败!");
                    }
                }
            };
            // <a href="目的地?key=value">
            request.send("id=" + id);
        }
    }

servlet/DelStudent.java

package com.test.servlet;

import com.test.dao.StudentDaoIf;
import com.test.dao.StudentDaoImpl;

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 DelStudent extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/plain;charset=utf-8");

        StudentDaoIf dao = new StudentDaoImpl();
        PrintWriter out = response.getWriter();

        if(dao.delStuById(Integer.parseInt(request.getParameter("id")))){
            out.print("suc");
            out.close();
            return;
        }
        out.print("err");
        out.close();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值