过滤器

过滤器的定义

在客户端将请求发送到服务器端之前,拦截这些请求;在服务器端的响应返回给客户端之前,处理这些响应。
比如字符编码过滤器CharacterEncodingFilter,就是设置request和response中的字符编码方式。

过滤器的实现

方式一 利用WebFilter注解配置
@Slf4j
@WebFilter(filterName = "filter1", urlPatterns = {"/*"})
public class MyFirstFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("filter1 init method invoke....");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.info("filter1 doFilter method invoke....");
        //让过滤器继续往下执行
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        log.info("filter1 destroy method invoke....");
    }
}

在SpringBoot主程序类上添加Servlet组件扫描的注解@ServletComponentScan,运行程序即可看到控制台输出的init方法的调用输出内容,访问任意请求,都可以看到doFilter的方法内容输出。
以上代码可以实现过滤器的配置和使用,但是存在一个问题,当项目中有多个过滤器同时存在时,不能设置这些过滤器的执行顺序,需要借助FilterRegistrationBean类型的对象设置过滤器,可以再添加一个过滤器查看运行效果。

方式二:FilterRegistrationBean方式

将前面的两个过滤器类上的@WebFilter注解去掉,其他都不变,在项目中添加一个配置类专门针对过滤器配置,代码如下:

public class MyFilterRegistration {
    //注册第一个filter
    @Bean
    public FilterRegistrationBean registerMyFirstFilter() {
        FilterRegistrationBean  filterRegistrationBean = new FilterRegistrationBean();
        //注册Filter
        filterRegistrationBean.setFilter(new MyFirstFilter());
        //配置过滤器的名字
        filterRegistrationBean.setName("filter1");
        //配置过滤器过滤的url
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.setOrder(2);
        return filterRegistrationBean;
    }

    //注册第二个filter
    @Bean
    public FilterRegistrationBean registerMySecondFilter() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        //注册filter
        filterRegistrationBean.setFilter(new MySecondFilter());
        //配置过滤器的名字
        filterRegistrationBean.setName("filter2");
        //配置过滤器过滤的url
        filterRegistrationBean.addUrlPatterns("/*");
        //设置执行顺序
        filterRegistrationBean.setOrder(1);
        return filterRegistrationBean;
    }
}

在使用setOrder()方法可以设置多个过滤器的执行顺序,其中值越小,优先级越高。
其他代码不变,再看代码的运行效果,会发现,doFilter方式是先执行MySecondFilter再执行MyFirstFilter。

拦截器

拦截器的定义

在Servlet的规范中并没有拦截器的概念,是在Spring框架中衍生出来的。

拦截器的处理:

Springboot 过滤器 urlPatterns springboot过滤器执行顺序_拦截器


拦截器中有三个方法:

1、 preHandle:表示被拦截的URL 对应的控制层方法执行前的自定义处理逻辑

2、 postHandle:表示被拦截的URL对应的控制层方法执行后的自定义处理逻辑,此时还没有对ModelAndView进行渲染

3、 afterCompletion:表示此时ModelAndView已经做了页面渲染,执行拦截器的自定义处理逻辑。

拦截器的实现

添加一个类,实现HandlerInterceptor接口

@Slf4j
public class MyFirstInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("preHandle method invoke....");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("postHandle method invoke....");
        log.info("要跳转的页面是:" + modelAndView.getViewName());
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("afterCompletion method invoke....");
    }
}

接着,配置该拦截器,在之前写的WebMvcConfigurer接口的实现类中添加拦截器的注册信息:

`

Springboot 过滤器 urlPatterns springboot过滤器执行顺序_ide_02

拦截器和过滤器的区别

从请求处理的生命周期上看,拦截器和过滤器的作用是类似的,区别是:

过滤器使用的是Filter接口,实现的是init、doFilter和destroy方法

拦截器使用的是HandlerInterceptor接口,实现的是preHandle、postHandle、afterCompletion方法。

过滤器和拦截器的执行位置

Springboot 过滤器 urlPatterns springboot过滤器执行顺序_ide_03


过滤器和拦截器的使用场景:

规范不同的:Filter是Servlet规范中定义的组件,在Servlet容器内生效,而拦截器时Spring框架定义的,在Spring上下文中生效;

拦截器可以获取并使用Spring IOC容器中的bean,但过滤器不行。

拦截器可以访问Spring上下文值对象,如ModelAndView,过滤器不行。

过滤器的力度比拦截器的力度大,因为过滤器是在进入Servlet容器之前处理请求,拦截器则是在进入到Servlet容器之内处理请求,过滤器比较适合系统级别的处理动作,比如权限认证之类的。

拦截器比过滤器力度小,更适合分模块、分范围的统一业务逻辑处理。