阅读 29

SpringBoot项目实战经验之Filter实现自定义过滤器

此文章已同步更新至我的个人博客simonting.gitee.io

Servlet包中提供了Filter接口供我们实现自定义过滤器。

自定义拦截器可以参考我之前的文章

与之不同的是,拦截器是Spring框架提供的功能,而Filter过滤器是Servlet提供的。下面是拦截器与过滤器的一些主要区别:

  • Filter由Servlet包提供,只能用于Web应用,不能使用Spring容器资源;拦截器由Spring提供,既能用于Web应用,也能用于Application和Swing应用,能使用Spring容器资源。
  • Filter只能在Servlet的前后起作用;而拦截器能深入到方法前后、异常抛出前后。
  • Filter基于函数回调;拦截器基于java的反射机制。
  • ......

实现自定义过滤器

  • 1、实现Filter接口,自定义过滤器
  • 2、注册过滤器

我们可以定义多个过滤器,形成一个过滤链,执行的顺序可以在注册的时候设置优先级,优先级的数字越小优先级越大

自定义过滤器

定义过滤器1

/**
 * @Author zhangting
 * @Desc 自定义过滤器1
 * @Date 2020/08/04
 **/
@Slf4j
public class MyFilter1 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // web应用程序启动时,web服务器将创建Filter的实例对象,并调用init方法,完成对象的初始化功能,此方法只执行一次。
        log.info("----- init filter1 -----");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 实际的过滤操作
        log.info("----- doFilter1 -----");
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
        // 模拟测试
        httpRequest.setAttribute("name", "zhangting");
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        // Filter对象床创建后会驻留在内存,当web应用移除或服务器停止时才会销毁,此方法只执行一次。
        log.info("----- destroy filter1 -----");
    }
}
复制代码

定义过滤器2

/**
 * @Author zhangting
 * @Desc 自定义过滤器2
 * @Date 2020/08/04
 **/
@Slf4j
public class MyFilter2 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // web应用程序启动时,web服务器将创建Filter的实例对象,并调用init方法,完成对象的初始化功能,此方法只执行一次。
        log.info("----- init filter2 -----");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 实际的过滤操作
        log.info("----- doFilter2 -----");
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
        // 模拟测试
        httpRequest.setAttribute("city", "nanjing");
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        // Filter对象床创建后会驻留在内存,当web应用移除或服务器停止时才会销毁,此方法只执行一次。
        log.info("----- destroy filter2 -----");
    }
}
复制代码

注册过滤器

编写一个javaconfig类来注册过滤器

/**
 * @Author zhangting
 * @Desc 注册过滤器
 * @Date 2020/08/04
 **/
@Slf4j
@Configuration
public class FilterConfig {

    @Bean
    @Primary
    public FilterRegistrationBean<MyFilter1> registerMyFilter1() {
        log.info("register MyFilter1...");
        FilterRegistrationBean<MyFilter1> filterRegistrationBean = new FilterRegistrationBean<MyFilter1>();
        // 注册
        filterRegistrationBean.setFilter(new MyFilter1());
        // 设置需要过滤的URL,不设置则默认为全部
        filterRegistrationBean.addUrlPatterns("/v1/filter");
        filterRegistrationBean.setName("myFilter1");
        // 设置优先级,数字越小优先级越大
        filterRegistrationBean.setOrder(1);
        return filterRegistrationBean;
    }

    @Bean
    public FilterRegistrationBean<MyFilter2> registerMyFilter2() {
        log.info("register MyFilter2...");
        FilterRegistrationBean<MyFilter2> filterRegistrationBean = new FilterRegistrationBean<MyFilter2>();
        // 注册
        filterRegistrationBean.setFilter(new MyFilter2());
        // 设置需要过滤的URL,不设置则默认为全部
        filterRegistrationBean.addUrlPatterns("/v1/filter");
        filterRegistrationBean.setName("myFilter2");
        // 设置优先级,数字越小优先级越大
        filterRegistrationBean.setOrder(2);
        return filterRegistrationBean;
    }
}
复制代码

测试

编写测试类

@Slf4j
@RestController
@RequestMapping("/v1")
public class TestController {

    @GetMapping("/filter")
    public ResponseEntity<?> filter(HttpServletRequest request) {
        Map<String, String> map = new HashMap<>();
        // 在过滤器1中往request中塞了一个name,在过滤器2中往request中塞了一个city
        map.put("name", request.getAttribute("name").toString());
        map.put("city", request.getAttribute("city").toString());
        return new ResponseEntity<>(map, HttpStatus.OK);
    }
}
复制代码

启动服务,两个过滤器会在启动的时候进行注册及调用init方法对过滤器进行初始化。 使用postman对/v1/filter接口发起请求 查看日志可以得知,过滤器按照我们设置的执行顺序执行,先执行过滤器1,再执行过滤器2 我们在过滤器1、2中添加的测试值成功的返回到了前台,测试成功