拦截器
1. 简介
Spring MVC 中的拦截器(Interceptor)类似与 Servlet 开发中的过滤器 Filter,它主要用于拦截用户请求并作相应的处理, 它也是 AOP 编程思想的体现, 底层通过动态代理模式完成。
2. 定义实现类
拦截器有两种实现方式:
1. 实现 HandlerInterceptor 接口
2. 继承 HandlerInterceptorAdapter 抽象类(看源码最底层也是通过 HandlerInterceptor 接口 实现)
3.HandlerInterceptor 方法介绍
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 进行逻辑判断,如果 ok 就返回 true,不行就返回 false,返回 false 就不会处理请求
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception { }
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {}
preHandle:在业务处理器处理请求之前被调用。预处理,可以进行编码、安全控制、权限校验等处理;
postHandle:在业务处理器处理请求执行完成后,生成视图之前执行。
afterCompletion:在 DispatcherServlet 完全处理完请求后被调用,可用于清理资源等。
4. 应用场景
1. 日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算 PV(Page View)等;
2. 登录鉴权:如登录检测,进入处理器检测检测是否登录;
3. 性能监控:检测方法的执行时间;
4. 其他通用行为。
5. 与 Filter 过滤器的区别
1. 拦截器是基于 java 的反射机制的,而过滤器是基于函数回调。
2. 拦截器不依赖于 servlet 容器,而过滤器依赖于 servlet 容器。
3. 拦截器只能对 Controller 请求起作用,而过滤器则可以对几乎所有的请求起作用。
4. 拦截器可以访问 action 上下文、值栈里的对象,而过滤器不能访问。
5. 在 Controller 的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
6. 拦截器可以获取 IOC 容器中的各个 bean,而过滤器不行。这点很重要,在拦截器里注入一个 service,可以调用业务逻辑。
具体实现
单个拦截器
1. 新建拦截器
public class Test1Interceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {System.out.println("执行 preHandle 方法 -->01");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {System.out.println("执行 postHandle 方法 -->02");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {System.out.println("执行 afterCompletion 方法 -->03");
}
}
2. 配置拦截器
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
/*
* 拦截器配置
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册自定义拦截器,添加拦截路径和排除拦截路径
registry.addInterceptor(new Test1Interceptor()) // 添加拦截器
.addPathPatterns("/**") // 添加拦截路径
.excludePathPatterns(// 添加排除拦截路径
"/hello").order(0);// 执行顺序
super.addInterceptors(registry);
}
}
3. 测试拦截器
@RestController
public class TestController {@RequestMapping("/hello")
public String getHello() {System.out.println("这里是 Hello");
return "hello world";
}
@RequestMapping("/test1")
public String getTest1() {System.out.println("这里是 Test1");
return "test1 content";
}
@RequestMapping("/test2")
public String getTest2() {System.out.println("这里是 Test2");
return "test2 content";
}
}
4. 单个拦截器的执行流程
通过浏览器测试:
http://127.0.0.1:8080/hello
结果:
这里是 Hello
http://127.0.0.1:8080/test1、http://127.0.0.1:8080/test2
结果:
执行 preHandle 方法 -->01
这里是 Test1
执行 postHandle 方法 -->02
执行 afterCompletion 方法 -->03
多个拦截器
1. 新建两个拦截器
Test1Interceptor
public class Test1Interceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {System.out.println("执行 Test1Interceptor preHandle 方法 -->01");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {System.out.println("执行 Test1Interceptor postHandle 方法 -->02");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {System.out.println("执行 Test1Interceptor afterCompletion 方法 -->03");
}
}
Test2Interceptor
public class Test2Interceptor extends HandlerInterceptorAdapter{public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {System.out.println("执行 Test2Interceptor preHandle 方法 -->01");
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {System.out.println("执行 Test2Interceptor postHandle 方法 -->02");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {System.out.println("执行 Test2Interceptor afterCompletion 方法 -->03");
}
}
2. 配置拦截器
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
/*
* 拦截器配置
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册自定义拦截器,添加拦截路径和排除拦截路径
registry.addInterceptor(new Test1Interceptor()) // 添加拦截器 1
.addPathPatterns("/**") // 添加拦截路径
.excludePathPatterns(// 添加排除拦截路径
"/hello")
.order(0);
registry.addInterceptor(new Test2Interceptor()) // 添加拦截器 2
.addPathPatterns("/**") // 添加拦截路径
.excludePathPatterns(// 添加排除拦截路径
"/test1")
.order(1);
super.addInterceptors(registry);
}
}
3. 测试拦截器
@RestController
public class TestController {@RequestMapping("/hello")
public String getHello() {System.out.println("这里是 Hello");
return "hello world";
}
@RequestMapping("/test1")
public String getTest1() {System.out.println("这里是 Test1");
return "test1 content";
}
@RequestMapping("/test2")
public String getTest2() {System.out.println("这里是 Test2");
return "test2 content";
}
}
4. 多个拦截器的执行流程
通过浏览器测试:
http://127.0.0.1:8080/test2
结果:
执行 Test1Interceptor preHandle 方法 -->01
执行 Test2Interceptor preHandle 方法 -->01
这里是 Test2
执行 Test2Interceptor postHandle 方法 -->02
执行 Test1Interceptor postHandle 方法 -->02
执行 Test2Interceptor afterCompletion 方法 -->03
执行 Test1Interceptor afterCompletion 方法 -->03
通过示例,简单的说多个拦截器执行流程就是 先进后出。
简单的 token 判断示例
1. 拦截器
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {System.out.println("执行 Test1Interceptor preHandle 方法 -->01");
String token = request.getParameter("token");
if (StringUtils.isEmpty(token)) {response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
response.getWriter().println("token 不存在");
return false;
}
return true;
}
2. 测试及结果
未传 token:
执行 Test1Interceptor preHandle 方法 -->01
传 token:
执行 Test1Interceptor preHandle 方法 -->01
页码:1
页码大小:10
执行 Test1Interceptor postHandle 方法 -->02
执行 Test1Interceptor afterCompletion 方法 -->03
示例代码
github
码云
非特殊说明,本文版权归 朝雾轻寒 所有,转载请注明出处.
原文标题:Spring Boot 2.X(九):Spring MVC – 拦截器(Interceptor)
原文地址:https://www.zwqh.top/article/info/18
如果文章对您有帮助,请扫码关注下我的公众号,文章持续更新中 …