1、概览 {#1概览}
本文将会带你了解 Spring MVC HandlerInterceptor
和 Servlet Filter
之间的区别和各自的应用场景。
2、Filter {#2filter}
Filter 是 Web 服务器的一部分,而不是 Spring 框架的组件。对于传入请求,可以使用 Filter 来操作甚至阻止请求到达任何 Servlet。反之亦然,也可以阻止响应到达客户端。
Spring Security 就是使用 Filter 进行身份认证和授权的一个很好的例子。要配置 Spring Security,只需添加一个 Filter
,即 DelegatingFilterProxy
。这样,Spring Security 就能拦截所有进出流量。这就是 Spring Security 可以在 Spring MVC 之外使用的原因。
2.1、创建 Filter {#21创建-filter}
创建一个实现 jakarta.servlet.Filter
接口的 Filter
实现类:
public class LogFilter implements Filter {
private Logger logger = LoggerFactory.getLogger(LogFilter.class);
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
logger.info("Hello from: " + request.getLocalAddr());
chain.doFilter(request, response); // 继续请求链调用
}
}
接下来,覆写 doFilter
方法,在该方法中,可以访问或操作 ServletRequest
、ServletResponse
或 FilterChain
对象。可以使用 FilterChain
对象允许或阻止请求。
可以选择直接继承
HttpFilter
抽象类,覆写其doFilter
方法。这样的话不需要自己强制转换
ServletRequest
和ServletResponse
为HttpServletRequest
和HttpServletResponse
。protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
然后可以在配置类中通过 FilterRegistrationBean
Bean 进行注册:
@Bean
public FilterRegistrationBean<LogFilter> logFilter() {
FilterRegistrationBean<LogFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new LogFilter()); // 设置 Filer 实现
registrationBean.setOrder(2); // Filter 的执行顺序
registrationBean.addUrlPatterns("/*"); // Filter 拦截的 URL
return registrationBean;
}
3、HandlerInterceptor {#3handlerinterceptor}
HandlerInterceptor
是 Spring MVC 框架中的组件,位于 DispatcherServlet
和 Controller 之间。使用拦截器,可以在请求到达 Controller 之前、视图渲染之前和之后对其进行拦截。
3.1、创建 HandlerInterceptor {#31创建-handlerinterceptor}
创建一个实现 org.springframework.web.servlet.HandlerInterceptor
接口的拦截器类。
可以选择覆写三个方法:
preHandle()
:在调用目标 Handler 之前执行,如果该方法返回false
则会阻止请求调用。postHandle()
:在调用目标 Handler 之后、DispatcherServlet
渲染视图之前执行。afterCompletion()
:在请求完成、视图渲染后执行。
创建一个测试拦截器,覆写上述三个方法,用于输出日志:
public class LogInterceptor implements HandlerInterceptor {
private Logger logger = LoggerFactory.getLogger(LogInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
logger.info("preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
logger.info("postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
logger.info("afterCompletion");
}
}
然后,通过 WebMvcConfigurer
配置类,配置 LogInterceptor
:
@Configuration
public class MvcConfiguration implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor()) // 设置拦截器实现
.addPathPatterns("/**") // 设置要拦截的路径
.excludePathPatterns("/foo") // 设置要忽略拦截的路径
;
}
}
4、主要区别和使用场景 {#4主要区别和使用场景}
Filter
和 HandlerInterceptor
在请求/响应流程中的位置示意图如下:
Filter
可在请求到达 DispatcherServlet
之前对其进行拦截,因此非常适合执行粗粒度任务,例如
- 认证。
- 日志记录和审计。
- 压缩图像和数据。
- 任何希望与 Spring MVC 解耦的功能。
HandlerInterceptor
会拦截 DispatcherServlet
与 Controller 之间的请求。这是在 Spring MVC 框架内完成的,提供了对 Handler
和 ModelAndView
对象的访问。这减少了重复代码,并允许实现更细粒度的功能,例如:
- 处理横切关注点,如应用日志记录。
- 详细的权限检查。
- 操作 Spring Context 或 Model。
5、总结 {#5总结}
本文介绍了如何创建、使用 Servlet 过滤器(Filter
)和 Spring MVC 拦截器(HandlerInterceptor
),以及它们之间的区别和应用场景。
Ref:https://www.baeldung.com/spring-mvc-handlerinterceptor-vs-filter