Filter、FilterChain、FilterConfig 介绍
在Java Web开发中,Filter
、FilterChain
和 FilterConfig
是Servlet API中的核心组件,用于处理HTTP请求和响应的预处理或后处理任务。它们在Java EE(现为Jakarta EE)中广泛用于拦截和修改请求/响应,常见于Web应用程序的过滤器机制(如权限验证、日志记录、编码设置等)。以下是对它们的详细介绍:
1. Filter
定义
Filter
(过滤器)是一个接口,定义在 javax.servlet
包中,用于在请求到达Servlet/JSP或响应返回客户端之前,对请求和响应进行拦截和处理。过滤器可以执行预处理(如验证用户权限)、后处理(如压缩响应)或记录日志等任务。
作用
- 拦截请求:在请求到达Servlet之前修改或验证请求数据。
- 处理响应:在响应返回客户端之前修改或格式化响应数据。
- 应用场景:
- 字符编码设置(防止乱码)。
- 用户认证和授权。
- 日志记录。
- 数据压缩、加密。
- 防XSS攻击或SQL注入。
核心方法
Filter
接口定义了以下三个方法:
public interface Filter {
void init(FilterConfig filterConfig) throws ServletException;
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException;
void destroy();
}
init(FilterConfig filterConfig)
:- 在过滤器初始化时调用(Web容器启动时)。
- 用于加载配置参数或初始化资源。
- 只调用一次。
doFilter(ServletRequest, ServletResponse, FilterChain)
:- 核心方法,每次请求/响应经过过滤器时调用。
- 包含过滤逻辑,处理请求/响应。
- 调用
chain.doFilter(request, response)
将请求传递给下一个过滤器或目标资源。 destroy()
:- 在过滤器销毁时调用(Web容器关闭时)。
- 用于释放资源。
- 只调用一次。
示例:字符编码过滤器
import javax.servlet.*;
import java.io.IOException;
public class CharacterEncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 初始化代码
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
request.setCharacterEncoding("UTF-8"); // 设置请求编码
response.setCharacterEncoding("UTF-8"); // 设置响应编码
chain.doFilter(request, response); // 继续处理请求
}
@Override
public void destroy() {
// 清理资源
}
}
2. FilterChain
定义
FilterChain
是一个接口,定义在 javax.servlet
包中,表示过滤器链,负责管理多个过滤器的执行顺序并将请求传递给下一个过滤器或最终的Servlet。
作用
- 维护过滤器的执行顺序(根据
web.xml
或注解的配置顺序)。 - 提供
doFilter
方法,将请求/响应传递给链中的下一个过滤器或目标资源(如Servlet、JSP)。 - 如果链中没有更多过滤器,请求将到达目标资源。
核心方法
public interface FilterChain {
void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException;
}
doFilter(ServletRequest, ServletResponse)
:- 调用后将请求/响应传递给下一个过滤器或目标资源。
- 如果不调用此方法,请求将被拦截,不会继续传递。
工作原理
- Web容器根据配置(如
web.xml
或@WebFilter
)按顺序组装过滤器链。 - 每个过滤器的
doFilter
方法通过调用chain.doFilter
将控制权交给下一个过滤器。 - 如果链中所有过滤器都处理完毕,请求到达目标Servlet。
示例:过滤器链
假设有两个过滤器 Filter1
和 Filter2
,配置顺序为 Filter1 -> Filter2 -> Servlet
:
public class Filter1 implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("Filter1: Before");
chain.doFilter(request, response); // 传递给 Filter2
System.out.println("Filter1: After");
}
}
public class Filter2 implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("Filter2: Before");
chain.doFilter(request, response); // 传递给 Servlet
System.out.println("Filter2: After");
}
}
执行顺序:
- Filter1: Before
- Filter2: Before
- Servlet 处理
- Filter2: After
- Filter1: After
3. FilterConfig
定义
FilterConfig
是一个接口,定义在 javax.servlet
包中,用于在过滤器初始化时提供配置信息(如初始化参数、Servlet上下文等)。
作用
- 提供过滤器的配置参数(如
web.xml
中定义的<init-param>
)。 - 提供对
ServletContext
的访问,用于获取Web应用的全局信息。 - 传递过滤器的名称。
核心方法
public interface FilterConfig {
String getFilterName(); // 获取过滤器名称
ServletContext getServletContext(); // 获取 ServletContext
String getInitParameter(String name); // 获取指定初始化参数
Enumeration<String> getInitParameterNames(); // 获取所有初始化参数名
}
配置示例
在 web.xml
中配置过滤器和初始化参数:
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>com.example.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
使用 FilterConfig
在过滤器的 init
方法中获取配置参数:
public class CharacterEncodingFilter implements Filter {
private String encoding;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
encoding = filterConfig.getInitParameter("encoding"); // 获取参数
if (encoding == null) {
encoding = "UTF-8"; // 默认值
}
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
request.setCharacterEncoding(encoding);
response.setCharacterEncoding(encoding);
chain.doFilter(request, response);
}
@Override
public void destroy() {
// 清理资源
}
}
4. 配置过滤器
过滤器可以通过以下两种方式配置:
4.1 使用 web.xml
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>com.example.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/*</url-pattern> <!-- 拦截所有请求 -->
</filter-mapping>
4.2 使用注解(Servlet 3.0+)
import javax.servlet.annotation.WebFilter;
@WebFilter(filterName = "MyFilter", urlPatterns = "/*")
public class MyFilter implements Filter {
// 实现方法
}
5. 实际应用场景
- 字符编码统一:使用
Filter
设置所有请求/响应的字符编码为 UTF-8。 - 权限验证:检查用户是否登录,未登录则重定向到登录页面。
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpSession session = req.getSession();
if (session.getAttribute("user") == null) {
((HttpServletResponse) response).sendRedirect("/login");
} else {
chain.doFilter(request, response);
}
}
- 日志记录:记录每个请求的URL和时间。
- 请求过滤:防止SQL注入或XSS攻击,通过检查请求参数。
6. 注意事项
- 执行顺序:过滤器按
web.xml
或注解中定义的顺序执行。 - 线程安全:过滤器是单例的,
doFilter
方法可能被多个线程并发调用,需确保线程安全。 - 性能:避免在过滤器中执行耗时操作,以免影响请求处理效率。
- 兼容性:
Filter
是Servlet规范的一部分,适用于所有支持Servlet的容器(如Tomcat、Jetty)。
7. 总结
Filter
:用于拦截和处理请求/响应,核心是doFilter
方法。FilterChain
:管理多个过滤器的执行顺序,传递请求给下一个过滤器或目标资源。FilterConfig
:提供过滤器的配置信息,如初始化参数和Servlet上下文。
如果需要更详细的代码示例(如权限验证过滤器)或某个具体场景的实现,请告诉我!