SpringBoot_Filter过滤器

Published by jwq on

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

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

Optimized by Optimole