51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

Spring 应用中的 HandlerInterceptor 和 Filter

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 方法,在该方法中,可以访问或操作 ServletRequestServletResponseFilterChain 对象。可以使用 FilterChain 对象允许或阻止请求。

可以选择直接继承 HttpFilter 抽象类,覆写其 doFilter 方法。

这样的话不需要自己强制转换 ServletRequestServletResponseHttpServletRequestHttpServletResponse

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主要区别和使用场景}

FilterHandlerInterceptor 在请求/响应流程中的位置示意图如下:

Filter 和 HandlerInterceptor 在请求/响应流程中的位置示意图

Filter 可在请求到达 DispatcherServlet 之前对其进行拦截,因此非常适合执行粗粒度任务,例如

  • 认证。
  • 日志记录和审计。
  • 压缩图像和数据。
  • 任何希望与 Spring MVC 解耦的功能。

HandlerInterceptor 会拦截 DispatcherServlet 与 Controller 之间的请求。这是在 Spring MVC 框架内完成的,提供了对 HandlerModelAndView 对象的访问。这减少了重复代码,并允许实现更细粒度的功能,例如:

  • 处理横切关注点,如应用日志记录。
  • 详细的权限检查。
  • 操作 Spring Context 或 Model。

5、总结 {#5总结}

本文介绍了如何创建、使用 Servlet 过滤器(Filter)和 Spring MVC 拦截器(HandlerInterceptor),以及它们之间的区别和应用场景。


Ref:https://www.baeldung.com/spring-mvc-handlerinterceptor-vs-filter

赞(0)
未经允许不得转载:工具盒子 » Spring 应用中的 HandlerInterceptor 和 Filter