0
点赞
收藏
分享

微信扫一扫

Spring Boot拦截器(Interceptor)的概念

Spring Boot拦截器(Interceptor)的概念

  • 在Spring Boot中,拦截器是一种AOP的实现方式。它主要用于拦截请求,在请求处理之前和之后执行特定的代码逻辑。与过滤器不同的是,拦截器更侧重于对Spring MVC中的控制器(Controller)进行拦截,能够访问到Spring MVC上下文中的对象,比如获取请求的处理器(Handler)信息、模型(Model)和视图(View)相关信息等。 1 创建拦截器类
  • 要创建拦截器,需要实现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对象 1 2 3 4 5 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 { // 可以在这里进行资源清理等操作 } }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 配置拦截器 方式一:通过实现WebMvcConfigurer接口

  • 创建一个配置类,实现WebMvcConfigurer接口。
  • addInterceptors方法中添加拦截器并配置拦截路径。
  • 例如: 1 2 3 @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方法来配置拦截器。 例如:

public class InterceptorConfiguration extends WebMvcConfigurationSupport { @Override protected void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new RequestTimeInterceptor()).addPathPatterns("/**"); } } 1 2 3 4 5 6 7

  • 不过这种方式可能会导致Spring Boot自动配置的一些Web相关的配置失效,如静态资源处理等,所以一般推荐使用第一种方式。 1 拦截器的执行顺序
  • 当有多个拦截器时,它们的执行顺序是按照在InterceptorRegistry中添加的顺序来执行的。先添加的拦截器先执行preHandle方法,后执行postHandleafterCompletion方法。例如,假设有拦截器Interceptor1Interceptor2,配置如下: 1 @Configuration public class InterceptorConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new Interceptor1()).addPathPatterns("/"); registry.addInterceptor(new Interceptor2()).addPathPatterns("/"); } } 1 2 3 4 5 6 7 8
  • 在这个例子中,Interceptor1preHandle方法会先于Interceptor2preHandle方法执行。而Interceptor2postHandleafterCompletion方法会先于Interceptor1的相应方法执行。 1 过滤器 Filter 的概念 在 Spring Boot 中,过滤器是一种用于拦截和处理请求和响应的组件。它可以在请求到达控制器(Controller)之前进行预处理,例如验证请求头、验证用户身份等,也可以在响应返回客户端之前进行后处理,例如修改响应头、添加日志信息等。过滤器可以对多个请求和响应进行统一的处理,是实现横切关注点(如安全、日志记录等)的重要手段。 实现Filter接口,并使用@WebFilter注解(原生servlet配置方式)
  • 使用注解方式(推荐)
  • 在Spring Boot中,更方便的是使用@WebFilter注解来创建过滤器。例如:

@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() {
        // 销毁方法,在过滤器销毁时调用,可以进行一些资源释放等
    }
}

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 其中@WebFilter(urlPatterns = "/*")注解用于指定过滤器要拦截的 URL 模式,/*表示拦截所有的请求路径。 自动配置使用@WebFilter注解的过滤器: 需要在 Spring Boot 的主应用程序类上添加@ServletComponentScan注解,这样 Spring Boot 才能扫描到过滤器并自动进行配置。例如:

@SpringBootApplication @ServletComponentScan public class MySpringBootApp { public static void main(String[] args) { SpringApplication.run(MySpringBootApp.class, args); } } 1 2 3 4 5 6 7 8 手动配置(通过FilterRegistrationBean): 有时候可能需要更灵活的配置,例如设置过滤器的执行顺序、添加初始化参数等。可以通过FilterRegistrationBean对象 来手动配置过滤器。例如: FilterRegistrationBean对象可以:

@Configuration public class FilterConfig { @Bean public FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new MyFilter()); registrationBean.addUrlPatterns("/*"); registrationBean.setName("myFilter"); registrationBean.setOrder(1); // 设置过滤器的执行顺序,数字越小越先执行 return registrationBean; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 过滤器链(Filter Chain)

  • 当有多个过滤器时,它们会形成一个过滤器链。请求会依次经过每个过滤器,每个过滤器都可以对请求进行处理,然后决定是否将请求传递给下一个过滤器。在doFilter方法中,通过调用filterChain.doFilter(servletRequest, servletResponse)来将请求传递给下一个过滤器或控制器。如果某个过滤器没有调用这个方法,那么请求就会被截断,后续的过滤器和控制器都不会收到这个请求。同样,在响应返回时,也会按照相反的顺序经过各个过滤器,每个过滤器可以对响应进行处理。例如,假设有两个过滤器Filter1Filter2,请求首先会到达Filter1Filter1处理后传递给Filter2Filter2处理后传递给控制器;响应返回时,先经过Filter2,再经过Filter1,最后返回给客户端。 1 **1.**通过xml文件配置过滤器链:
  • 创建两个过滤器:CharacterEncodingFilter、LoggingFilter 1 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() { // 可以在这里进行资源释放等操作 } }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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() {

}

} 1 2 3 4 5 6 7 8 9 10 11 12 13 14 * 配置过滤器链(在 web.xml 中) * 在这个配置中,LoggingFilter会应用到所有的请求(/*)。CharacterEncodingFilter会应用到名为MyServlet的 Servlet。当请求到来时,会先经过LoggingFilter,然后根据请求的目标是MyServlet时,再经过CharacterEncodingFilter。 1 2 <filter - name>LoggingFilter</filter - name> <filter - class>com.example.filters.LoggingFilter</filter - class>

<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>

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 上述代码中,首先定义了一个名为CharacterEncodingFilter的过滤器,并且通过<init - param>标签设置了一个初始化参数encoding为UTF - 8。然后通过<filter - mapping>标签将这个过滤器应用到所有的请求(/*)。当请求到来时,这个过滤器会设置请求的字符编码为UTF - 8,然后将请求传递给下一个过滤器或者目标资源。 **2.**使用注解方式(Servlet 3.0+)实现过滤器链

  • 当有多个注解式过滤器时,过滤器的执行顺序是按照类名的字典序来确定的。如果需要更精确地控制顺序,可以使用@javax.annotation.Priority注解来指定优先级。数字越小,优先级越高。 1 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 { //... }

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

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

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

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() { // 销毁过滤器,释放资源 } }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 2.然后,在Spring Boot的配置类中注册DelegatingFilterProxyRegistrationBean:

@Configuration public class FilterConfig { @Bean public FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); DelegatingFilterProxy delegatingFilterProxy = new DelegatingFilterProxy("myFilter"); registrationBean.setFilter(delegatingFilterProxy); registrationBean.addUrlPatterns("/"); return registrationBean; } @Bean(name = "myFilter") public MyFilter myFilter() { return new MyFilter(); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 在上述配置中,首先创建了一个DelegatingFilterProxyRegistrationBean,并将一个DelegatingFilterProxy 实例设置为其过滤器。DelegatingFilterProxy 的构造函数参数 "myFilter" 是要在 Spring 应用上下文中查找的真正过滤器 Bean 的名称。然后,通过addUrlPatterns("/") 设置了过滤器拦截的 URL 模式为所有请求。同时,还通过@Bean(name = "myFilter") 方法定义了真正的过滤器MyFilter,这样DelegatingFilterProxy 就能在 Spring 应用上下文中找到它并进行委托。 DelegatingFilterProxyRegistrationBean的优点: 1 .灵活性高,它允许过滤器成为 Spring 的 Bean,从而可以利用 Spring 的各种功能,

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

举报

相关推荐

0 条评论