本篇Blog介绍另一个常用的技术Ajax。虽然Ajax可以脱离SpringMVC去使用,但是SpringMVC对AJax有更好的支持
AJAX概念概述
AJAX即Asynchronous Javascript And XML(异步JavaScript和XML),AJAX不是一种新的编程语言,而是一种用于创建更好更快以及交互性更强的 Web 应用程序的技术。它是一套综合了多项技术的浏览器端网页开发技术。这些技术包括Javascript、XHTML和CSS、DOM、XML和XMLHttpRequest。
通过在浏览器与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新
AJAX优缺点归纳
使用AJAX的最大优点,就是能在不更新整个页面的前提下维护数据。这使得Web应用程序更为迅捷地回应用户动作,并避免了在网络上发送那些没有改变的html代码信息。
- 减轻服务器负担,按需要获得数据。
- 无刷新更新页面,减少用户的实际和心理的等待时间。
- 更好的用户体验。
- 减轻宽带的负担。
- 主流浏览器支持。
当然缺点也比较明显:
- AJAX大量使用了Javascript和AJAX引擎,使用AJAX的程序必须测试针对各个浏览器的兼容性。
- AJAX更新页面内容的时候并没有刷新整个页面,因此,网页的后退功能是失效的。
- 对搜索引擎支持不好
索性AJAX提供了一些浏览器的兼容使用方式。
AJAX原理
AJAX的原理简单来说通过浏览器的javascript对象XmlHttpRequest(Ajax引擎)对象来向服务器发异步请求并接收服务器的响应数据,然后用javascript来操作DOM而更新页面。这其中最关键的一步就是从服务器获得请求数据。即用户的请求间接通过AJAX引擎发出而不是通过浏览器直接发出,同时Ajax引擎也接收服务器返回响应的数据,所以不会导致浏览器上的页面全部刷新,通俗的说,就是浏览器使用AJAX引擎做代理来处理请求和响应
浏览器创建ajax对象,AJAX对象向后端发送请求,后端接收请求响应数据给前端,AJAX对象接收响应数据通过dom操作更新视图,整个过程浏览器“不刷新”,真正的请求是由AJAX引擎发出。不是由浏览器窗口发出,所以浏览器窗口是不会刷新的, AJAX引擎同时也接收服务器返回的响应内容
AJAX发送请求方式
上述我们提到了AJAX引擎,AJAX引擎就是XMLHttpRequest对象,所有现代浏览器均支持 XMLHttpRequest 对象(IE5 和 IE6 使用 ActiveXObject)。它同时也是一个Javascript对象,常用方法与属性如下:
常用属性:
使用JavaScript语法发送请求
以下是使用JavaScript语法发送请求的get请求方式的标准步骤:
//1.创建ajax对象
var xhr = new XMLHttpRequest();
//2.配置请求方式和请求地址
xhr.open("get","xxx地址");
//如果要传入参数
xhr.open("get","xxx地址?参数名1=参数值1&参数名2=参数值2")
//如果要设置请求方式,true表示同步,false表示异步
xhr.open("get","xxx地址?参数名1=参数值1&参数名2=参数值2",true)
//3.发送请求
xhr.send();
//4.监听状态变化&接收响应数据
xhr.onreadystatechange = function(){
if(xhr.readyState===4 && xhr.status===200){
var data = xhr.reponseText;
}
}
这里需要注意两点,同步异步以及事件监听机制。
同步和异步的概念
- 同步:就是在发出一个功能调用时,在没有得到结果之前,不能够继续调用其他功能。
- 异步:异步的概念和同步相对。当一个异步过程调用发出后,调用者不能立刻得到结果,程序继续向下执行。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。
同步是阻塞模式,异步是非阻塞模式。发送请求的区别:
- 同步是指:发送方发出数据后,等接收方发回响应以后才发下一个数据包的通讯方式。
- 异步是指:发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式
AJAX中的异步请求是异步的真正的实现,是指用户页面(HTML)没有直接和服务器打交道而是通过Ajax引擎间接和服务器打交道的, 而用户页面和Ajax引擎打交道时并不会等待服务器返回的响应内容,页面中的Javascript代码继续执行,也可以继续发出新的Ajax请求
事件监听的概念
需要注意其中onreadystatechange是一个监听事件(监听ajax对象的状态(readyState)变化,整个过程中readyState状态值会不断发生改变),readyState: 一共有五个值(状态4需要记忆)
- 0 刚创建的ajax对象状态为0
- 1 调用了open方法之后
- 2 后端接收请求
- 3 后端处理数据,响应数据中,数据可能没有完全传输完
- 4 数据传输完成已就绪,放在responseText属性中。
status是状态码,标识请求结果,responseText用来存放后端响应的数据,是字符串格式。post的方式类似:
//1.创建ajax对象
var xhr = new XMLHttpRequest();
//2.配置请求方式和请求地址
xhr.open("post","xxx地址");
//如果要传入参数
xhr.open("post","xxx地址?参数名1=参数值1&参数名2=参数值2")
//如果要设置请求方式,true表示同步,false表示异步
xhr.open("post","xxx地址?参数名1=参数值1&参数名2=参数值2",true)
//3.设置请求头
xhr.setRequestHeader("Content-Type","application/x-www-form-encoded");
//4.发送
xhr.send();
//5.监听状态和接收数据
xhr.onreadystatechange = function(){
if(xhr.readyState===4 && xhr.status===200){
var data = xhr.responseText;
}
}
使用JQuery语法发送请求
上述示例是使用原生JS语法发送AJAX请求,下面这几种是JQuery语法的形式:
//1.get方式
$.get('xxx地址',{
"属性名1":"属性值1",
"属性名2":"属性值2"
},function(data){
//data存储就是后端响应的数据
console.log(data);
});
//2.post方式
$.post('xxx地址',{
"属性名1":"属性值1",
"属性名2":"属性值2"
},function(data){
//data存储就是后端响应的数据
console.log(data);
});
//3.万能模式
$.ajax({
url:'xxx地址',
type:"请求方式",
dataType:”json” , //告诉后端我们想要的数据格式
data:{
"属性名1":"属性值1",
"属性名2":"属性值2"
},
success:function(data){
//data存放的就是后端响应的数据
console.log(data);
}
})
我们一般更多的是使用JQuery的形式去实现
SpringMVC整合AJAX
我们一般使用AJAX作为表单的验证和用户信息的验证,这样提示信息就可以直接打到前端页面上。我们的目标是模拟一个用户验证,只用用户名和密码输入完全正确才允许登录。
1 新建一个项目
首先我们新建一个AJAX的SpringMVC项目
配置pom.xml
依赖,同时也引入jackson包
<!--https://mvnrepository.com/仓库获取的最新包 20210831-->
<dependencies>
<!-- jackson包引入-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.1</version>
</dependency>
<!--Spring MVC框架依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.9</version>
</dependency>
<!--JSP相关依赖-->
<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>
<!--servlet相关依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!--单元测试相关依赖-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
2 创建Model类
我们创建一个Model类,这个Model类就是要返回给前端的VO
package com.example.ajax.model;
import lombok.Data;
@Data
public class User {
private String username;
private String password;
}
3 编写AJAX控制器Controller
我们需要编写一个控制器,注意控制器可以使用注解@RestController来标明所有返回的数据都将被序列化为Json格式:
package com.example.ajax.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/user")
public class AjaxController {
@RequestMapping("/argcheck")
public String ArgCheck(String name,String pwd){
String msg = "";
//模拟数据库中存在数据
if (name!=null){
if ("admin".equals(name)){
msg = "OK";
}else {
msg = "用户名输入错误";
}
}
if (pwd!=null){
if ("111111".equals(pwd)){
msg = "OK";
}else {
msg = "密码输入有误";
}
}
return msg; //由于@RestController注解,将msg转成json格式返回
}
}
4 注册DispatcherServlet
接着是我们的传统艺能,注册SpringMVC过滤器来拦截请求
<?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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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>
<!--1.注册DispatcherServlet-->
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--通过初始化参数指定SpringMVC配置文件的位置,进行关联-->
<init-param>
<param-name>contextConfigLocation</param-name>
<!--关联一个springMVC的配置文件:【servlet-name】-servlet.xml-->
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!--启动级别-1,在Tomcat启动时就初始化Spring容器-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--/ 匹配所有的请求;(不包括.jsp)-->
<!--/* 匹配所有的请求;(包括.jsp)-->
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
5 编写springmvc-servlet.xml配置文件
编写springmvc-servlet.xml文件,并且在这里加一部分配置让返回的数据不会乱码。
<?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
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 -->
<context:component-scan base-package="com.example.ajax.controller"/>
<!-- 让Spring MVC不处理静态资源 -->
<mvc:default-servlet-handler />
<!--
支持mvc注解驱动
在spring中一般采用@RequestMapping注解来完成映射关系
要想使@RequestMapping注解生效
必须向上下文中注册DefaultAnnotationHandlerMapping
和一个AnnotationMethodHandlerAdapter实例
这两个实例分别在类级别和方法级别处理。
而annotation-driven配置帮助我们自动完成上述两个实例的注入。
-->
<mvc:annotation-driven />
<!--视图解析器-->
<!--通过视图解析器解析处理器返回的逻辑视图名并传递给DispatcherServlet-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
<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>
</beans>
6 编写前端JSP视图文件
接下来我们要编写前端的请求文件,格式如下:
<%--
Created by IntelliJ IDEA.
User: 13304
Date: 2021/9/12
Time: 15:02
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>ajax</title>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script>
function username(){
$.post({
url:"${pageContext.request.contextPath}/user/argcheck",
data:{'name':$("#name").val()},
success:function (data) {
if (data.toString()=='OK'){
$("#userInfo").css("color","green");
}else {
$("#userInfo").css("color","red");
}
$("#userInfo").html(data);
}
});
}
function password(){
$.post({
url:"${pageContext.request.contextPath}/user/argcheck",
data:{'pwd':$("#pwd").val()},
success:function (data) {
if (data.toString()=='OK'){
$("#pwdInfo").css("color","green");
}else {
$("#pwdInfo").css("color","red");
}
$("#pwdInfo").html(data);
}
});
}
</script>
</head>
<body>
<p>
用户名:<input type="text" id="name" onblur="username()"/>
<span id="userInfo"></span>
</p>
<p>
密码:<input type="text" id="pwd" onblur="password()"/>
<span id="pwdInfo"></span>
</p>
</body>
</html>
6 配置Tomcat服务器并测试
最后我们配置并启动Tomcat服务器来测试:
在浏览器中输入:http://localhost:8080/ajax/login.jsp
,返回结果为:
接下来当我们在框中输入内容可以看到ajax请求而页面并没有刷新,观察请求的url我们发现ajax请求了我们的控制器:
然后将结果返回给dom
总结一下
AJAX还是比较经典的,我理解它的常用案例就是通过局部刷新进行逻辑处理,整体页面的资源无需再被处理,也就是我们不需要提交表单给controller,然后controller再将结果打回去进行一个页面刷新操作,在带宽资源紧张的情况下这么使用还是挺方便的。所以AJAX只是一种模式,Struts框架和SpringMVC框架都可以使用,只不过因为SpringMVC可以使用@RestController注解轻易的实现JSON传输,Struts却不易实现,而对于AJAX而言,JSON 可通过 JavaScript 进行解析,更加适合于AJAX 进行传输,所以对于自动集成AJAX这一点,SpringMVC又更胜一筹。