过滤器Filter详解
在 Java Web 开发中,你是否遇到过这样的需求:
✅ 用户必须登录才能访问订单页面✅ 所有请求统一设置 UTF-8 编码避免乱码✅ 记录每个请求的访问日志用于审计✅ 防止跨站脚本攻击(XSS)✅ 响应数据压缩以提升性能这些看似分散的功能,其实都可以通过一个强大的机制统一实现:Filter(过滤器)。
🔐 Filter 就像网站的“保安”或“安检门”,它在请求到达业务逻辑之前、响应返回客户端之前,进行拦截、检查、处理,是构建安全、高效 Web 应用的基石。
一、什么是 Filter?Filter 是 Java Servlet 规范中定义的一个接口(javax.servlet.Filter),用于对进入 Web 应用的 请求(Request) 和 响应(Response) 进行预处理和后处理。
核心能力:✅ 拦截所有匹配路径的 HTTP 请求✅ 在请求到达 Servlet 之前进行处理(如:登录校验、编码设置)✅ 在响应返回客户端之前进行处理(如:压缩、添加头信息)✅ 可以放行请求,也可以直接拦截并返回响应(如:跳转登录页)二、Filter 的核心作用作用
典型场景
权限控制
登录校验、角色权限验证
编码处理
统一设置请求/响应字符编码(UTF-8)
日志记录
记录请求路径、IP、耗时等
安全防护
XSS 过滤、CSRF 防护、IP 黑名单
性能优化
响应压缩(GZIP)、缓存控制
请求改造
修改请求头、包装 Request
响应改造
修改响应头、包装 Response
三、Filter 的生命周期(由 Servlet 容器管理)Filter 的生命周期由 Web 容器(如 Tomcat)控制,分为四个阶段:
阶段
方法
调用时机
调用次数
实例化
构造函数
容器启动时
1 次
初始化
init(FilterConfig config)
实例化后
1 次
过滤处理
doFilter(ServletRequest, ServletResponse, FilterChain)
每次请求匹配时
N 次
销毁
destroy()
容器关闭时
1 次
💡 类比:就像保安的上班流程:打卡(构造)→ 接收任务(init)→ 检查人员(doFilter)→ 下班(destroy)
四、Filter 核心接口详解1. javax.servlet.Filter所有过滤器必须实现的接口,定义三个核心方法:
代码语言:java复制public interface Filter {
void init(FilterConfig config) throws ServletException;
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;
void destroy();
}2. FilterChain:过滤器链多个 Filter 按顺序组成一条“过滤链”chain.doFilter(request, response) 是放行请求的关键调用后,请求进入下一个 Filter 或目标资源不调用,则请求被拦截3. FilterConfig提供 Filter 的配置信息可获取初始化参数(init-param)可获取 Filter 名称、ServletContext 等五、如何实现一个 Filter?步骤 1:创建 Filter 类代码语言:java复制import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 初始化:读取配置参数
String encoding = filterConfig.getInitParameter("encoding");
System.out.println("Filter 初始化,编码:" + encoding);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
System.out.println("👉 请求拦截: " + req.getRequestURI());
// ✅ 预处理:例如设置编码
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
// 🔁 放行请求(关键!)
chain.doFilter(request, response);
// ✅ 后处理:例如记录响应
System.out.println("👈 响应完成: " + response.getContentType());
}
@Override
public void destroy() {
System.out.println("🔒 Filter 销毁,释放资源");
}
}六、Filter 的配置方式方式 1:web.xml 配置(传统方式)代码语言:xml复制
方式 2:@WebFilter 注解(Servlet 3.0+)代码语言:java复制import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
@WebFilter(
filterName = "myFilter",
urlPatterns = {"/api/*", "/user/*"},
initParams = {
@WebInitParam(name = "encoding", value = "UTF-8")
}
)
public class MyFilter implements Filter {
// ...
}方式 3:Spring Boot 中使用 @Component + @WebFilter代码语言:java复制import org.springframework.stereotype.Component;
import javax.servlet.annotation.WebFilter;
@Component
@WebFilter(urlPatterns = "/*", filterName = "logFilter")
public class LogFilter implements Filter {
// ...
}✅ Spring Boot 注意:需在启动类上添加 @ServletComponentScan
代码语言:java复制@SpringBootApplication
@ServletComponentScan // 启用 @WebFilter 扫描
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}七、Filter 拦截路径配置拦截模式
示例
说明
精确匹配
/login
只拦截 /login
目录匹配
/api/*
拦截 /api/ 下所有路径
后缀匹配
*.jsp
拦截所有 .jsp 文件
全部拦截
/*
拦截所有请求(慎用)
⚠️ 注意:多个路径可用数组配置:
java深色版本@WebFilter(urlPatterns = {"/api/*", "/user/*"})
八、Filter 执行流程(多 Filter 链)当多个 Filter 拦截同一请求时,形成 Filter Chain,执行顺序如下:
代码语言:javascript代码运行次数:0运行复制客户端请求
↓
[Filter 1] → doFilter() → 预处理
↓
[Filter 2] → doFilter() → 预处理
↓
... 更多 Filter
↓
[目标资源] → Servlet / Controller
↓
[Filter 2] ← 后处理 ← doFilter() 返回
↓
[Filter 1] ← 后处理 ← doFilter() 返回
↓
响应返回客户端执行顺序规则:注解方式:按 类名的字母顺序 升序执行(如 AFilter → BFilter)web.xml 方式:按
九、实战案例:登录校验 Filter需求:用户访问 /order/* 下的接口必须登录,否则跳转登录页。
实现:代码语言:java复制@Component
@WebFilter(urlPatterns = "/order/*", filterName = "authFilter")
public class AuthFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
// 获取会话中的用户
Object user = req.getSession().getAttribute("user");
if (user == null) {
// ❌ 未登录,拦截并跳转
System.out.println("🚫 未登录,跳转登录页");
res.sendRedirect("/login");
return; // 阻止继续执行
}
// ✅ 已登录,放行
System.out.println("✅ 用户已登录,放行请求");
chain.doFilter(request, response);
}
}流程图解:代码语言:javascript代码运行次数:0运行复制请求 /order/create
↓
AuthFilter 检查 session
↓
用户存在? → 是 → 放行 → OrderController
↓
← 否 → 重定向 /login十、Filter vs Interceptor vs AOP特性
Filter
Interceptor
AOP
所属层级
Servlet 容器
Spring MVC
Spring AOP
拦截范围
所有 Web 请求(包括静态资源)
仅 Controller 请求
任意方法调用
依赖框架
Servlet API
Spring MVC
Spring AOP
执行时机
最早(进入 DispatcherServlet 前)
进入 Controller 前
方法调用前后
适用场景
编码、安全、日志
权限、日志、性能监控
事务、日志、缓存
✅ 推荐组合使用:
Filter:全局编码、安全过滤Interceptor:业务权限、接口日志AOP:事务管理、方法级监控十一、常见面试题1. chain.doFilter() 的作用是什么?是放行请求的关键。调用后,请求进入下一个 Filter 或目标资源。不调用则请求被拦截。
2. Filter 的 init() 和 destroy() 方法调用几次?各调用 1 次,由容器管理生命周期。
3. 多个 Filter 的执行顺序如何控制?注解方式:类名字母顺序web.xml:按
5. 如何在 Filter 中修改请求体?需要包装 ServletRequest,继承 HttpServletRequestWrapper,重写 getReader() 或 getInputStream()。
十二、总结关键点
说明
Filter 是 Web 安全的第一道防线
拦截非法请求,保护核心资源
生命周期由容器管理
init → doFilter × N → destroy
chain.doFilter() 是放行关键
不调用则请求终止
Spring Boot 中使用 @Component + @WebFilter
配合 @ServletComponentScan
多 Filter 按顺序执行
形成“责任链”模式
适合做全局性、非业务性处理
编码、日志、安全、压缩
结语Filter 是 Java Web 开发中不可或缺的组件,它让你能够在不修改业务代码的前提下,为整个应用添加横切关注点(Cross-Cutting Concerns)。
🔑 核心思想:关注点分离 —— 业务逻辑归业务,安全、日志、编码归 Filter。
掌握 Filter,你就能为你的 Web 应用装上一把坚固的“安全锁”,让系统更安全、更稳定、更易维护。