SpringBoot -拦截器Interceptor、过滤器 Filter 及设置

Spring Boot拦截器(Interceptor)的概念

复制代码
- 在Spring Boot中,拦截器是一种AOP的实现方式。它主要用于<font style="color:#DF2A3F;">拦截请求</font>,在请求处理之前和之后执行特定的代码逻辑。与过滤器不同的是,拦截器更侧重于对Spring MVC中的<font style="color:#DF2A3F;">控制器(Controller)</font>进行拦截,能够访问到Spring MVC上下文中的对象,比如获取请求的处理器(Handler)信息、模型(Model)和视图(View)相关信息等。

创建拦截器类

复制代码
- 要创建拦截器,需要实现`HandlerInterceptor`接口。这个接口有三个方法:
    * `<font style="color:#DF2A3F;">preHandle()</font>`:在请求处理之前调用。可以进行权限验证、日志记录等操作。如果返回`false`,则请求被中断,不会继续执行后续的处理器(Controller)方法;如果返回`true`,则请求继续传递。
    * `<font style="color:#DF2A3F;">postHandle()</font>`:在请求处理之后,视图渲染之前调用。可以对模型(Model)和视图(View)进行修改等操作。
    * `<font style="color:#DF2A3F;">afterCompletion()</font>`:在整个请求完成后(包括视图渲染后)调用。主要用于资源清理等操作。
- 例如,创建一个简单的拦截器来记录请求处理时间:RequestTimeInterceptor对象
java 复制代码
public class RequestTimeInterceptor implements HandlerInterceptor {
    private Date startTime;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        startTime = new Date();
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        Date endTime = new Date();
        System.out.println("Request processing time: " + (endTime.getTime() - startTime.getTime()) + "ms");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 可以在这里进行资源清理等操作
    }
}

配置拦截器

方式一:通过实现WebMvcConfigurer接口

复制代码
- 创建一个配置类,实现`WebMvcConfigurer`接口。
- 在`addInterceptors`方法中添加拦截器并配置拦截路径。
- 例如:
java 复制代码
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new RequestTimeInterceptor()).addPathPatterns("/**");
    }
}

上述代码中,addInterceptor方法添加了RequestTimeInterceptor拦截器,addPathPatterns方法指定了拦截的路径为所有路径(/**`)。

  • 方式二:通过扩展WebMvcConfigurationSupport类(不推荐,可能会覆盖Spring Boot的默认配置)
    • 创建一个配置类,继承自WebMvcConfigurationSupport
    • 重写addInterceptors方法来配置拦截器。
    • 例如:
java 复制代码
public class InterceptorConfiguration extends WebMvcConfigurationSupport {
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new RequestTimeInterceptor()).addPathPatterns("/**");
    }
}
复制代码
- 不过这种方式可能会导致Spring Boot自动配置的一些Web相关的配置失效,如静态资源处理等,所以一般推荐使用第一种方式。

拦截器的执行顺序

复制代码
- 当有多个拦截器时,它们的执行顺序是按照在`InterceptorRegistry`中添加的顺序来执行的。先添加的拦截器先执行`preHandle`方法,后执行`postHandle`和`afterCompletion`方法。例如,假设有拦截器`Interceptor1`和`Interceptor2`,配置如下:
java 复制代码
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new Interceptor1()).addPathPatterns("/**");
        registry.addInterceptor(new Interceptor2()).addPathPatterns("/**");
    }
}
复制代码
- 在这个例子中,`Interceptor1`的`preHandle`方法会先于`Interceptor2`的`preHandle`方法执行。而`Interceptor2`的`postHandle`和`afterCompletion`方法会先于`Interceptor1`的相应方法执行。

过滤器 Filter 的概念

  • 在 Spring Boot 中,过滤器是一种用于拦截和处理请求和响应的组件。它可以在请求到达控制器(Controller)之前进行预处理,例如验证请求头、验证用户身份等,也可以在响应返回客户端之前进行后处理,例如修改响应头、添加日志信息等。过滤器可以对多个请求和响应进行统一的处理,是实现横切关注点(如安全、日志记录等)的重要手段。

实现Filter接口,并使用@WebFilter注解(原生servlet配置方式)

java 复制代码
- **使用注解方式(推荐)**:
  - 在Spring Boot中,更方便的是使用`@WebFilter`注解来创建过滤器。例如:
    - ```java
      @WebFilter(urlPatterns = "/*")
      public class MyFilter implements Filter {
          @Override
          public void init(FilterConfig filterConfig) throws ServletException {
              // 初始化方法,在过滤器初始化时调用,可以进行一些初始化操作,如加载配置文件等
          }
          @Override
          public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
              // 过滤方法,在这里可以对请求进行处理,然后决定是否将请求传递给下一个过滤器或控制器
              // 例如,可以在这里检查请求头中的令牌(Token)是否有效
              filterChain.doFilter(servletRequest, servletResponse);
              // 在调用filterChain.doFilter后,可以对响应进行处理
          }
          @Override
          public void destroy() {
              // 销毁方法,在过滤器销毁时调用,可以进行一些资源释放等
          }
      }
  • 其中@WebFilter(urlPatterns = "/*")注解用于指定过滤器要拦截的 URL 模式,/*表示拦截所有的请求路径。
  • 自动配置使用@WebFilter注解的过滤器:
    • 需要在 Spring Boot 的主应用程序类上添加@ServletComponentScan注解,这样 Spring Boot 才能扫描到过滤器并自动进行配置。例如:
java 复制代码
@SpringBootApplication
@ServletComponentScan
public class MySpringBootApp {
    public static void main(String[] args) {
        SpringApplication.run(MySpringBootApp.class, args);
    }
}
  • 手动配置(通过 FilterRegistrationBean
    • 有时候可能需要更灵活的配置,例如设置过滤器的执行顺序、添加初始化参数等。可以通过FilterRegistrationBean对象 来手动配置过滤器。例如:
    • <font style="color:rgb(38, 38, 38);background-color:rgb(242, 242, 247);">FilterRegistrationBean对象可以:</font>
      • 设置实际过滤器 setFilter()
      • 设置过滤器名 setName("myFilter");
      • 设置过滤路径 addUrlPatterns("/*");
      • 设置优先级 setOrder(1);
java 复制代码
@Configuration
public class FilterConfig {
    @Bean
    public FilterRegistrationBean<MyFilter> myFilterRegistration() {
        FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new MyFilter());
        registrationBean.addUrlPatterns("/*");
        registrationBean.setName("myFilter");
        registrationBean.setOrder(1); // 设置过滤器的执行顺序,数字越小越先执行
        return registrationBean;
    }
}

过滤器链(Filter Chain)

复制代码
- 当有多个过滤器时,它们会形成一个过滤器链。请求会依次经过每个过滤器,每个过滤器都可以对请求进行处理,然后决定是否将请求传递给下一个过滤器。在`doFilter`方法中,通过调用`filterChain.doFilter(servletRequest, servletResponse)`来将请求传递给下一个过滤器或控制器。如果某个过滤器没有调用这个方法,那么请求就会被截断,后续的过滤器和控制器都不会收到这个请求。同样,在响应返回时,也会按照相反的顺序经过各个过滤器,每个过滤器可以对响应进行处理。例如,假设有两个过滤器`Filter1`和`Filter2`,请求首先会到达`Filter1`,`Filter1`处理后传递给`Filter2`,`Filter2`处理后传递给控制器;响应返回时,先经过`Filter2`,再经过`Filter1`,最后返回给客户端。

**1.**通过xml文件配置过滤器链:

复制代码
    * 创建两个过滤器:CharacterEncodingFilter、LoggingFilter
java 复制代码
public class CharacterEncodingFilter implements Filter {
    private String encoding;
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        encoding = filterConfig.getInitParameter("encoding");
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding(encoding);
        filterChain.doFilter(servletRequest, servletResponse);
    }
    @Override
    public void destroy() {
        // 可以在这里进行资源释放等操作
    }
}
java 复制代码
public class LoggingFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("Request received at: " + new Date());
        filterChain.doFilter(servletRequest, servletResponse);
    }
    @Override
    public void destroy() {
       
    }
}
复制代码
    * **配置过滤器链(在 web.xml 中)**
    * 在这个配置中,`LoggingFilter`会应用到所有的请求(`/*`)。`CharacterEncodingFilter`会应用到名为`MyServlet`的 Servlet。当请求到来时,会先经过`LoggingFilter`,然后根据请求的目标是`MyServlet`时,再经过`CharacterEncodingFilter`。
xml 复制代码
<filter>
  <filter - name>LoggingFilter</filter - name>
  <filter - class>com.example.filters.LoggingFilter</filter - class>
</filter>
<filter - mapping>
  <filter - name>LoggingFilter</filter - name>
  <url - pattern>/*</url - pattern>
</filter - mapping>

<filter>
  <filter - name>CharacterEncodingFilter</filter - name>
  <filter - class>com.example.filters.CharacterEncodingFilter</filter - class>
  <init - param>
    <param - name>encoding</param - name>
    <param - value>UTF - 8</param - value>
  </init - param>
</filter>
<filter - mapping>
  <filter - name>CharacterEncodingFilter</filter - name>
  <servlet - name>MyServlet</servlet - name>
</filter - mapping>
  • 上述代码中,首先定义了一个名为CharacterEncodingFilter的过滤器,并且通过<init - param>标签设置了一个初始化参数encodingUTF - 8。然后通过<filter - mapping>标签将这个过滤器应用到所有的请求(/*)。当请求到来时,这个过滤器会设置请求的字符编码为UTF - 8,然后将请求传递给下一个过滤器或者目标资源。

**2.**使用注解方式(Servlet 3.0+)实现过滤器链

复制代码
- 当有多个注解式过滤器时,过滤器的执行顺序是按照类名的字典序来确定的。如果需要更精确地控制顺序,可以使用`@javax.annotation.Priority`注解来指定优先级。数字越小,优先级越高。
java 复制代码
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.annotation.Priority;
import java.io.IOException;

@WebFilter(filterName = "AuthFilter", urlPatterns = "/*")
@Priority(1)
public class AuthFilter implements Filter {
    //...
}

@WebFilter(filterName = "AnotherFilter", urlPatterns = "/*")
@Priority(2)
public class AnotherFilter implements Filter {
    //...
}

DelegatingFilterProxyRegistrationBean 对象代理过滤器。

  • DelegatingFilterProxyRegistrationBean 是 Spring Boot 中用于注册一个代理过滤器(DelegatingFilterProxy)的配置类。它主要用于将一个基于 Servlet 的过滤器集成到 Spring 的应用上下文中,使得这个过滤器能够利用 Spring 的特性,如依赖注入、配置属性等。
  • 这个类在将传统的 Servlet 过滤器与 Spring 应用进行整合时非常有用。例如,在一些安全认证过滤器或者日志记录过滤器的场景下,通过它可以更好地管理和配置这些过滤器,让它们能够从 Spring 的环境配置(如配置文件、环境变量等)中获取必要的参数,并且能够方便地与 Spring 管理的其他组件(如服务层组件、数据源等)进行交互。

·配置 **DelegatingFilterProxyRegistrationBean**

假设我们有一个自定义的过滤器MyFilter,并且希望通过DelegatingFilterProxyRegistrationBean 来注册它,使其能够与 Spring 应用上下文集成。

1**.创建一个过滤器:MyFilter**

java 复制代码
public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化过滤器,这里可以获取初始化参数等操作
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 执行过滤操作,例如检查请求头、验证用户身份等
        filterChain.doFilter(servletRequest, servletResponse);
    }
    @Override
    public void destroy() {
        // 销毁过滤器,释放资源
    }
}

2.然后,在Spring Boot的配置类中注册DelegatingFilterProxyRegistrationBean

java 复制代码
@Configuration
public class FilterConfig {
    @Bean
    public FilterRegistrationBean<DelegatingFilterProxy> myFilterRegistration() {
        FilterRegistrationBean<DelegatingFilterProxy> registrationBean = new FilterRegistrationBean<>();
        DelegatingFilterProxy delegatingFilterProxy = new DelegatingFilterProxy("myFilter");
        registrationBean.setFilter(delegatingFilterProxy);
        registrationBean.addUrlPatterns("/*");
        return registrationBean;
    }
    @Bean(name = "myFilter")
    public MyFilter myFilter() {
        return new MyFilter();
    }
}
  • 在上述配置中,首先创建了一个DelegatingFilterProxyRegistrationBean,并将一个DelegatingFilterProxy 实例设置为其过滤器。DelegatingFilterProxy 的构造函数参数 "myFilter" 是要在 Spring 应用上下文中查找的真正过滤器 Bean 的名称。然后,通过addUrlPatterns("/*") 设置了过滤器拦截的 URL 模式为所有请求。同时,还通过@Bean(name = "myFilter") 方法定义了真正的过滤器MyFilter,这样DelegatingFilterProxy 就能在 Spring 应用上下文中找到它并进行委托。

DelegatingFilterProxyRegistrationBean的优点:

1 .灵活性高,它允许过滤器成为 Spring 的 Bean,从而可以利用 Spring 的各种功能,

2 .便与维护和管理。有多个过滤器需要集成和管理。

相关推荐
用户99045017780096 分钟前
ruoyi-vue2集成flowable6.7.2后端篇
后端
qq_124987075311 分钟前
基于springboot框架的小型饮料销售管理系统的设计与实现(源码+论文+部署+安装)
java·spring boot·后端·spring·毕业设计
我命由我1234517 分钟前
Python Flask 开发:在 Flask 中返回字符串时,浏览器将其作为 HTML 解析
服务器·开发语言·后端·python·flask·html·学习方法
IT_陈寒26 分钟前
JavaScript 性能优化:5个被低估的V8引擎技巧让你的代码提速50%
前端·人工智能·后端
想用offer打牌37 分钟前
数据库大事务有什么危害(面试版)
数据库·后端·架构
Jaising66638 分钟前
Spring 错误使用事务导致数据可见性问题分析
数据库·spring boot
踏浪无痕1 小时前
别再只会用 Feign!手写一个 Mini RPC 框架搞懂 Spring Cloud 底层原理
后端·面试·架构
NMBG221 小时前
外卖综合项目
java·前端·spring boot
小徐Chao努力1 小时前
Spring AI Alibaba A2A 使用指南
java·人工智能·spring boot·spring·spring cloud·agent·a2a
用户695619440371 小时前
前后端分离VUE3+Springboot项目集成PageOffice核心代码
后端