过滤器和拦截器的区别

233 阅读1分钟

过滤器和拦截器的区别

什么是过滤器?

Filter 也称为过滤器,基于Servlet实现,过滤器的主要应用场景是对字符编码、跨域等问题进行过滤。Servlet的工作原理是拦截配置好的客户端请求,然后对Request和Response进行处理。Filter过滤器随着web应用的启动而启动,只初始化一次。

什么是拦截器?

拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行,基于AOP思想,对方法进行增强。和servlet 中的过滤器类似,都是对用户请求进行处理。

他们有什么不同?

img

  1. 拦截器是基于Java的反射机制,而过滤器是基于函数回调;
  2. 拦截器不依赖servlet容器,过滤器依赖servlet容器;
  3. 拦截器只能对Controller 请求起作用,而过滤器则可以对几乎所有的请求起作用;
  4. 拦截器可以访问action上下文、堆栈里的对象,过滤器不能访问;
  5. 在action生命周期中,拦截器可以多次被调用,过滤器只能在容器初始化时被调用一次。

在springboot中使用拦截器和过滤器

使用过滤器,有两种方式

  1. 实现 Filter 类,重写其 doFilter 方法,注意这个类是 javax.servlet 包下的

    @Slf4j
    @Component
    public class MyFilter implements Filter {
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
                throws IOException, ServletException {
            log.info("进入过滤器 MyFilter");
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }
    

    注册

    @Configuration
    public class FilterConfig {
    ​
        @Autowired
        private MyFilter myFilter;
    ​
        @Bean
        public FilterRegistrationBean injectFilterOne() {
            FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
            registrationBean.setFilter(myFilter);
            registrationBean.addUrlPatterns("/*");
            registrationBean.setName("filter_one");
            // 优先级
            registrationBean.setOrder(1);
            return registrationBean;
        }
    }
    
  2. 使用 @WebFilter 注解

    @Slf4j
    @WebFilter(filterName = "filter_two", urlPatterns = {"/*"})
    public class MyFilter2 implements Filter {
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
                throws IOException, ServletException {
            log.info("进入过滤器 MyFilter2");
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }
    

    这种方式需要在启动类上扫描 @WebFilter注解,需要加上以下注解

    @ServletComponentScan(value = {"com.example.config.filter"})

使用拦截器

新建一个类实现 HandlerInterceptor 接口

@Component
@Slf4j
public class MyInterceptor implements HandlerInterceptor {
​
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("进入拦截器 MyIntercept,preHandle 方法 ");
        return HandlerInterceptor.super.preHandle(request, response, handler);
    }
​
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("进入拦截器 MyIntercept,postHandle 方法 ");
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }
​
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("进入拦截器 MyIntercept,afterCompletion 方法 ");
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

注册

@Configuration
public class WebConfig implements WebMvcConfigurer {
​
    @Autowired
    private MyInterceptor myInterceptor;
​
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 拦截器拦截路径
        registry.addInterceptor(myInterceptor).addPathPatterns("/**");
    }
}
1. preHandle(......)方法:当url已经匹配到controller层中某个方法时,在方法执行前执行
它会决定是否放行,返回true,放行,返回false,不会执行
2.  postHandle(……) 方法:url 匹配到Controller 中的某个方法,且执行完了该方法,
但是在 DispatcherServlet 视图渲染之前执行。在这个方法中有个 ModelAndView 参数,可以在此做一些修改动作。
3. afterCompletion(……) 方法:在整个请求处理完成后(包括视图渲染)执行,
做一些资源的清理工作,这个方法只有在 preHandle(……) 被成功执行后并且返回true才会被执行。

过滤器和拦截器放在一起的执行结果:

2023-05-06 23:41:48.774  INFO 15484 --- [nio-8080-exec-2] com.example.config.filter.MyFilter       : 进入过滤器 MyFilter
2023-05-06 23:41:48.774  INFO 15484 --- [nio-8080-exec-2] com.example.config.filter.MyFilter2      : 进入过滤器 MyFilter2
2023-05-06 23:41:48.785  INFO 15484 --- [nio-8080-exec-2] c.e.config.interceptor.MyInterceptor     : 进入拦截器 MyIntercept,preHandle 方法 
2023-05-06 23:41:48.807  INFO 15484 --- [nio-8080-exec-2] c.e.config.interceptor.MyInterceptor     : 进入拦截器 MyIntercept,postHandle 方法 
2023-05-06 23:41:48.807  INFO 15484 --- [nio-8080-exec-2] c.e.config.interceptor.MyInterceptor     : 进入拦截器 MyIntercept,afterCompletion 方法 

参考文章

  1. blog.csdn.net/K_520_W/art…
  2. www.cnblogs.com/wangms821/p…