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
- 用户发送请求到 web 服务器,请求会先到过滤器;
- 过滤器会对请求进行一些处理,比如过滤请求的参数、修改返回给客户端的 response 的内容、判断是否让用户访问该接口等等。
- 用户请求响应完毕。
- 进行一些自己想要的其他操作。
3. 如何自定义Filter
下面提供两种方法。
自定义的 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
0 条评论