前言
拦截器是Spring MVC框架提供的一种强大的机制,用于在请求到达控制器之前或之后进行预处理和后处理。它可以拦截并处理请求,对请求进行必要的修改或验证,以及在请求返回给客户端之前进行额外的操作。拦截器可以帮助我们实现各种需求,如身份验证、日志记录、性能监控等。
在本篇博文中,我们将深入研究拦截器的概念、工作原理和使用方法。我们将学习如何创建和配置拦截器,以及如何将其应用于Spring MVC应用程序中。最后,我们还将探讨一些实际应用场景,并给出一些拦截器的最佳实践。
一、前期准备
1、新建项目,结构如下
2、导入依赖
<dependencies>
<!-- springmvc 依赖,会将spring的核心包一并添加进来 -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.23</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.5</version>
</dependency>
</dependencies>
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">
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
4、新建 User 类
@Data
public class User {
private String userName;
private String password;
}
5、新建一个 LoginService 接口
public interface LoginService {
/**
* 登录认证
* @param userName
* @param password
* @return
*/
User auth(String userName,String password);
}
6、新建一个 LoginServiceImpl 实现类
@Service
public class LoginServiceImpl implements LoginService {
@Override
public User auth(String userName, String password) {
if ("qiu".equals(userName) && "123".equals(password)){
User user = new User();
user.setUserName(userName);
user.setPassword(password);
return user;
}
throw new RuntimeException("账号密码错误");
}
}
7、新建一个 index.html 页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>home page</h1>
</body>
</html>
二、实现拦截器
1、编写一个 controller
@RestController
@RequiredArgsConstructor
public class UserController {
private final LoginService service;
@PostMapping("/auth")
public ResultVO login(String userName, String password, HttpSession session){
User auth = service.auth(userName, password);
session.setAttribute("user",auth);
return new ResultVO();
}
}
2、编写登录页面 login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户登录</title>
<script src="js/JQuery文件.txt.js"></script>
</head>
<body>
<h1>用户登录</h1>
<form id="f1">
账号:<input type="text" name="userName"/><br>
密码:<input type="password" name="password"/><br>
<input type="button" value="登录"/>
</form>
<script>
$(function(){
$(':button').on('click', function(){
let formData = $('#f1').serialize();
$.ajax({
url: '../auth',
type: 'post',
data: formData,
success: function (result) {
if(result.code === 200) {
location.href = 'index.html';
}
},
error:function (error) {
alert(error)
}
});
});
})
</script>
</body>
</html>
3、编写拦截器
/**
* @Date 2023-10-27
* @Author qiu
* 认证拦截器
* 拦截所有的请求,如果未登录则返回 401(未登录,未认证) 状态码
*/
@Slf4j
public class AuthInterceptor implements HandlerInterceptor {
/**
* 在调用 controller 的请求方法之前执行
* 如果此方法返回 false ,则请求不会继续往下执行
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("执行 preHandle 方法");
HttpSession session = request.getSession();
// 如果 session 为 null 表示用户未登录
if ( session.getAttribute("user") == null ){
ResultVO resultVO = new ResultVO();
// 设置 401 状态码
resultVO.setCode(HttpStatus.UNAUTHORIZED.value());
resultVO.setMessage("未登录,请登录!");
response.setContentType("application/json;charset=utf-8");
String json = new ObjectMapper().writeValueAsString(resultVO);
response.getWriter().println(json);
return false;
}
return true;
}
/**
* 在调用 controller 方法之后,返回之前执行
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("执行 postHandle 方法");
}
/**
* 调用 controller 方法并返回之后执行
* (注意:只有在 preHandle 返回 TRUE ,才会执行)
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("执行 afterCompletion 方法");
}
}
4、配置 dispatcher-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
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 扫描 -->
<context:component-scan base-package="edu.nf.ch10"/>
<!-- mvc 注解驱动器 -->
<mvc:annotation-driven/>
<!-- 静态资源处理器 -->
<mvc:default-servlet-handler/>
<!-- 内部资源视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- 配置拦截器 -->
<mvc:interceptors>
<!-- 装配具体的拦截器 -->
<mvc:interceptor>
<!-- 设置哪些请求会经过这个拦截器 -->
<mvc:mapping path="/**"/>
<!-- 排除哪些请求不经过这个拦截器 -->
<mvc:exclude-mapping path="/static/login.html"/>
<mvc:exclude-mapping path="/auth"/>
<mvc:exclude-mapping path="/static/js/**"/>
<!-- 装配具体的拦截器 -->
<bean class="edu.nf.ch10.interceptor.AuthInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>
5、运行效果
1)非登录效果
2)登录效果
三、使用拦截器的好处
使用拦截器的好处包括:
-
统一处理:可以在拦截器中统一处理一些公共业务逻辑,比如权限校验、日志记录等,避免重复代码的出现。
-
粒度控制:可以根据具体的业务场景,选择拦截器拦截请求,实现粒度控制,从而更好地满足业务需求。
-
解耦合:通过拦截器可以将多个模块的功能解耦合,降低各组件之间的耦合度,提高代码可维护性和可扩展性。
-
提高安全性:通过拦截器可以对请求进行安全控制,比如防止SQL注入、XSS攻击等,提高Web应用系统的安全性。
-
性能优化:通过拦截器可以对请求进行缓存、预处理等操作,以提高Web应用系统的性能。
总之,使用拦截器可以帮助我们更好地管理请求,增强代码的可维护性和可读性,提高Web应用系统的安全性和性能。
四、gitee 案例
地址:ch10 · qiuqiu/SpringMVC - 码云 - 开源中国 (gitee.com)