过滤器(Filter)是Servlet技术中的一个重要组件,它位于客户端与服务器端之间,用于拦截客户端发送到服务器的请求,或者在服务器将响应返回给客户端之前对响应进行处理。过滤器提供了一种灵活的方式来修改或增强请求和响应的数据,同时不影响Web应用程序的其他部分。
过滤器的工作原理
过滤器的工作原理类似于链式结构,多个过滤器可以串联在一起,形成一个过滤器链。当一个请求到达 Web 容器时,它会依次经过过滤器链中的所有过滤器,每个过滤器都可以对请求进行处理,然后将请求传递给下一个过滤器,最终到达目标 Servlet。
过滤器的使用场景
- 身份验证和授权: 检查用户是否已登录,是否有权限访问请求的资源。
- 日志记录: 记录请求和响应信息,方便调试和分析。
- 数据压缩: 压缩响应数据,减少网络传输时间。
- 字符编码转换: 统一请求和响应的字符编码。
- 敏感信息过滤: 过滤掉敏感信息,例如密码或信用卡号。
过滤器接口
JavaWeb 过滤器需要实现 javax.servlet.Filter
接口,该接口定义了三个方法:
init(FilterConfig filterConfig)
: 初始化过滤器,在过滤器第一次被使用时调用。doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
: 过滤器核心方法,用于处理请求和响应。destroy()
: 销毁过滤器,在过滤器被移除时调用。
Filter生命周期
- 初始化:当容器启动时,调用
init(FilterConfig config)
方法。 - 过滤:当请求到达时,调用
doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
方法。 - 销毁:当容器停止时,调用
destroy()
方法。
配置过滤器
在web.xml
中配置过滤器:
<filter>
<filter-name>CharsetFilter</filter-name>
<filter-class>com.example.CharsetFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CharsetFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
过滤器代码
import javax.servlet.*;
import java.io.IOException;
public class CharsetFilter 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");
// 放行请求
chain.doFilter(request, response);
// 在响应返回客户端之前的处理
response.setContentType("text/html;charset=UTF-8");
}
@Override
public void destroy() {
// 销毁时的操作
}
}
重写doFilter方法
也可以重写doFilter方法,选择放行条件。例如,可以根据请求的URL或请求参数来判断是否放行。
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String requestURI = httpRequest.getRequestURI();
// 只放行特定的URL
if (requestURI.equals("/public")) {
chain.doFilter(request, response); // 放行
} else {
// 其他请求不放行,可以返回错误页面或重定向
response.getWriter().write("不允许访问该资源");
}
}
放行的注意事项
- 确保调用:在
doFilter
中必须确保调用chain.doFilter(request, response)
,否则请求将不会继续处理,可能导致客户端超时或错误。 - 顺序执行:在多个过滤器的情况下,放行的顺序由它们在配置中的声明顺序决定。第一个过滤器先执行,之后是下一个过滤器或目标资源。
- 性能考虑:在过滤器中进行复杂的逻辑处理可能会影响性能,建议将逻辑尽量简化。
过滤链和优先级
过滤器链是由多个过滤器组成的一个链条,当一个请求到达服务器时,Servlet容器会按照预定义的顺序依次调用这些过滤器。每个过滤器可以在请求到达目标资源之前或响应返回给客户端之前执行特定的操作。
过滤器链中的过滤器执行顺序是由它们的优先级决定的。优先级高的过滤器先执行,优先级低的过滤器后执行。
优先级设置:
- Web.xml 配置: 在 web.xml 文件中使用
<filter-mapping>
元素的order
属性来设置过滤器的优先级,数字越小,优先级越高。
<filter-mapping>
<filter-name>Filter1</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<order>1</order>
</filter-mapping>
<filter-mapping>
<filter-name>Filter2</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<order>2</order>
</filter-mapping>
- 注解配置: 在
@WebFilter
注解中使用order
属性来设置过滤器的优先级,数字越小,优先级越高。
@WebFilter(filterName = "Filter1", urlPatterns = "/*", order = 1)
public class LogFilter implements Filter {
// ...
}
@WebFilter(filterName = "Filter2", urlPatterns = "/*", order = 2)
public class AuthFilter implements Filter {
// ...
}