本文为 SSM 框架系列之 SpringMVC 第五部分:AJAX的使用
其它内容的链接如下:
1. 传统 MVC
2. Hello SpringMVC
3. 配置解析
4. JSON的使用
5. AJAX 的使用
6. 拦截器
目录:
1 AJAX 简介
1.1 AJAX 定义
AJAX,即异步的 JavaScript 和 XML 技术( Asynchronous JavaScript and XML),是一种无需重新加载整个网页的情况下,更新部分网页的技术。
1.2 为什么需要 AJAX
通过 AJAX 可以创造出动态性极强的 web 界面,比如在百度的搜索框内输入关键字时,JavaScript 会把这些字符发送到服务器,然后服务器会返回一个搜索建议的列表。
如果利用传统的同步的网页技术来实现这种效果的话,则必须每输入一个字符,便提交一次表单,并加载整个页面,这种方式对于用户的体验和开发者的效率都是不佳的。所以,AJAX 应运而生。
该 Visio 图像的下载链接为:传送门
1.3 怎么实现 AJAX
编写常规的 AJAX 代码并不容易,因为不同的浏览器对 AJAX 的实现并不相同。不过,jQuery 团队为我们解决了这个难题,通过 jQuery,我们只需要一行简单的代码,就可以实现 AJAX 功能。
通过 jQuery AJAX 方法,您能够使用 HTTP Get 和 HTTP Post 从远程服务器上请求文本、HTML、XML 或 JSON – 同时您能够把这些外部数据直接载入网页的被选元素中。
jQuery.ajax(...)
部分参数:
url:(重要)请求地址
type:请求方式,GET、POST(1.9.0之后用method)
headers:请求头
data:(重要)要发送的数据
contentType:即将发送信息至服务器的内容编码类型(默认: "application/x-www-form-urlencoded; charset=UTF-8")
async:是否异步
timeout:设置请求超时时间(毫秒)
beforeSend:发送请求前执行的函数(全局)
complete:完成之后执行的回调函数(全局)
success:(重要)成功之后执行的回调函数(全局)
error:(重要)失败之后执行的回调函数(全局)
accepts:通过请求头发送给服务器,告诉服务器当前客户端可接受的数据类型
dataType:将服务器端返回的数据转换成指定类型
"xml": 将服务器端返回的内容转换成xml格式
"text": 将服务器端返回的内容转换成普通文本格式
"html": 将服务器端返回的内容转换成普通文本格式,在插入DOM中时,如果包含JavaScript标签,则会尝试去执行。
"script": 尝试将返回值当作JavaScript去执行,然后再将服务器端返回的内容转换成普通文本格式
"json": 将服务器端返回的内容转换成相应的JavaScript对象
"jsonp": JSONP 格式使用 JSONP 形式调用函数时,如 "myurl?callback=?" jQuery 将自动替换 ? 为正确的函数名,以执行回调函数
2 前景知识
2.1 jQuery
2.1.1 jQuery 的导入
在 HTML 或者 JSP 中引入 jQuery 有两种方式,一种是将对应的 .js 包下载到本地导入,另一种是使用 cdn 在线导入。
1)本地安装
1 JQuery 官网
2 选择版本号
3 点击后,浏览器会显示 jQuery 的源码,这个时候,通过 Ctrl + S 快捷键保存到本地
4 将下载好的 Js 文件拖到 IDEA 对应的文件夹内
5 在对应的 标签内导入即可
<script src="${pageContext.request.contextPath}/static/js/jquery-3.6.0.js"></script>
2)CDN 在线安装
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
so easy!
2.1.2 jQuery 语法
基础语法是:$(selector).action()
- 美元符号定义 jQuery
- 选择符(selector)“查询”和“查找” HTML 元素
- jQuery 的 action() 执行对元素的操作
2.1.3 文档就绪函数
所有 jQuery 函数位于一个 document ready 函数中:
$(document).ready(function(){
--- jQuery functions go here ----
});
这是为了防止文档在完全加载(就绪)之前运行 jQuery 代码。
2.1.4 jQuery 事件函数
jQuery 是为事件处理特别设计的。事件处理程序指的是当 HTML 中发生某些事件时所调用的方法。
<%@ page contentType="text/html; charset=UTF-8" isELIgnored="false" language="java" %>
<html>
<head>
<title>jQuery 测试</title>
<script src="${pageContext.request.contextPath}/static/js/jquery-3.6.0.js"></script>
<script type="text/javascript">
// jQuery 函数需要在一个 document ready 函数中,这也算是一个固定写法
$(document).ready(function(){
// 当按钮的点击事件触发时,会调用 .hide() 函数
$("p").click(function(){
$(this).hide();
});
});
</script>
</head>
<body>
<p>If you click on me, I will disappear.</p>
</body>
</html>
2.1.5 jQuery 选择器
语法 | 描述 |
---|---|
$(this).hide() | 隐藏当前 HTML 元素 |
$(“p”).hide() | 隐藏所有 元素 |
$(“p.intro”).hide() | 隐藏所有 class=“intro” 的 元素 |
$(".intro").hide() | 隐藏所有 class=“intro” 的元素 |
$("#intro").hide() | 隐藏 id=“intro” 的元素 |
参考文献:传送门
2.2 利用浏览器查看 AJAX
2.2.1 浏览器 F12 开发者工具详解
开发者最常用的四个功能模块:
- 元素(ELements):查看网页页面的所有元素,修改元素的代码与属性。
- 控制台(Console):查看 JS 对象的及其属性;执行 JS 语句;查看控制台日志。
- 源代码(Sources):该页面用于查看页面的 HTML 文件源代码、JavaScript 源代码、CSS 源代码,此外最重要的是可以调试 JavaScript 源代码,给 JS 代码添加断点等。
- 网络(Network):网络页面主要用于查看header等与网络连接相关的信息。
具体每个模块的含义参考这篇博客,写得十分详细:传送门 https://zhuanlan.zhihu.com/p/231865779
2.2.2 查看 AJAX
在浏览器中点击 F12 进入开发者调试,选择 Network,当操作 Ajax 时,Network 会返回如下类型的数据。即为 AJAX。
3 利用 AJAX 返回普通字符串数据
目标:利用 AJAX 实现当鼠标从文本框返回时,浏览器出现设定好的弹窗内容。
1 前端的代码为:web/test.jsp
<%@ page contentType="text/html; charset=UTF-8" isELIgnored="false" language="java" %>
<html>
<head>
<title>利用 AJAX 返回普通字符串数据</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
<script>
function a() {
// jQuery 固定写法,其中如果 $ 不报错,就说明 jquery 导入成功了,因为 Jquery 的简写就是 $
$(document).ready(function(){
$.post({
// 配置了 Tomcat 服务器之后会自动补全(没想到 script 中没有自动补全)
// input 标签中的值怎么取,可以使用 # 选择器
url:"${pageContext.request.contextPath}/ajax/a1",
data:{"name":$("#username").val()},
success:function (data) {
alert(data);
}
})
});
}
</script>
</head>
<body>
<%-- 失去焦点时,发起一个请求(携带)信息到后端 --%>
<%-- 其中 id 是唯一标识符,id 属性是用来唯一定位的,而不是 name 属性 --%>
用户名:<input type="text" id="username" onblur="a()">
</body>
</html>
2 后端控制器代码为:sharm.controller.AjaxController
@Controller
@RequestMapping("/ajax")
public class AjaxController {
@RequestMapping("/a1")
// 当返回类型为 String 时, return String 中的 String 是返回地址,方法中的数据是放在类似于 Model 中的 map 里
public void test1(String name, HttpServletResponse response) throws IOException {
// 选择在前端的 Console 窗口输出
if("sharm".equals(name)){
response.getWriter().println("your name is right.");
}else{
response.getWriter().println("your name is false.");
}
}
}
3 功能演示
4 利用 AJAX 返回 JSON 数据,并在前端显示
再次介绍完整的步骤:
1 新建一个 Module,配置 Web 框架;
① 右键 module,add Web Application Frameworks Support;
②
③:
2 配置 pom.xml 文件;
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springmvc</artifactId>
<groupId>sharm</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ajax</artifactId>
<!-- 经过实践证明,这段代码确实是必须要写的 -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<java.version>11</java.version>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<!-- 依赖 -->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
<!-- 静态资源导出 -->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
3 配置 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">
<!-- 配置 DispatchServlet:这是 SpringMVC 的核心,请求分发器,前端控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- DispatchServlet 要绑定 Spring 的配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:ajax.xml</param-value>
</init-param>
<!-- 设置启动级别为 1 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!--/ 匹配所有的请求;(不包括.jsp)-->
<!--/* 匹配所有的请求;(包括.jsp)-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- Spring 自带的过滤器,用来解决 JSON 乱码问题 -->
<filter>
<filter-name>encoding</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>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
4 配置 spring 配置文件;
<?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">
<!-- 默认:自动扫描包,让指定包下的注解生效,由IOC容器统一管理 -->
<context:component-scan base-package="sharm.controller"/>
<!-- 默认:让 Spring MVC 不处理 html、css 等静态资源,开发 web 项目时,一般都需要过滤静态资源 -->
<mvc:default-servlet-handler />
<!-- 默认:支持mvc注解驱动,这样就不需要写处理器映射器和处理器适配器,
而 annotation-driven 配置帮助我们自动完成上述两个实例的注入。-->
<mvc:annotation-driven />
<!-- 前后端分离后,通过使用 JSON 来传输数据,就不需要视图解析器了 -->
<!-- <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"-->
<!-- id="internalResourceViewResolver">-->
<!-- <!– 前缀 –>-->
<!-- <property name="prefix" value="/WEB-INF/jsp/" />-->
<!-- <!– 后缀 –>-->
<!-- <property name="suffix" value=".jsp" />-->
<!-- </bean>-->
</beans>
5 书写 User 实体类(也就是需要返回的 JSON 对象);
package sharm.pojo;
public class User {
private String name;
private int age;
private String gender;
// 省略无参和有参构造方法
// 省略各个属性的 getter 和 setter 方法
// 省略 toString 方法的重写
}
6 书写 Controller 控制器;
@Controller
@RequestMapping("/ajax")
public class AjaxController {
@RequestMapping(value = "/a2", produces = "application/json;charset=utf-8")
@ResponseBody
public String test2() throws JsonProcessingException {
// 一:创建一个 jackson 的对象映射器,用来解析数据
ObjectMapper objectMapper = new ObjectMapper();
// 二:创建一个用于转换成 JSON 文件的 Java 集合
User sharm = new User("Sharm", 24, "男");
User jack = new User("jack", 24, "男");
User luma = new User("luma", 24, "男");
User loro = new User("lora", 24, "男");
List<User> list = new ArrayList<User>();
list.add(sharm);
list.add(jack);
list.add(luma);
list.add(loro);
// 三:将对象解析成 JSON 格式
String listStr = objectMapper.writeValueAsString(list);
// 四:由于 @ResponseBody 注解,这里会直接返回字符串,而无需走视图解析器
// 如果是前后端分离的情况,那肯定不走视图解析器了,只要返回 json 即可
return listStr;
}
}
6.1 测试:直接通过 url 访问 /ajax/a2 页面时
可以看到返回的是一个 JSON 数据。
7 编写前端页面:web/test2.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>利用 AJAX 返回 JSON 数据,并在前端显示</title>
</head>
<body>
<table width="80%" align="center">
<tr>
<td>姓名</td>
<td>年龄</td>
<td>性别</td>
</tr>
<tbody id="content">
</tbody>
</table>
<input type="button" id="btn" value="获取数据"/>
<%-- 就离谱,把 script 标签放在 head 标签中就没用,而放在 <input> 下面就可以--%>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
<script type="text/javascript">
$("#btn").click(function () {
$(document).ready(function(){
$.post({
// $.post(url, param[可以省略], success[通常是一个函数])
url:"${pageContext.request.contextPath}/ajax/a2",
success:function (data) {
console.log(data);
var html="";
for (var i = 0; i <data.length ; i++) {
// 这里的属性是点不出来的,需要主动和传回来的 JSON 参数相同
html+= "<tr>" +
"<td>" + data[i].name + "</td>" +
"<td>" + data[i].age + "</td>" +
"<td>" + data[i].gender + "</td>" +
"</tr>"
}
$("#content").html(html);
}
})
});
})
</script>
</body>
</html>
8 显示效果
前端页面点击 “获取数据按钮” 时,数据会直接通过 ajax 返回显示,且 url 无需刷新。
5 利用 AJAX 实现登录提示
功能:要求在登录时,实现利用 AJAX 实时判断登录名是否存在,已经登录名和密码是否对应。
1 前端代码实现:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>ajax</title>
</head>
<body>
<p>
用户名:<input type="text" id="name" onblur="a1()"/>
<span id="userInfo"></span>
</p>
<p>
密码:<input type="text" id="pwd" onblur="a2()"/>
<span id="pwdInfo"></span>
</p>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
<script type="text/javascript">
function a1() {
// 如果 jQuery 显示 $ 无效,可以在 IDEA 中的 Setting 的 JavaScript 中,jQuery 是否导入
$(document).ready(function () {
$.post({
url: "${pageContext.request.contextPath}/ajax/a3",
data: {'name': $("#name").val()},
success: function (data) {
if (data.toString() === "请继续输入密码") {
// 给 span 标签增加 CSS 样式
$("#userInfo").css("color", "green");
} else {
$("#userInfo").css("color", "red");
}
// 给 span 标签增加内容
$("#userInfo").html(data);
}
});
});
}
function a2() {
$(document).ready(function () {
$.post({
url: "${pageContext.request.contextPath}/ajax/a4",
data: {'pwd': $("#pwd").val()},
success: function (data) {
if (data.toString() === "密码正确,等待登录……") {
$("#pwdInfo").css("color", "green");
} else {
$("#pwdInfo").css("color", "red");
}
$("#pwdInfo").html(data);
}
});
});
}
</script>
</body>
</html>
2 服务器端代码实现
-
如果使用 @RestController 注解,可以直接返回 JSON 的字符串,但必须在 Spring 的配置文件中加入 JSON 乱码问题的解决办法。
-
而如果使用 @Controller + @ResponseBody 注解,则必须将普通字符串先使用 objectMapper 对象转变成 JSON。
2.1 使用 @RestController 注解
@RestController
@RequestMapping("/ajax")
public class TempController {
@RequestMapping("/a3")
public String ajax3(String name, String pwd) {
String returnMsg = "";
//模拟数据库中存在数据
String dbName = "sharm";
String dbPwg = "123456";
if(dbName.equals(name)){
returnMsg = "请继续输入密码";
}else{
returnMsg = "该用户名不存在";
}
if(pwd != null){
if(dbPwg.equals(pwd)){
returnMsg = "密码正确,等待登录……";
}else{
returnMsg = "密码输入有误,请重新输入";
}
}
return returnMsg;
}
}
2.2 使用 @Controller + @ResponseBody 注解
@Controller
@RequestMapping("/ajax")
public class AjaxController {
@RequestMapping(value = "/a3", produces = "application/json;charset=utf-8")
@ResponseBody
public String ajax3(String name, String pwd) throws JsonProcessingException {
String returnMsg = "";
//模拟数据库中存在数据
String dbName = "sharm";
String dbPwg = "123456";
if(dbName.equals(name)){
returnMsg = "请继续输入密码";
}else{
returnMsg = "该用户名不存在";
}
if(pwd != null){
if(dbPwg.equals(pwd)){
returnMsg = "密码正确,等待登录……";
}else{
returnMsg = "密码输入有误,请重新输入";
}
}
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(returnMsg);
}
}
3 结果展示