1. Filter 介绍

Filter 过滤器这个概念应该大家不会陌生,特别是对与从 Servlet 开始入门学 Java 后台的同学来说。那么这个东西我们能做什么呢?Filter 过滤器主要是用来过滤用户请求的,它允许我们对用户请求进行前置处理和后置处理,比如实现 URL 级别的权限控制、过滤非法请求等等。Filter 过滤器是面向切面编程——AOP 的具体实现(AOP切面编程只是一种编程思想而已)。

另外,Filter 是依赖于 Servlet 容器,接口就在 Servlet 包下面,属于 Servlet 规范的一部分。所以,很多时候我们也称其为“增强版 Servlet”。Filter

如果我们需要自定义 Filter 的话非常简单,只需要实现 接口,然后重写里面的 3 个方法即可!

jakarta.Servlet.Filter

public interface Filter {
    default void init(FilterConfig filterConfig) throws ServletException {
    }

    void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;

    default void destroy() {
    }
}

2. Filter是如何实现拦截的?

Filter接口中有一个叫做 doFilter 的方法,这个方法实现了对用户请求的过滤。具体流程大体是这样的:doFilter

  1. 用户发送请求到 web 服务器,请求会先到过滤器;
  2. 过滤器会对请求进行一些处理,比如过滤请求的参数、修改返回给客户端的 response 的内容、判断是否让用户访问该接口等等。
  3. 用户请求响应完毕。
  4. 进行一些自己想要的其他操作。

3. 如何自定义Filter

下面提供两种方法。

3.1自己手动注册配置实现

自定义的 Filter 需要实现javax.Servlet.Filter接口,并重写接口中定义的3个方法。

@Component
public class MyFilter implements Filter {
    private static final Logger logger = LoggerFactory.getLogger(MyFilter.class);
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        logger.info("初始化过滤器:", filterConfig.getFilterName());
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        logger.info("执行过滤器:");
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String requestURI = request.getRequestURI();
        logger.info("请求地址:{}", requestURI);
        long startTime = System.currentTimeMillis();
        //通过doFilter实现过滤功能
        filterChain.doFilter(servletRequest, servletResponse);
        // 上面的 doFilter 方法执行结束后用户的请求已经返回
        long endTime = System.currentTimeMillis();
        System.out.println("该用户的请求已经处理完毕,请求花费的时间为:" + (endTime - startTime));

    }

    @Override
    public void destroy() {
        logger.info("销毁过滤器");
        Filter.super.destroy();
    }
}

3.2 在配置中注册自定义的过滤器。

@Configuration
public class MyFilterConfig {

    @Autowired
    private MyFilter myFilter;
    @Bean
    public FilterRegistrationBean<MyFilter> registerMyFilter(){
        FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(myFilter);
        registrationBean.setOrder(1);
        registrationBean.addUrlPatterns("/user/*");
        return registrationBean;
    }

}

在Spring Boot项目中,如果你使用的是Spring Boot 2.0及以上版本,那么你不需要显式地注册过滤器。Spring Boot会自动扫描并注册所有实现了Filter接口的Bean。

然而,如果你需要自定义过滤器的URL模式,或者你需要使用Spring Boot提供的过滤器,但是需要对其进行一些配置,那么你可能需要显式地注册过滤器。

4.定义多个拦截器,并决定它们的执行顺序

假如我们现在又加入了一个过滤器怎么办?

MyFilter2.java

@Component
public class MyFilter1 implements Filter {
    private static final Logger logger = LoggerFactory.getLogger(MyFilter1.class);
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        logger.info("初始化过滤器1:", filterConfig.getFilterName());
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        logger.info("执行过滤器1:");
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String requestURI = request.getRequestURI();
        logger.info("请求地址1:{}", requestURI);
        long startTime = System.currentTimeMillis();
        //通过doFilter实现过滤功能
        filterChain.doFilter(servletRequest, servletResponse);
        // 上面的 doFilter 方法执行结束后用户的请求已经返回
        long endTime = System.currentTimeMillis();
        System.out.println("该用户的请求已经处理完毕1,请求花费的时间为:" + (endTime - startTime));

    }

    @Override
    public void destroy() {
        logger.info("销毁过滤器1");
        Filter.super.destroy();
    }
}

在配置中注册自定义的过滤器,通过 FilterRegistrationBean 的setOrder 方法可以决定 Filter 的执行顺序。

@Configuration
public class MyFilterConfig {

    @Autowired
    private MyFilter myFilter;
    @Autowired
    private MyFilter1 myFilter1;
    @Bean
    public FilterRegistrationBean<MyFilter> registerMyFilter(){
        FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(myFilter);
        registrationBean.setOrder(1);
        registrationBean.addUrlPatterns("/user/*");
        return registrationBean;
    }
    @Bean
    public FilterRegistrationBean<MyFilter1> registerMyFilter1(){
        FilterRegistrationBean<MyFilter1> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(myFilter1);
        registrationBean.setOrder(2);
        registrationBean.addUrlPatterns("/user/*");
        return registrationBean;
    }
}

自定义 Controller 验证过滤器

@RestController
@RequestMapping("/user")
public class MyController {

    @GetMapping("/hello")
    public String getHello() throws InterruptedException {
        Thread.sleep(1000);
        return "Hello";
    }
}

实际测试效果如下:

2025-05-08T10:48:52.844+08:00  INFO 17400 --- [nio-8080-exec-1] com.example.datasource.filter.MyFilter   : 执行过滤器:
2025-05-08T10:48:52.844+08:00  INFO 17400 --- [nio-8080-exec-1] com.example.datasource.filter.MyFilter   : 请求地址:/user/query
2025-05-08T10:48:52.844+08:00  INFO 17400 --- [nio-8080-exec-1] c.example.datasource.filter.MyFilter1    : 执行过滤器1:
2025-05-08T10:48:52.844+08:00  INFO 17400 --- [nio-8080-exec-1] c.example.datasource.filter.MyFilter1    : 请求地址1:/user/query
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@d054dab] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@684707086 wrapping com.mysql.cj.jdbc.ConnectionImpl@12a30b53] will not be managed by Spring
==>  Preparing: select * from user where name=?
==> Parameters: jq(String)
<==    Columns: id, name, age, money
<==        Row: 4, jq, 23, 2222.0
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@d054dab]
该用户的请求已经处理完毕1,请求花费的时间为:73
该用户的请求已经处理完毕,请求花费的时间为:73
分类: SpringBoot

0 条评论

发表回复

Avatar placeholder

您的邮箱地址不会被公开。 必填项已用 * 标注