什么是拦截器
在 Spring Web MVC 中,拦截器(Interceptor)同 Servlet 中的过滤器(Filter) 类似,
都可以实现对用户的请求做出相应的处理。
所有 HandlerMapping
的实现都支持处理程序拦截器,当想将特定功能应用于某些请求时很有用 —— 例如检查权限。
拦截器必须实现 org.springframework.web.servlet
包中 HandlerInterceptor
接口的三个方法,
这些方法能够提供足够的灵活性来进行各种预处理和后处理:
preHandle(..): Before the actual handler is run // 在实际 handler 之前运行
postHandle(..): After the handler is run // 在 handler 之后运行
afterCompletion(..): After the complete request has finished // 在整个请求完成后运行
preHandle 方法返回一个布尔值,可以用该方法中断或者继续执行链的处理。
- 当返回 true 时,执行链会继续执行;
- 当返回 false 时,DispatcherServlet 假定拦截器本身已经处理了请求(例如,呈现了适当的视图)并且不会继续执行其他拦截器和执行链中的实际处理程序。
【注意】:postHandle
对于 @ResponseBody
和 ResponseEntity
方法的用处不大,因为这些方法的响应是在 HandlerAdapter
中和 postHandle
之前写入和提交的。
这意味着对响应进行任何更改都为时已晚,例如添加额外的请求头。
对于此类场景,您可以实现 ResponseBodyAdvice
并将其声明为 Controller Advice
bean 或直接在 RequestMappingHandlerAdapter
上进行配置。
自定义拦截器
1、定义拦截器:监控请求时间
- 在进入处理器之前记录开始时间,即在拦截器的 preHandle 记录开始时间;
- 在结束请求处理之后记录结束时间,即在拦截器的 afterCompletion 记录结束实现,并用结束时间-开始时间得到这次请求的处理时间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @Component public class TimeTrackingInterceptor implements HandlerInterceptor {
private static Logger log = LoggerFactory.getLogger(TimeTrackingInterceptor.class); private static final ThreadLocal<Long> logTimeThreadLocal = new NamedThreadLocal<>("ThreadLocal StartTime");
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { long beginTime = System.currentTimeMillis(); logTimeThreadLocal.set(beginTime); log.info(request.getRequestURI() + " 开始执行时间:" + beginTime); return true; }
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { }
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { long beginTime = logTimeThreadLocal.get(); long endTime = System.currentTimeMillis(); log.info(request.getRequestURI() + " 执行结束时间:" + endTime); log.info("耗时:" + (endTime - beginTime) + "ms"); } }
|
2、controller 类
1 2 3 4 5 6 7 8 9 10
| @RestController public class InterceptorController {
@RequestMapping("/index") public Map<String,String> hello(Model model){ Map<String,String> response=new HashMap<>(); response.put("msg","hello"); return response; } }
|
配置拦截器
有关如何配置拦截器的示例,可参阅 MVC 配置部分中的拦截器。
能够使 TimeTrackingInterceptor 拦截到 /index 生效,将 TimeTrackingInterceptor 注册拦截器配置中即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @Configuration public class InterceptorConfig implements WebMvcConfigurer { private final TimeTrackingInterceptor timeTrackingInterceptor;
public InterceptorConfig(TimeTrackingInterceptor timeTrackingInterceptor) { this.timeTrackingInterceptor = timeTrackingInterceptor; }
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(timeTrackingInterceptor).addPathPatterns("/index"); }
@Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/**").addResourceLocations("classpath:/my/"); }
}
|
启动应用,运行效果
启动后通过访问http://127.0.0.1:8080/index,发现已经拦截到请求,在控制台日志中打印了上述日志信息。
参考资料
Title: Spring之Interceptor
Author: Amber
Date: 2022-07-01
Last Update: 2024-10-29
Blog Link: https://wyiyi.github.io/amber/2022/07/01/interceptor/
Copyright Declaration: Copyright © 2022 Amber.