Ajax(上)

目录

传统请求及缺点

AJAX概述

XMLHttpRequest对象

AJAX GET请求

AJAX POST请求


传统请求及缺点

传统的请求都有哪些?

直接在浏览器地址栏上输入URL。

  • 点击超链接
  • 提交form表单
  • 使用JS代码发送请求

    window.open(url)

    document.location.href = url

    window.location.href = url

    ....

传统请求存在的问题

  • 页面全部刷新导致了用户的体验较差。
  • 传统的请求导致用户的体验有空白期。(用户的体验是不连贯的)

AJAX概述

AJAX不能称为一种技术,它是多种技术的综合产物。

AJAX可以让浏览器发送一种特殊的请求,这种请求可以是:

  • 异步的。

什么是异步,什么是同步?

  • 假设有t1和t2线程,t1和t2线程并发,就是异步。
  • 假设有t1和t2线程,t2在执行的时候,必须等待t1线程执行到某个位置之后t2才能执行,那么t2在等t1,显然他们是排队的,排队的就是同步。
  • AJAX是可以发送异步请求的。也就是说,在同一个浏览器页面当中,可以发送多个ajax请求,这些ajax请求之间不需要等待,是并发的。

AJAX代码属于WEB前端的JS代码。和后端的java没有关系,后端也可以是php语言,也可以是C语言。

AJAX 应用程序可能使用 XML 来传输数据,但将数据作为纯文本或 JSON 文本传输也同样常见。

AJAX可以更新网页的部分,而不需要重新加载整个页面。(页面局部刷新)

AJAX可以做到在同一个网页中同时启动多个请求,类似于在同一个网页中启动“多线程”,一个“线程”一个“请求”。

XMLHttpRequest对象

  • XMLHttpRequest对象是AJAX的核心对象,发送请求以及接收服务器数据的返回,全靠它了。
  • XMLHttpRequest对象,现代浏览器都是支持的,都内置了该对象。直接用即可。

创建XMLHttpRequest对象

var xhr = new XMLHttpRequest();

XMLHttpRequest对象的方法

方法

描述

abort()

取消当前请求

getAllResponseHeaders()

返回头部信息

getResponseHeader()

返回特定的头部信息

open(method, url, async, user, psw)

规定请求method:请求类型 GET 或 POSTurl:文件位置async:true(异步)或 false(同步)user:可选的用户名称psw:可选的密码

send()

将请求发送到服务器,用于 GET 请求

send(string)

将请求发送到服务器,用于 POST 请求

setRequestHeader()

向要发送的报头添加标签/值对

XMLHttpRequest对象的属性

属性

描述

onreadystatechange

定义当 readyState 属性发生变化时被调用的函数

readyState

保存 XMLHttpRequest 的状态。0:请求未初始化 1:服务器连接已建立 2:请求已收到 3:正在处理请求 4:请求已完成且响应已就绪

responseText

以字符串返回响应数据

responseXML

以 XML 数据返回响应数据

status

返回请求的状态号200: "OK"403: "Forbidden"404: "Not Found"

statusText

返回状态文本(比如 "OK" 或 "Not Found")

AJAX GET请求

前端代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>发送ajax get请求</title>
</head>
<body>
<script type="text/javascript">
    window.onload = function () {
        document.getElementById("btn").onclick = function () {
            //1. 创建AJAX核心对象
            var xhr = new XMLHttpRequest();
            //2. 注册回调函数
            xhr.onreadystatechange = function(){
                if (this.readyState == 4) {
                    if (this.status == 200) {
                        // 通过XMLHttpRequest对象的responseText属性可以获取到服务器响应回来的内容。
                        // 并且不管服务器响应回来的是什么,都以普通文本的形势获取。(服务器可能响应回来:普通文本、XML、JSON、HTML...)
                        // innerHTML属性是javascript中的语法,和ajax的XMLHttpRequest对象无关。
                        // innerHTML可以设置元素内部的HTML代码。(innerHTML可以将后面的内容当做一段HTML代码解释并执行)
                        //document.getElementById("myspan").innerHTML = this.responseText
                        document.getElementById("mydiv").innerHTML = this.responseText
                        // innerText也不是AJAX中的,是javascript中的元素属性,和XMLHttpRequest无关。
                        // innerText也是设置元素中的内容,但是即使后面是一段HTML代码,也是将其看做一个普通字符串设置进去。
                        //document.getElementById("myspan").innerText = this.responseText
                    }else{
                        alert(this.status)
                    }
                }
            }
            //3. 开启通道
            xhr.open("GET", "/ajax/ajaxrequest2", true)
            //4. 发送请求
            xhr.send()
        }
    }
</script>
<button id="btn">发送ajax get请求</button>
<span id="myspan"></span>
<div id="mydiv"></div>
</body>
</html>

后端代码:

package com.bjpowernode.ajax.servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

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

/**
 * @program: 代码
 * @ClassName: AjaxRequest2Servlet
 * @version: 1.0
 * @description:
 * @author: bjpowernode
 * @create: 2022-05-13 10:46
 **/

@WebServlet("/ajaxrequest2")
public class AjaxRequest2Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 设置响应的内容类型以及字符集
        response.setContentType("text/html;charset=UTF-8");
        // 获取响应流
        PrintWriter out = response.getWriter();
        // 响应
        out.print("<font color='red'>用户名已存在!!!</font>");
    }
}

AJAX get请求如何提交数据呢?

  • get请求提交数据是在“请求行”上提交,格式是:url?name=value&name=value&name=value....
  • 其实这个get请求提交数据的格式是HTTP协议中规定的,遵循协议即可。

AJAX GET请求的缓存问题

对于低版本的IE浏览器来说,AJAX的get请求可能会走缓存。存在缓存问题。对于现代的浏览器来说,大部分浏览器都已经不存在AJAX get缓存问题了。

什么是AJAX GET请求缓存问题呢?

  • 在HTTP协议中是这样规定get请求的:get请求会被缓存起来。
  • 发送AJAX GET请求时,在同一个浏览器上,前后发送的AJAX请求路径一样的话,对于低版本的IE来说,第二次的AJAX GET请求会走缓存,不走服务器。

POST请求在HTTP协议中规定的是:POST请求不会被浏览器缓存。

GET请求缓存的优缺点:

  • 优点:直接从浏览器缓存中获取资源,不需要从服务器上重新加载资源,速度较快,用户体验好。
  • 缺点:无法实时获取最新的服务器资源

浏览器什么时候会走缓存?

  • 第一:是一个GET请求
  • 第二:请求路径已经被浏览器缓存过了。第二次发送请求的时候,这个路径没有变化,会走浏览器缓存。

如果是低版本的IE浏览器,怎么解决AJAX GET请求的缓存问题呢?

可以在请求路径url后面添加一个时间戳,这个时间戳是随时变化的。所以每一次发送的请求路径都是不一样的,这样就不会走浏览器的缓存问题了。

可以采用时间戳:"url?t=" + new Date().getTime()

或者可以通过随机数:"url?t=" + Math.random()

也可以随机数+时间戳....

AJAX POST请求

AJAX POST请求和GET请求的代码区别在哪里?就是前端代码有区别。后端代码没有区别。

// 4. 发送AJAX POST请求
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded") // 设置请求头的内容类型。模拟form表单提交数据。
// 获取表单中的数据
var username = document.getElementById("username").value;
var password = document.getElementById("password").value;
// send函数中的参数就是发送的数据,这个数据在“请求体”当中发送。
xhr.send("username="+username+"&password="+password)

实现一个案例:

使用AJAX POST请求实现用户注册的时候,用户名是否可用。(验证用户名是否可以注册)实现步骤如下:

在前端,用户输入用户名之后,失去焦点事件blur发生,然后发送AJAX POST请求,提交用户名

在后端,接收到用户名,连接数据库,根据用户名去表中搜索

如果用户名已存在

  • 后端响应消息:对不起,用户名已存在(在前端页面以红色字体展示)

如果用户名不存在

  • 后端响应消息:用户名可以使用(在前端页面以绿色字体展示)

前端代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>AJAX POST请求验证用户名是否可用</title>
  </head>
  <body>
    
    <script type="text/javascript">
      window.onload = function(){
        
        document.getElementById("username").onfocus = function (){
          document.getElementById("tipMsg").innerHTML = ""
        }
        
        document.getElementById("username").onblur = function (){
          //console.log("正在发送AJAX POST请求验证用户名")
          // 发送AJAX POST请求
          // 1.
          var xhr = new XMLHttpRequest()
          // 2.
          xhr.onreadystatechange = function () {
            if (this.readyState == 4) {
              if (this.status == 200) {
                document.getElementById("tipMsg").innerHTML = this.responseText
              }else{
                alert(this.status)
              }
            }
          }
          // 3.
          xhr.open("POST", "/ajax/ajaxrequest4", true)
          // 4.
          xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
          // 获取表单数据
          var username = document.getElementById("username").value
          xhr.send("uname=" + username)//这个uname随便写,前端的发送,后端使用这个接受
        }
      }
    </script>
    
    用户名:<input type="text" id="username">
    
    <span id="tipMsg"></span>
    
  </body>
</html>

后端代码

package com.bjpowernode.ajax.servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.*;

/**
 * @program: 代码
 * @ClassName: AjaxRequest4Servlet
 * @version: 1.0
 * @description: 验证用户名是否可用
 * @author: bjpowernode
 * @create: 2022-05-14 10:19
 **/
@WebServlet("/ajaxrequest4")
public class AjaxRequest4Servlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 获取用户名
        String uname = request.getParameter("uname");
        // 打布尔标记(一种编程模型)
        boolean flag = false; // 默认是用户名不存在。
        // 连接数据库验证用户名是否存在
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            // 1.注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 2.获取连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC", "root", "root");
            // 3.获取预编译的数据库操作对象
            String sql = "select id,name from t_user where name = ?";
            ps = conn.prepareStatement(sql);
            ps.setString(1, uname);
            // 4.执行SQL语句
            rs = ps.executeQuery();
            // 5.处理结果集
            if (rs.next()) {
                // 用户名已存在。
                flag = true;
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 6.释放资源
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }

        // 响应结果到浏览器
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        if (flag) {
            // 用户名已存在,不可用
            out.print("<font color='red'>对不起,用户名已存在</font>");
        }else{
            // 用户名不存在,可以使用
            out.print("<font color='green'>用户名可以使用</font>");
        }
    }
}

实现一个案例:

用户点击按钮之后,发送AJAX请求,显示学生列表。

在后端java程序中拼接HTML代码,然后将HTML代码直接响应到浏览器客户端。这种方式不好,不应该在java代码中编写HTML代码,能否在java程序中直接向前端响应数据?可以,可以在后端拼接JSON格式的字符串,或者XML格式的字符串,将这个字符串发送给前端,前端解析即可。

前端代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>发送AJAX请求,显示学生列表</title>
  </head>
  <body>
    
    <script type="text/javascript">
      window.onload = function () {
        document.getElementById("btn").onclick = function () {
          // 1.创建核心对象
          var xhr = new XMLHttpRequest();
          // 2.注册回调函数
          xhr.onreadystatechange = function () {
            if (this.readyState == 4) {
              if (this.status == 200) {
                //document.getElementById("stutbody").innerHTML = this.responseText
                
                // 将json格式的字符串转换成json对象
                var stuList = JSON.parse(this.responseText) // 是一个数组,并且数组中有多个学生数据
                var html = ""
                for (var i = 0; i < stuList.length; i++) {
                  var stu = stuList[i]
                  html += "<tr>"
                  html += "<td>"+(i+1)+"</td>"
                  html += "<td>"+stu.name+"</td>"
                  html += "<td>"+stu.age+"</td>"
                  html += "<td>"+stu.addr+"</td>"
                  html += "</tr>"
                }
                document.getElementById("stutbody").innerHTML = html
                
              } else {
                alert(this.status)
              }
            }
          }
          // 3.开启通道
          xhr.open("GET", "/ajax/ajaxrequest5?t=" + new Date().getTime(), true)
          // 4.发送请求
          xhr.send()
        }
      }
    </script>
    
    <input type="button" value="显示学员列表" id="btn">
    
    <table width="50%" border="1px">
      <thead>
        <tr>
          <th>序号</th>
          <th>姓名</th>
          <th>年龄</th>
          <th>住址</th>
        </tr>
      </thead>
      <tbody id="stutbody">
        <!--<tr>
        <td>1</td>
        <td>张三</td>
        <td>20</td>
        <td>北京大兴区</td>
    </tr>
    <tr>
        <td>2</td>
        <td>李四</td>
        <td>22</td>
        <td>北京海淀区</td>
    </tr>-->
      </tbody>
    </table>
    
  </body>
</html>

后端代码

package com.bjpowernode.ajax.servlet;

import com.alibaba.fastjson.JSON;
import com.bjpowernode.ajax.beans.Student;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
* @program: 代码
* @ClassName: AjaxRequest5Servlet
* @version: 1.0
* @description: 发送AJAX请求动态展示学员列表
* @author: bjpowernode
* @create: 2022-05-14 12:08
**/
@WebServlet("/ajaxrequest5")
public class AjaxRequest5Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 连接数据库,查询学员信息,拼接HTML代码,响应HTML代码到浏览器(这里就不再连接数据库了,写死了。)
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        
        /*// 连接数据库,拼接HTML代码
        StringBuilder html = new StringBuilder();
        
        // 目前存在的缺点:在后端的java代码中又开始拼接HTML代码了。显然这是在后端java中写前端的HTML代码。不好维护。
        // 能不能直接将数据返回,给WEB前端数据就行了。让WEB前端能够拿到数据就行,然后页面展示的功能交给WEB前端来处理。
        // 我们后端的java代码能不能只返回数据????可以。(返回数据可以采用JSON的格式,也可以采用XML的格式)
        html.append("<tr>");
        html.append("<td>1</td>");
        html.append("<td>王五</td>");
        html.append("<td>20</td>");
        html.append("<td>北京大兴区</td>");
        html.append("</tr>");
        html.append("<tr>");
        html.append("<td>2</td>");
        html.append("<td>李四</td>");
        html.append("<td>22</td>");
        html.append("<td>北京海淀区</td>");
        html.append("</tr>");
        
        out.print(html);*/
        
        // 将以上程序拼接HTML,换成拼接JSON格式的字符串。
        //String jsonStr = "[{\"name\":\"王五\",\"age\":20,\"addr\":\"北京大兴区\"}, {\"name\":\"李四\",\"age\":22,\"addr\":\"北京海淀区\"}]";
        
        // 准备StringBuilder对象,拼接JSON
        StringBuilder json = new StringBuilder();
        String jsonStr = "";
        
        // 连接数据库,查询所有的学生,拼接json字符串
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            // 1.注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 2.获取连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC", "root", "root");
            // 3.获取预编译的数据库操作对象
            String sql = "select name, age, addr from t_student";
            ps = conn.prepareStatement(sql);
            // 4.执行SQL语句
            rs = ps.executeQuery();
            // 5.处理结果集
            /*json.append("[");
            while (rs.next()) {
            // 获取每个学生的信息
            String name = rs.getString("name");
            String age = rs.getString("age");
            String addr = rs.getString("addr");
            // 拼接json格式的字符串
            // {"name":"   王五    ","age":    20      ,"addr":"      北京大兴区     "},
            json.append("{\"name\":\"");
            json.append(name);
            json.append("\",\"age\":");
            json.append(age);
            json.append(",\"addr\":\"");
            json.append(addr);
            json.append("\"},");
            }
            jsonStr = json.substring(0, json.length() - 1) + "]";*/
            
            
            List<Student> studentList = new ArrayList<>();
            while (rs.next()) {
                // 取出数据
                String name = rs.getString("name");
                int age = rs.getInt("age");
                String addr = rs.getString("addr");
                // 将以上数据封装成Student对象
                Student s = new Student(name, age, addr);
                // 将Student对象放到List集合
                studentList.add(s);
            }
            
            // 将List集合转换成json字符串
            jsonStr = JSON.toJSONString(studentList);
            
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 6.释放资源
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        
        // 响应JSON格式的字符串给前端。
        out.print(jsonStr);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值