您的位置:首页 > Web前端 > JavaScript

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

2019-01-14 13:01 369 查看
版权声明:©2018 本文為博主來秋原創,轉載請註明出處,博主保留追責權利。 https://blog.csdn.net/qq_30257081/article/details/86368778
  • 1.2 JS与AJAX的关系

  • 1.3 AJAX用到的技术

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

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

  • 3 在原生JS中使用AJAX处理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();
    }
    }
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: