Spring boot Interceptor
工作原理
- Spring Interceptor依赖于 IOC容器, 基于 Java反射机制动态代理实现的
执行顺序
- 过滤前 - 拦截前 - Action处理 - 拦截后 -过滤后
使用场景
- 拦截器常用于权限验证等场景, 但由于依赖 IOC容器, 因此比起过滤器更灵活, 且控制的更细
常用拦截器接口
名称 | 类型 | - |
---|---|---|
HandlerInterceptor | 接口 | Spring的基础拦截器 |
AsyncHandlerInterceptor | 接口 | 继承 HandlerInterceptor接口, 并多了 afterConcurrentHandlingStarted方法, 用于处理异步请求 |
HandlerInterceptorAdapter | 抽象类 | 实现 AsyncHandlerInterceptor接口的适配器类 |
WebRequestInterceptor | 接口 | 类似与 HandlerInterceptor接口, 不同在于此接口只针对请求, 所以没有 response参数, 还有 preHandle没有返回值 |
HandlerInterceptor例子
工作流程
- 首先执行 preHandle方法(请求Controllor之前), 如果返回值是 true将会执行 postHandle方法(请求Controllor之后视图渲染之前), 最后执行 afterCompletion. 或当 preHandle方法的返回值为 false将会终止当前拦截器, 并如果下一步还有相同条件下的一个或多个拦截器都会终止, 还有如有当前拦截器之前有已执行过的拦截器也都不会不行到 postHandle方法, 而直接执行 afterCompletion结束拦截器, 但当前拦截器是不会执行 afterCompletion.
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CustomHandlerInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("CustomHandlerInterceptor preHandle");
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
System.out.println("CustomHandlerInterceptor postHandle");
}
/**
* 用于给当前拦截器做资源清理
*/
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
System.out.println("CustomHandlerInterceptor afterCompletion");
}
}
AsyncHandlerInterceptor例子
工作流程
- 与 HandlerInterceptor接口类似, 不过多了 afterConcurrentHandlingStarted方法, 当执行 preHandle方法的返回值是 false时以及没有异步请求时是与 HandlerInterceptor接口完全相同, 或 preHandle方法的返回值是 true, 且处理异步请求时 会执行 afterConcurrentHandlingStarted方法, 请看输出日志
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CustomAsyncHandlerInterceptor implements AsyncHandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("CustomAsyncHandlerInterceptor preHandle");
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
System.out.println("CustomAsyncHandlerInterceptor postHandle");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
System.out.println("CustomAsyncHandlerInterceptor afterCompletion");
}
public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("CustomAsyncHandlerInterceptor afterConcurrentHandlingStarted");
}
}
# 测试地址 http://127.0.0.1:8080/streaming
@GetMapping(value = "/streaming")
public StreamingResponseBody streaming() {
System.out.println("TestController -> streaming");
return (OutputStream outputStream) -> {
outputStream.write("streaming: ".getBytes());
outputStream.flush();
outputStream.close();
};
}
# 输出日志
CustomHandlerInterceptor preHandle
CustomAsyncHandlerInterceptor preHandle
TestController -> streaming
CustomAsyncHandlerInterceptor afterConcurrentHandlingStarted
CustomHandlerInterceptor preHandle
CustomAsyncHandlerInterceptor preHandle
CustomAsyncHandlerInterceptor postHandle
CustomHandlerInterceptor postHandle
CustomAsyncHandlerInterceptor afterCompletion
CustomHandlerInterceptor afterCompletion
HandlerInterceptorAdapter例子
工作流程
- 与 AsyncHandlerInterceptor接口完全相同, 只不过此接口为适配器, 因此可以只覆写要用的方法, 如果当前用的 Java版本是1.8的话由于出了新特性 default, 基本与实现 AsyncHandlerInterceptor接口相同了
WebRequestInterceptor例子
工作流程
- 方法的执行顺序与 HandlerInterceptor接口相同, 不同在于此接口只针对请求, 所以没有 response参数, 还有 preHandle没有返回值
import org.springframework.lang.Nullable;
import org.springframework.ui.ModelMap;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.WebRequestInterceptor;
public class CustomWebRequestInterceptor implements WebRequestInterceptor {
public void preHandle(WebRequest var1) throws Exception {
System.out.println("CustomWebRequestInterceptor preHandle");
}
public void postHandle(WebRequest var1, @Nullable ModelMap var2) throws Exception {
System.out.println("CustomWebRequestInterceptor postHandle");
}
public void afterCompletion(WebRequest var1, @Nullable Exception var2) throws Exception {
System.out.println("CustomWebRequestInterceptor afterCompletion");
}
}
配置拦截器
- Spring5.x或 Spring boot2.x版本或以上版本, 配环境时实现 WebMvcConfigurer, 以下版本可以实现 WebMvcConfigurerAdapter
通配符|匹配范围
–|:–:
*
| 如 /user/* 将会匹配 /user/a | /user/abc
**
| 包括多级路径 如 /user/** 将会匹配 /user/a | /user/abc/list | /user/abc/list/name等
ABC*
| 如 /user/list* 将会匹配 /user/list | /user/lists等
import com.example.demo.interceptor.CustomAsyncHandlerInterceptor;
import com.example.demo.interceptor.CustomHandlerInterceptor;
import com.example.demo.interceptor.CustomWebRequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter;
@Configuration
public class WebConfig implements WebMvcConfigurer {
/**
* 添加拦截器方法 addInterceptor
* 添加请求地址条件方法 addPathPatterns
* 添加过滤请求条件方法 excludePathPatterns
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(customHandlerInterceptor()).addPathPatterns("/*");
registry.addInterceptor(customAsyncHandlerInterceptor()).addPathPatterns("/**").excludePathPatterns("/streaming");
registry.addInterceptor(customWebRequestInterceptor()).addPathPatterns("/*/list*");
}
@Bean
public CustomHandlerInterceptor customHandlerInterceptor() {
return new CustomHandlerInterceptor();
}
@Bean
public CustomAsyncHandlerInterceptor customAsyncHandlerInterceptor() {
return new CustomAsyncHandlerInterceptor();
}
@Bean
public WebRequestHandlerInterceptorAdapter customWebRequestInterceptor() {
return new WebRequestHandlerInterceptorAdapter(
new CustomWebRequestInterceptor()
);
}
}
如果您觉得有帮助,欢迎点赞哦 ~ 谢谢!!