目录
1 传统请求的缺点
为什么要学习Ajax?
传统请求方式有缺点:在之前我们学习发送请求的时候,每发送一次请求,页面就会刷新一次,也就是说当我在一个页面发送请求的时候,请求到另一个页面,整个页面就会变为请求后的页面。假如我正在看视频,视频正在缓存,但是这时我想登录,传统请求这时就会跳转到登录界面,我看的视频界面就没了,缓存也没了,需要重新打开视频,体验极差。
大概演示一下传统请求的请求是什么样子,下面是几个我们学过的请求:
这时的页面底层是这个样子:
我们点击一个请求:
我们发现页面直接刷新为请求后的页面了,大概这个意思。我们使用Ajax就可以使这两个页面变成一个页面,之前的请求就不用了。经典白学。
2 Ajax概述
- Ajax全称为:Asynchronous JavaScript And Xml
- Ajax不能称为一种技术,它是多种技术的综合产物,Ajax属于Web前端的JS代码,和后端的java没有关系,后端可以是别的语言比如C语言,php语言。
- Ajax可以让浏览器发送一种特殊的请求,这种请求可以是异步的
- 什么是异步,什么是同步?假设有两个线程t1和t2,t1和t2线程并发就是异步,t2在执行的时候必须等待t1执行完,它们是排队执行的,这是同步。
- Ajax应用程序可能使用XML来传输数据,但将数据作为纯文本或JSON文本传输也同样常见
- Ajax可以更新网页的部分,不需要加载整个页面。页面局部刷新
- Ajax可以做到一个网页启动多个请求,类似多线程。
Ajax应用程序执行的过程是怎样的
- 首先Web前端向服务器请求数据
- 对于Ajax来说,服务器可能会给Web前端响应三种数据:普通文本;XML字符串;JSON字符串
- Ajax会解析这些响应回来的数据,将解析之后的数据渲染到div图层中,这个div就更新了,这样页面就完成了局部刷新。
那么学习Ajax之前要学习哪些内容呢,首先是JavaScript,我还不是很熟悉,再见,先滚去学JavaScript了。
3 readyState状态值得理解
XMLHttpRequest对象的readyState属性对应的状态值:
- 0:请求未初始化
- 1:服务器连接已建立
- 2:请求已收到
- 3:正在处理请求
- 4:请求已完成且响应已就绪
当XMLHttpRequest对象的readyState属性的值变成4的时候,表示这个Ajax请求响应已经全部完成
4 第一个Ajax请求详解
4.1 发送Ajax请求步骤
发送Ajax请求主要分为四步:
第一步:创建Ajax核心对象XMLHttpRequest,直接new就好
第二步:注册回调函数
- 使用对象XMLHttpRequest调用onreadystatechange事件。得到一个回调函数,这个函数在XMLHttpRequest对象的readyState状态值发生改变的时候被调用。
- 当XMLHttpRequest对象的readyState的状态是4的时候,表示响应结束了
- 响应结束后一般会有一个HTTP的状态码
- 常见的状态码包括:200表示成功了;404表示资源找不到;500表示服务器内部错误
- 然后我们获取HTTP状态码,使用XMLHttpRequest对象的status方法得到
- 得到状态码就可以根据状态码做选择,若是200则输出信息,通过XMLHttpRequest对象的responseText属性获取响应信息
- 可以写一个div,然后将响应信息放到div图层中
第三步:开启通道(open只是浏览器和服务器建立连接,通道打开,并不会发送请求)
- 其中open的参数的含义:
- method:请求的方式——GET、POST、或者其它;
- url:请求的路径;async:只能是true或者false,true表示ajax请求是一个异步请求,false则是同步请求。大部分是true;
- user:用户名;pwd:
- 密码,用户名和密码是进行身份验证的,说明想访问这个服务器上的资源可能需要提供一些口令才能访问,需不需要用户名和密码,服务器说了算。
第四步:发送请求,使用对象XMLHttpRequest的send方法
代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script type="text/javascript">
window.onload = function (){
document.getElementById("helloBtn").onclick = function (){
//发送Ajax get请求
//1.创建Ajax核心对象XMLHttpRequest
var xhr = new XMLHttpRequest();
//2.注册回调函数
//这是一个回调函数,这个函数在XMLHttpRequest对象的readyState状态值发生改变的时候被调用
xhr.onreadystatechange = function (){
//这里的回调函数会被调用多次
//console.log(xhr.readyState)
//当XMLHttpRequest对象的readyState的状态是4的时候,表示响应结束了
if (this.readyState == 4){
//响应结束
//alert("响应结束了")
//得到状态码
//alert(this.status)
//所以我们可以根据得到的状态码判断该做什么
if (this.status == 404){
alert("对不起,您访问的资源不存在,请检查请求路径")
}else if (this.status == 500){
alert("对不起,服务器内部发生严重错误,请联系管理员")
}else if (this.status == 200){
//响应成功
//alert("响应成功")
//通过XMLHttpRequest对象的responseText属性来获取响应信息
//alert(this.responseText)
//响应到div中
document.getElementById("mydiv").innerHTML = this.responseText
}
}
}
//3.开启通道(open只是浏览器和服务器建立连接,通道打开,并不会发送请求)
xhr.open("GET","/ajax/ajaxrequest",true)
//4.发送请求
xhr.send()
}
}
</script>
<input type="button" value="hello ajax" id="helloBtn">
<div id="mydiv"></div>
</body>
</html>
@WebServlet("/ajaxrequest")
public class AjaxServlet01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out = response.getWriter();
out.write("hello ajax");
}
}
4.2 使用ajax发送get请求提交数据给服务器
可以直接在请求路径后面加上?然后拼接请求内容如下:
var username = document.getElementById("username").value
var password = document.getElementById("password").value
xhr.open("GET","/ajax/ajaxrequest2?username="+username+"&password="+password,true)
在重写ajax请求的代码时,出现一个错误,把onclick写成了click,焯!!
ajax get请求在低版本的ie浏览器上会出现缓存问题,就是访问同一个资源也就是url是同一个就会直接去找缓存而不是找服务器,这样当然速度会快,但是服务器更新了它依然找缓存,这就不好了,但是目前主流浏览器不存在这种问题了。。需要注意的是:post请求不会有缓存问题。
4.3 POST请求模拟表单提交数据
怎么使用AJax提交POST请求呢,肯定不能放在url后面进行请求,那是get请求了。可以放在send方法里面,要注意格式(name=value&name=value),其实就和get请求一样,不过是放在send函数中而已。但是这样还不够,我们还要send之前open之后执行setRequestHeader方法,它用来设置请求头的内容类型,用来模拟Ajax提交form表单,具体如下:
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded")
var username = document.getElementById("username").value
var password = document.getElementById("password").value
xhr.send("username="+username+"&password="+password)
5 验证用户名是否可用
实现一个小案例:使用Ajax post请求实现用户注册的时候,用户名是否可用,实现步骤如下:
- 在前端,用户输出用户名之后失去焦点事件blur发生,然后发送post请求,提交用户名
- 在后端,接收用户名,连接数据库,根据用户名去表中搜索
- 如果用户名存在,响应消息:对不起用户名已存在;如果用户名不存在响应消息:用户名可以使用
代码如下:
前端代码朴实无华,和上面差不多,主要展示后端代码:
package com.itzw.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.*;
@WebServlet("/ajaxrequest4")
public class AjaxServlet04 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String username = request.getParameter("username");
//out.print("username:"+username);
//连接数据库
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
//打布尔标记
boolean ok = false;
try {
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接
String url = "jdbc:mysql://127.0.0.1:3306/db1";
String user = "root";
String password = "123456";
conn = DriverManager.getConnection(url, user, password);
//获取预编译的数据库操作对象
String sql = "select username from t_user where username = ?";
ps = conn.prepareStatement(sql);
ps.setString(1,username);
//执行SQL语句
rs = ps.executeQuery();
//处理结果集
if (rs.next()){
//有结果说明用户名重复
ok = true;
}
} catch (Exception e) {
e.printStackTrace();
}finally {
//释放资源
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();
}
}
}
//判断前端该输出什么内容
if (ok){
//用户名重复
out.print("<font color='red'>用户名重复,请重新输入</font>");
}else {
//用户名可以使用
out.print("<font color='green'>用户名可以使用</font>");
}
}
}
6 基于JSON的数据交换
我们发现目前存在的缺点:当我们想将数据传到前端,需要在后端进行java代码和HTML代码的拼接,这显然是非常愚蠢的,我们能不能直接将数据返回,让web前端能够拿到数据就行。当然可以,返回数据可以采用JSON的格式,也可以是XML格式,重点在JSON。
6.1 什么是JSON
这个在JavaScript中学过,这里简单回顾一下
<script type="text/javascript">
//这样就可以创建一个JSON对象
//JSON对象中的属性可以存任何类型,包括数组甚至另一个JSON对象,和java一样可以套娃
var user = {
"name":"王德发",
"age":18,
"hobby":["抽烟","喝酒","烫头"]
}
//这样就可以获取JSON对象中的数据
alert(user.name)
alert(user.hobby[0])
</script>
6.2 在前端中如何将JSON字符串转为JSON对象
有两种方式
第一种:使用eval函数
第二种:调用JavaScript语言中的内置对象JSON的一个方法parse即可。
第一种JavaScript中讲到过,第二种比较简单,下面演示一下第二种:
//这是从java中获取到的JSON格式的字符串数据
var fromJavaData = "{\"username\":\"张麻子\",\"password\":\"123456\"}";
//这样就可以将字符串转为JSON对象
var jsonObj = JSON.parse(fromJavaData)
6.3 前后端进行JSON格式的字符串进行数据的交换
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script type="text/javascript">
window.onload = function () {
document.getElementById("displayStu").onclick = function (){
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function (){
if (this.readyState == 4){
if (this.status == 200){
//得到学生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.sno+"</td>"
html+="<td>"+stu.name+"</td>"
html+="<td>"+stu.addr+"</td>"
html+="</tr>"
}
//把拼接的结果放到tbody中
document.getElementById("stubody").innerHTML = html
}else {
//失败
alert(this.status)
}
}
}
xhr.open("GET","/ajax/ajaxrequest5",true)
xhr.send()
}
}
</script>
<input type="button" id="displayStu" value="展示学员列表">
<table border="1px" width="50%">
<tr>
<th>序号</th>
<th>学号</th>
<th>姓名</th>
<th>住址</th>
</tr>
<tbody id="stubody">
</tbody>
</table>
</body>
</html>
后端模拟从数据库得到数据
PrintWriter out = response.getWriter();
//模拟从数据库获取到的数据
String stuList = "[{\"sno\":\"110\",\"name\":\"王德发\",\"addr\":\"南京市\"},{\"sno\":\"120\",\"name\":\"张麻子\",\"addr\":\"北京市\"}]";
out.print(stuList);
6.4 连接数据库得到JSON格式字符串数据
我们可以连接数据库得到数据然后一点点将得到的数据拼成JSON格式的字符串,显然这个很麻烦,还好有个工具可以使用,这个工具为:fastjson-1.2.2,它是一个jar包,下面演示:
List<Student> stuList = new ArrayList<>();
while (rs.next()){
String sno = rs.getString("sno");
String name = rs.getString("name");
String addr = rs.getString("addr");
Student s = new Student(sno,name,addr);
stuList.add(s);
}
//将list集合转为JSON字符串
jsonStr = JSON.toJSONString(stuList);
这个jar包有个JSON类,用它调用toJSONString方法即可,需要注意的是,若想使用这个方法,需要先创建一个类,然后将数据封装到这个类里面然后再把它放在toJSONString里转换。演示:
7 基于XML数据格式交换数据
使用xml格式交换数据使用较少,这里演示一下即可
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script type="text/javascript">
window.onload = function (){
document.getElementById("displayStu").onclick = function (){
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function (){
if (this.readyState == 4){
if (this.status == 200){
//使用XMLHttpRequest对象的responseXML属性接收,可以自动封装成document对象(文档对象)
var xmlDoc = this.responseXML
//console.log(xmlDoc)
//获取所有<student>元素,返回多个对象,应该是个数组
var students = xmlDoc.getElementsByTagName("student")
//console.log(students[0])
var html = ""
for (var i = 0; i < students.length; i++) {
var student = students[i]
//获取student元素下的所有子元素
html += "<tr>"
html += "<td>"+(i+1)+"</td>"
var namOrAge = student.childNodes
for (var j = 0; j < namOrAge.length; j++) {
var node = namOrAge[j]
if (node.nodeName == "name"){
//console.log(node.textContent)
html += "<td>"+node.textContent+"</td>"
}
if (node.nodeName == "age"){
//console.log(node.textContent)
html += "<td>"+node.textContent+"</td>"
}
}
html += "<tr>"
}
document.getElementById("stuInfo").innerHTML = html
}else {
alert(this.status)
}
}
}
xhr.open("GET","/ajax/ajaxrequest6",true)
xhr.send()
}
}
</script>
<input type="button" value="展示学生信息" id="displayStu">
<table border="1px" width="50%">
<tr>
<td>序号</td>
<td>姓名</td>
<td>年龄</td>
</tr>
<tbody id="stuInfo">
</tbody>
</table>
</body>
</html>
后端提交的数据:
//response.setContentType("text/xml");
PrintWriter out = response.getWriter();
StringBuilder stuXML = new StringBuilder();
stuXML.append("<students>");
stuXML.append(" <student>");
stuXML.append(" <name>马邦德</name>");
stuXML.append(" <age>43</age>");
stuXML.append(" </student>");
stuXML.append(" <student>");
stuXML.append(" <name>张麻子</name>");
stuXML.append(" <age>44</age>");
stuXML.append(" </student>");
stuXML.append("</students>");
out.print(stuXML);
8 关于乱码问题
对于tomcat10来说不需要考虑乱码问题,都给我用10,nnd
对于tomcat9来说:
- 响应中文时会出现乱码,解决:response.setContentType("text/html;charset=UTF-8");
- 发送ajax post请求的时候,发送给服务器的数据,服务器接收之后乱码解决:request.setCharacterEncoding("UTF-8");
9 Ajax的异步与同步
大部分情况下都是使用异步,但有时我们需要使用同步,比如在我们注册时:需要输入很多信息,在这些信息验证(验证用户名是否符合要求之类的)前不能进行注册,所以这时使用异步就会出现问题,同步等待前面信息验证完才能进行注册
到目前为止Ajax的基本语法就结束了