java中的Filter(过滤器)和Intercepter(拦截器)的认知

一、过滤器的配置

  • 首先,从认知方面看,如果自己真的对Filter和Intercepter 不熟悉或者忘记的话可以自己在IDEA中编写Demo进行查看两个的区别,这也是自己动手去认知的过程。首先从Filter开始
public class TestFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("TestFilter init 完成");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
          System.out.println("执行TestFilter  doFIlter");
    }

    @Override
    public void destroy() {
        System.out.println("TestFilter destroy");
    }
}

以上代码在项目启动的时候会初始化FIlter。

ps:如果Filter要使请求继续被处理,就一定要调用filterChain.doFilter()!

代码很直观的看出Filter是基于Servlet。我们点击Filter的源码进行查看,看看里面是干了什么。比如注释什么的解释的很清楚。执行流程如下:

过滤器的应用场景:
以下是来自Filter的官方解释

Filters are configured in the deployment descriptor of a web application
Examples that have been identified for this design are

  1. Authentication Filters //身份验证过滤器
  2. Logging and Auditing Filters // 记录和审计过滤器
  3. Image conversion Filters // 图像转换过滤器
  4. Data compression Filters //数据压缩过滤器
  5. Encryption Filters //加密过滤器
  6. Tokenizing Filters //标记过滤器
  7. Filters that trigger resource access events //触发资源访问事件的过滤器
  8. XSL/T filters //XSLT 过滤器
  9. Mime-type chain Filter
  • 配置Filter交给Spring管理
    方式1
    使用@Component+@Order
    在TestFilter 类上加@Compoent 和@Order(1) 注解 即可把当前的Filter交给Spring管理。当有多个Filter时,这里的@Order(1)注解会指定执行顺序,数字越小,越优先执行,如果只写@Order,默认顺序值是Integer.MAX_VALUE。

@Component + @Order 注解方式配置简单,支持自定义 Filter 顺序。缺点是只能拦截所有URL,不能通过配置去拦截指定的 URL。

方式2
使用@WebFilter+@ServletComponentScan
@ServletComponentScan 可加在当前Filter类上,也可加在启动类上。

方式3
使用javaConfig配置类


@Configuration
public class FilterConfig {
    @Bean
    public FilterBean filterBean(){
        FilterBean <TestFilter> bean = new FilterBean<>();
        bean.setOrder(1);
        bean.setFilter(new TestFilter());
        // 匹配"/test/"下面的所有url
        bean.addUrlPatterns("/test/*");
        return bean;
    }
    @Bean
    public FilterBean2 filterBean2(){
        FilterBean2 <TestFilter2> bean = new FilterBean2<>();
        bean.setOrder(2);
        bean.setFilter(new TestFilter2());
        // 匹配所有url
        bean.addUrlPatterns("/*");
        return bean;
    }
}

使用@Component/@Order 注解 和 使用Config配置Filter的对比
首先定义两个Filter ,一个是使用@Component/@Order 一个是使用配置文件FilterRegistrationBean

@Component
@Order(-1)
public class TestFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("TestFilter init 完成");
    }
    /**
     * 需要忽略的地址
     */
    private static final String[] IGNORES = new String[]{
           "/"
    };
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        long start = System.currentTimeMillis();
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("TestFilter Execute cost="+(System.currentTimeMillis()-start));
    }

    @Override
    public void destroy() {
        System.out.println("TestFilter  destroy销毁");
    }
}

FilterRegistrationBeanConfig配置类

@Configuration
public class FilterConfig {
    @Bean
    public FilterRegistrationBean filterRegistrationBean(){
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new LogCostFilter());
        registration.addUrlPatterns("/*");
        registration.setName("LogCostFilter");
        registration.setOrder(2);
        return registration;
    }


}



public class LogCostFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        long start = System.currentTimeMillis();
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("Execute cost="+(System.currentTimeMillis()-start));
    }
}

执行结果是根据设置的优先级来的。

注意说明:使用@WebFilter注解的属性

属性名 类型 描述
filterName String 指定过滤器的 name 属性,等价于filter-name
value String[] 该属性等价于 urlPatterns 属性。但是两者不应该同时使用
urlPatterns String[] 指定一组过滤器的 URL 匹配模式。等价于 标签。
servletNames String[] 指定过滤器将应用于哪些 Servlet。取值是 @WebServlet 中的 name 属性的取值,或者是 web.xml 中 的取值。
dispatcherTypes DispatcherType 指定过滤器的转发模式。具体取值包括: ASYNC、ERROR、FORWARD、INCLUDE、REQUEST。
initParams WebInitParam[] 指定一组过滤器初始化参数,等价于 标签。
asyncSupported boolean 声明过滤器是否支持异步操作模式,等价于 标签。
description String 该过滤器的描述信息,等价于 标签。
displayName String 该过滤器的显示名,通常配合工具使用,等价于 标签。

执行顺序
比如:

encodingFilter.java

permissionFilter.java

先执行encodingFilter.java在执行permissionFilter.java

二、拦截器的配置

  • 首先我们实现拦截器类:
public class TestInterceptor implements HandlerInterceptor {
    long start = System.currentTimeMillis();
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        start = System.currentTimeMillis();
        return true;
    }
 
    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        System.out.println("Interceptor cost="+(System.currentTimeMillis()-start));
    }
 
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
    }
}


这里我们需要实现HandlerInterceptor这个接口,这个接口包括三个方法,

  1. preHandle是请求执行前执行的,
  2. postHandler是请求结束执行的,但只有preHandle方法返回true的时候才会执行,
  3. afterCompletion是视图渲染完成后才执行,同样需要preHandle返回true,该方法通常用于清理资源等工作。除了实现上面的接口外,我们还需对其进行配置:
@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter {
 
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new TestInterceptor()).addPathPatterns("/**");
        super.addInterceptors(registry);
    }
}

这里我们继承了WebMVCConfigurerAdapter,在进行静态资源目录配置的时候我们用到过这个类。这里我们重写了addInterceptors这个方法,进行拦截器的配置,主要配置项就两个,一个是指定拦截器第二个是指定拦截的URL。现在我们再启动系统访问任意一个URL即可。

posted @ 2022-01-14 17:47  烫手的山芋  阅读(715)  评论(0编辑  收藏  举报