Appearance
J2EE_008 Filter 笔记
目录
1. Filter 简介
Filter(过滤器) 是 Java Web 的核心组件之一,用于在 请求到达 Servlet 前 或 响应返回客户端前 对请求/响应进行预处理或后处理。
- 核心功能:拦截请求和响应,实现通用逻辑(如权限校验、日志记录、编码转换等)。
- 设计模式:责任链模式(多个 Filter 按顺序处理同一个请求)。
- 典型应用场景:
- 统一设置请求编码(解决中文乱码)
- 权限控制(登录校验、角色校验)
- 日志记录(记录请求耗时、请求参数)
- 敏感词过滤(替换响应内容)
2. Filter 核心API
接口/类 | 核心方法 | 说明 |
---|---|---|
javax.servlet.Filter | init(FilterConfig) doFilter(ServletRequest, ServletResponse, FilterChain) destroy() | Filter 接口定义的生命周期方法 |
FilterConfig | getInitParameter(String) | 获取 Filter 初始化参数 |
FilterChain | doFilter(ServletRequest, ServletResponse) | 调用链,决定是否放行到下一个 Filter/Servlet |
3. Filter 创建与配置
方式1: 注解配置(Servlet 3.0+)
java
@WebFilter(
urlPatterns = "/*", // 拦截路径(支持通配符)
initParams = { @WebInitParam(name = "charset", value = "UTF-8") } // 初始化参数
)
public class EncodingFilter implements Filter {
private String charset;
@Override
public void init(FilterConfig config) {
charset = config.getInitParameter("charset"); // 获取初始化参数
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
req.setCharacterEncoding(charset);
resp.setContentType("text/html;charset=" + charset);
chain.doFilter(req, resp); // 放行请求
}
@Override
public void destroy() {}
}
方式2: web.xml 配置
xml
<!-- 声明 Filter -->
<filter>
<filter-name>AuthFilter</filter-name>
<filter-class>com.example.AuthFilter</filter-class>
<init-param>
<param-name>excludePages</param-name>
<param-value>/login,/register</param-value>
</init-param>
</filter>
<!-- 配置 Filter 拦截路径 -->
<filter-mapping>
<filter-name>AuthFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher> <!-- 拦截类型:REQUEST, FORWARD, ERROR 等 -->
</filter-mapping>
4. Filter 生命周期
- 初始化阶段:
- 当 Web 应用启动时,容器调用
init()
方法,仅执行一次。 - 通过
FilterConfig
获取初始化参数。
- 当 Web 应用启动时,容器调用
- 拦截处理阶段:
- 每次请求匹配拦截路径时,执行
doFilter()
方法。
- 每次请求匹配拦截路径时,执行
- 销毁阶段:
- 当 Web 应用关闭时,容器调用
destroy()
方法,释放资源。
- 当 Web 应用关闭时,容器调用
5. Filter 执行流程
客户端请求 → Tomcat 容器 → Filter1 → Filter2 → ... → Servlet →
响应生成 → Filter2 → Filter1 → 客户端
- 关键点:
chain.doFilter(req, resp)
表示将请求传递给下一个 Filter 或目标 Servlet。- 若某个 Filter 未调用
chain.doFilter()
,则请求终止,响应直接返回客户端。
6. Filter 常见应用场景
场景1:全局编码过滤器
java
public void doFilter(...) {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
chain.doFilter(req, resp);
}
场景2:登录权限校验
java
public void doFilter(...) {
HttpServletRequest request = (HttpServletRequest) req;
HttpSession session = request.getSession(false);
if (session == null || session.getAttribute("user") == null) {
resp.getWriter().write("请先登录!");
return;
}
chain.doFilter(req, resp);
}
场景3:接口耗时统计
java
public void doFilter(...) {
long start = System.currentTimeMillis();
chain.doFilter(req, resp);
long end = System.currentTimeMillis();
System.out.println("请求耗时:" + (end - start) + "ms");
}
7. Filter 执行顺序控制
- 规则1:
web.xml
中<filter-mapping>
的声明顺序决定 Filter 执行顺序。 - 规则2:使用注解配置时,顺序不可控,可通过
@Order
注解(部分框架支持)或改为 XML 配置。 - 强制顺序示例(web.xml):xml
<filter-mapping><filter-name>FilterA</...></filter-mapping> <filter-mapping><filter-name>FilterB</...></filter-mapping> <!-- 执行顺序:FilterA → FilterB -->
8. Filter 高级特性
1. 动态拦截路径
通过 HttpServletRequest
判断请求路径,实现动态拦截:
java
String path = ((HttpServletRequest) req).getRequestURI();
if (path.startsWith("/admin")) {
// 执行管理员权限校验
}
2. 包装请求/响应对象
通过 ServletRequestWrapper
和 ServletResponseWrapper
修改请求参数或响应内容:
java
public void doFilter(...) {
// 包装请求对象,修改参数
ServletRequest wrappedReq = new HttpServletRequestWrapper((HttpServletRequest) req) {
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
return value == null ? "" : value.trim(); // 自动去除参数空格
}
};
chain.doFilter(wrappedReq, resp);
}
3. 异步处理支持(Servlet 3.0+)
在 Filter 中处理异步请求:
java
public void doFilter(...) {
AsyncContext asyncContext = req.startAsync();
asyncContext.start(() -> {
// 异步处理逻辑
asyncContext.complete();
});
}
9. 常见问题
Q1:Filter 不生效可能原因?
- 拦截路径配置错误(如
urlPatterns
未匹配到请求路径)。 - 未调用
chain.doFilter()
导致请求终止。 - Filter 类未正确配置(如
web.xml
中类名拼写错误)。
Q2:如何排除某些路径不过滤?
在 Filter 的 doFilter()
方法中判断请求路径并放行:
java
String path = ((HttpServletRequest) req).getRequestURI();
if (path.startsWith("/static") || path.equals("/login")) {
chain.doFilter(req, resp);
return;
}
Q3:Filter 与 Spring Interceptor 的区别?
Filter | Interceptor |
---|---|
Servlet 规范组件 | Spring 框架组件 |
依赖 Servlet 容器 | 依赖 Spring 容器 |
可拦截所有请求(包括静态资源) | 只能拦截 Controller 层的请求 |
总结
Filter 是 Java Web 开发中实现 横切关注点 的核心技术,通过统一处理请求和响应,可大幅提升代码复用性和可维护性。合理使用 Filter 能有效解决编码、安全、日志等共性问题。