什么是Filter过滤器?
Filter是Java Servlet规范中的一部分,用于拦截和过滤请求与响应,通常用于在目标Servlet执行之前或之后执行特定逻辑。它可以在不改变目标资源逻辑的情况下,增强功能或添加通用处理逻辑。
常见用途包括:
- 权限校验:检查用户是否已登录或具备权限。
- 编码处理:解决请求和响应的字符编码问题。
- 日志记录:记录用户的请求信息、访问日志等。
- 防止重复提交:防止用户重复提交表单数据。
- 跨域支持:添加跨域资源共享(CORS)相关头信息。
Filter的基本结构
Filter必须实现jakarta.servlet.Filter
接口,核心方法包括:
-
init(FilterConfig filterConfig)
初始化方法,在过滤器实例创建后调用一次。常用于初始化资源。 -
doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
核心方法,每次拦截请求时调用。此方法中可以定义过滤逻辑,通过调用chain.doFilter(request, response)
来放行请求。 -
destroy()
销毁方法,在过滤器被移除或服务器关闭时调用一次,用于释放资源。
Filter的配置
过滤器可以通过两种方式进行配置:
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>
2. 使用注解配置
通过@WebFilter
注解配置:
@WebFilter(urlPatterns = "/*")
public class MyFilter implements Filter {
// 实现方法
}
Filter的执行原理
- 当用户发起请求时,Servlet容器会根据请求路径匹配到相应的过滤器。
- 如果有多个过滤器匹配到同一个请求,按照配置的顺序依次执行。
- 在每个过滤器的
doFilter
方法中,是否执行目标Servlet取决于是否调用chain.doFilter(request, response)
。
Filter的生命周期
- 实例化:在服务器启动时,根据
web.xml
或注解配置创建Filter实例。 - 初始化:调用
init
方法,完成初始化操作。 - 请求过滤:每次请求调用
doFilter
方法。 - 销毁:在服务器关闭或应用程序卸载时,调用
destroy
方法释放资源。
Filter的匹配规则
精确匹配
匹配特定路径:
<url-pattern>/specificPath</url-pattern>
后缀匹配
匹配特定后缀:
<url-pattern>*.do</url-pattern>
前缀匹配
匹配路径前缀:
<url-pattern>/api/*</url-pattern>
全局匹配
匹配所有请求:
<url-pattern>/*</url-pattern>
Filter的优点
- 解耦合:将公共逻辑从Servlet中分离,便于维护。
- 复用性:公共逻辑只需编写一次,适用于多个Servlet。
- 灵活性:可以动态调整过滤器的顺序,实现运行时行为变化。
Filter在项目中的应用
场景1:用户登录校验
在OA项目中,所有的业务操作都要求用户先登录。可以通过Filter实现统一校验,避免每个Servlet重复编写代码。
示例代码:
@WebFilter(urlPatterns = "/*")
public class LoginFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// 从Session中获取用户信息
Object user = httpRequest.getSession().getAttribute("user");
if (user == null) {
// 未登录,重定向到登录页面
httpResponse.sendRedirect(httpRequest.getContextPath() + "/login.jsp");
} else {
// 已登录,放行请求
chain.doFilter(request, response);
}
}
}
场景2:统一编码设置
为了解决字符编码问题,可以在Filter中统一设置请求和响应的编码格式:
@WebFilter(urlPatterns = "/*")
public class EncodingFilter implements Filter {
@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);
}
}
场景3:记录请求日志
通过Filter记录用户的请求信息,便于后续分析和排查问题:
@WebFilter(urlPatterns = "/*")
public class LoggingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String uri = httpRequest.getRequestURI();
String ip = request.getRemoteAddr();
System.out.println("Request URI: " + uri + ", IP: " + ip);
chain.doFilter(request, response);
}
}
Filter的高级应用
责任链模式
Filter天然符合责任链设计模式:请求经过一系列过滤器处理,最终到达目标Servlet。可以动态调整过滤器的执行顺序,实现灵活扩展。
示例:多个过滤器处理请求
@WebFilter(urlPatterns = "/api/*")
public class FilterA implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("FilterA: Before");
chain.doFilter(request, response);
System.out.println("FilterA: After");
}
}
@WebFilter(urlPatterns = "/api/*")
public class FilterB implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("FilterB: Before");
chain.doFilter(request, response);
System.out.println("FilterB: After");
}
}
输出顺序:
FilterA: Before
FilterB: Before
FilterB: After
FilterA: After
改造OA项目的步骤
- 创建登录校验过滤器:验证用户是否登录,未登录则重定向到登录页面。
- 创建编码设置过滤器:统一设置请求和响应的字符编码。
- 配置过滤器顺序:确保登录校验过滤器先执行,编码过滤器后执行。
- 运行项目:通过访问不同模块验证过滤器功能。
总结
Filter是Java Web开发中的重要工具,提供了强大的拦截与增强功能。通过合理使用Filter,可以实现公共逻辑的复用、请求响应的统一处理以及动态扩展功能。在复杂项目中,Filter与责任链模式结合,可以极大提升系统的灵活性与可维护性。