9、AJAX
AJAX:Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)
-
在 2005 年,Google 通过 Google Suggest 使 AJAX 变得流行起来。
-
Google Suggest 使用 AJAX 创造出动态性极强的 web 界面:当您在谷歌的搜索框输入关键字时,JavaScript 会把这些字符发送到服务器,然后服务器会返回一个搜索建议的列表。
9.1、简介
9.1.1、什么是AJAX
- AJAX 是一种用于创建快速动态网页的技术。
-
AJAX 通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。**
- 即可以在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容;
- 传统的网页(不使用 AJAX)如果要更新内容,必须重新加载整个网页。
-
AJAX 不是新的编程语言,而是一种基于现有 Internet 标准的新方法。
- XMLHttpRequest 对象:异步的与服务器交换数据;
- JavaScript/DOM:信息显示/交互;
- CSS:给数据定义样式;
- JSON:作为转换数据的格式;
- AJAX 与浏览器和平台无关。
9.1.2、工作原理
9.2、iframe
使用前端的 iframe 标签来仿造 AJAX:页面局部刷新的效果。
HTML
- 创建 iframe 和输入框;
- 点击提交按钮,触发事件:获取输入框的值并赋值给 iframe 的 URL。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>iframe局部刷新页面</title>
<script type="text/javascript">
function go() {
let url = document.getElementById("url").value;
document.getElementById("myIframe").src = url;
}
</script>
</head>
<body>
<div>
<p>请输入地址:</p>
<input id="url" type="text">
<input type="button" value="提交" onclick="go()">
</div>
<div>
<iframe id="myIframe" width="700px" height="500px"></iframe>
</div>
</body>
</html>
9.3、XMLHttpRequest
- AJAX 的核心是 XMLHttpRequest 对象(XHR);
- XHR 用于在后台与服务器交换数据:向服务器发送请求、解析服务器响应;
- 原生 JS 实现 AJAX 比较麻烦,通常使用 jQuery 实现 AJAX。
9.4、jQuery实现AJAX
jQuery 提供多个与 AJAX 有关的方法。
9.4.1、jQuery.ajax
jQuery 可以简写成 $
,使用$.ajax(...)
函数
部分参数
参数 | 类型 | 描述 |
---|---|---|
async | Boolean | 是否异步请求,默认 true |
beforeSend | Function | 发送请求前执行的函数(全局) |
complete | Function | 请求完成后回调函数(成功或失败均调用) |
contentType | String | 发送信息至服务器时的内容编码类型, 默认 application/x-www-form-urlencoded; charset=UTF-8
|
data | String | 发送到服务器的数据。 会自动转换为请求字符串格式 |
dataType | String | 指定服务器端返回的数据类型 xml、html、script、json、jsonp、test |
error | Function | 请求失败的回调函数(全局) |
success | Function | 请求成功的回调函数(全局) |
timeout | Number | 设置请求超时时间(毫秒) |
type | String | 请求方式,GET(默认) 或 POST |
url | String | 请求地址 |
通常来说,url 、data 和回调函数是必要的。
9.4.2、环境搭建
搭建环境,测试 jQuery 实现 AJAX。
配置
需要 web.xml 和 springmvc 配置。
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>characterEncoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
applicationContext.xml
注:
- 过滤静态资源,否则 js 文件无法加载;
- 处理 JSON 乱码。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 添加注解支持 -->
<context:component-scan base-package="indi.jaywee.controller"/>
<!-- 过滤静态资源 -->
<mvc:default-servlet-handler/>
<!-- 添加注解驱动 -->
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"/>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!-- 视图解析器 -->
<bean id="internalResourceViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
JQuery库
要使用 jQuery 库,可以使用在线 CDN,也可以下载 JS 文件后导入项目。
引入在线 CDN
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
下载 JS 文件:jQuery 3.6.0开发版
-
导入静态资源:位置
web/statics/js/
-
引入本地 JS 文件
<script src="${pageContext.request.ContextPath}/statics/js/jquery-3.6.0.js"></script>
script 标签必须成对出现,不能自闭合!
9.4.3、测试
AjaxController
-
使用 @RestController 注解,Controller 内的方法返回字符串(详见8、JSON);
-
前端 AJAX 发送的数据(data)的键,必须与处理方法的参数名一致。
@RestController
public class AjaxController {
/**
* @param name 接收前端的data
* @return 要响应的数据
*/
@RequestMapping("/testName")
public String testName(String name) {
String msg = "admin";
if (!msg.equals(name)) {
msg = "user:" + name;
}
return msg;
}
}
test.jsp
- url:请求地址;
-
data:发送到服务器的数据
- 以键值对的格式;
- data 的键要与处理方法的参数名一致;
-
success:请求成功的回调函数
- 可以接收参数,参数是处理方法的返回值。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>AJAX测试</title>
<script src="${pageContext.request.contextPath}/statics/js/jquery-3.6.0.js"></script>
<script>
function test() {
$.ajax({
url: "${pageContext.request.contextPath}/testName",
data: {
"name": $("#username").val()
},
success: function (msg) {
console.log(msg)
}
})
}
</script>
</head>
<body>
<label>
检测用户:<input type="text" id="username" onblur="test()">
</label>
</body>
</html>
流程
- input 输入框:失去焦点,触发事件,调用 test() 函数;
- test() 函数:
- AJAX:发送请求到 Controller,携带 data 数据;
- Controller:接收请求,获取 data 参数, 处理逻辑并响应;
- success 回调函数:解析服务器响应,执行方法。
注意
- 检查项目结构是否有 lib 目录;
-
使用 @RestController 注解,Spring 自动将 Controller 内的方法返回字符串(详见8、JSON):
- 如果方法返回值类型是 String,直接返回字符串;
- 如果方法返回值类型是对象或集合,返回 JSON 字符串;
- 如果方法返回值是其它,根据一定规则返回字符串;
-
springmvc 配置文件
- 是否有过滤静态资源;
- 是否有处理 JSON 乱码;
- 一切正常,但是请求无法发送:刷新 Maven 并 clean。
9.5、应用
9.5.1、展示后台数据
以显示用户信息为例。
User
/**
* ID
*/
private int id;
/**
* 姓名
*/
private String name;
/**
* 性别
*/
private String gender;
UserController
如果 RestController 中方法返回的是集合或对象,Spring 自动将其转换为 JSON 字符串
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping("/listUsers")
public List<User> listUsers() {
// 模拟用户列表
List<User> userList = new ArrayList<>();
userList.add(new User(1, "Jaywee", "男"));
userList.add(new User(2, "小北", "女"));
userList.add(new User(3, "SecretMrJ", "男"));
userList.add(new User(4, "baby0", "女"));
return userList;
}
}
页面
- 入口函数
- 语法:
windows.load = function(){...}
或$(function () {...})
- JS 的优先级很高,会先运行 JS 函数再加载页面;
- 入口函数的作用:等待页面加载完毕后才执行;
- 必须将 JS 语句写在里面。否则 JS 函数会在页面加载之前执行,此时获取不到页面中的元素。
- 语法:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>展示用户</title>
<script src="${pageContext.request.contextPath}/statics/js/jquery-3.6.0.js"></script>
<script>
$(function () {
$("#btn").click(function () {
$.ajax({
url: "${pageContext.request.contextPath}/user/listUsers",
success: function (userList) {
let htmlContent = "";
for (let i = 0; i < userList.length; i++) {
htmlContent += "<tr>" +
"<td>" + userList[i].id + "</td>" +
"<td>" + userList[i].name + "</td>" +
"<td>" + userList[i].gender + "</td>" +
"</tr>"
}
$("#content").html(htmlContent)
}
})
})
})
</script>
</head>
<body>
<input type="button" id="btn" value="加载">
<table>
<thead>
<tr>
<td>ID</td>
<td>姓名</td>
<td>性别</td>
</tr>
</thead>
<tbody id="content">
</tbody>
</table>
</body>
</html>
流程
- btn 按钮绑定事件,等待触发;
-
btn 按钮:点击按钮,触发事件;
- 发送请求到 Controller;
- Controller:接收请求, 处理逻辑并响应;
-
success 回调函数:解析服务器响应,执行方法
- 获取服务器返回的数据;
- 循环拼接 htmlContent;
- 将 htmlContent 赋值给 tbody。
9.5.2、验证用户名
以注册时验证用户名是否可用为例。
UserController
@RestController
@RequestMapping("/user")
public class UserController {
/**
* @param username 用户名
* @return 用户名可用返回ture, 否则返回false
*/
@RequestMapping("/regist")
public boolean regist(String username) {
boolean flag = true;
// 模拟数据库查询的用户名列表
String[] nameList = new String[]{"admin", "jaywee", "小北"};
// 判断用户名是否已存在
for (String name : nameList) {
if (name.equals(username)) {
flag = false;
break;
}
}
return flag;
}
}
页面
注意:使用.toString()
将服务器返回的数据转换为字符串。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>注册</title>
<script src="${pageContext.request.contextPath}/statics/js/jquery-3.6.0.js"></script>
<script>
$(function () {
$("#username").blur(function () {
$.ajax({
url: "${pageContext.request.contextPath}/user/regist",
data: {
"username": $("#username").val()
},
success(flag) {
console.log(flag);
console.log(flag.type);
if (‘true‘ === flag.toString()) {
$("#verifyContent").html("用户名可用").css("color", "green");
} else {
$("#verifyContent").html("用户名已存在").css("color", "red");
}
}
})
})
})
</script>
</head>
<body>
<label>
用户名:<input type="text" id="username">
</label>
<span id="verifyContent"></span>
</body>
</html>
流程
- input 输入框绑定事件,等待触发;
-
input 输入框:失去焦点,触发事件;
- 发送请求到 Controller,携带 data 参数;
- Controller:接收请求, 处理逻辑并响应;
-
success 回调函数:解析服务器响应,执行方法
- 获取服务器返回的数据,判断是 true 还是 false;
- 添加提醒字样。