本文目录导读:

我来详细介绍Java Servlet过滤器的开发案例,从基础概念到完整实现。
Servlet过滤器基础
什么是Servlet过滤器
过滤器是Java Web组件,可以在请求到达Servlet之前或响应返回客户端之前进行预处理和后处理。
过滤器的典型应用场景
- 用户认证和授权
- 请求日志记录
- 数据压缩
- 输入验证
- 字符编码设置
- 敏感信息过滤
完整开发案例
案例1:字符编码过滤器
package com.example.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 字符编码过滤器 - 统一设置请求和响应的字符编码
*/
@WebFilter(urlPatterns = "/*") // 过滤所有请求
public class CharacterEncodingFilter implements Filter {
private String encoding = "UTF-8";
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 从web.xml或注解获取初始化参数
String encodingParam = filterConfig.getInitParameter("encoding");
if (encodingParam != null) {
encoding = encodingParam;
}
System.out.println("字符编码过滤器初始化完成,编码:" + encoding);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 设置请求编码
request.setCharacterEncoding(encoding);
// 设置响应编码
response.setCharacterEncoding(encoding);
response.setContentType("text/html; charset=" + encoding);
System.out.println("请求已设置编码为:" + encoding);
// 继续执行后续过滤器或目标Servlet
chain.doFilter(request, response);
System.out.println("响应已处理完成");
}
@Override
public void destroy() {
System.out.println("字符编码过滤器被销毁");
}
}
案例2:用户登录认证过滤器
package com.example.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* 用户登录认证过滤器 - 检查用户是否已登录
*/
@WebFilter(urlPatterns = {"/admin/*", "/user/*"}) // 只过滤管理后台和用户相关页面
public class LoginFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("登录认证过滤器初始化");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// 获取当前请求的URI
String requestURI = httpRequest.getRequestURI();
String contextPath = httpRequest.getContextPath();
String requestPath = requestURI.substring(contextPath.length());
// 允许访问的公共路径(不需要登录)
if (requestPath.equals("/login") || requestPath.equals("/register")
|| requestPath.equals("/index")) {
chain.doFilter(request, response);
return;
}
// 检查用户是否已登录
HttpSession session = httpRequest.getSession(false);
boolean isLoggedIn = (session != null && session.getAttribute("user") != null);
if (isLoggedIn) {
// 用户已登录,继续执行
System.out.println("用户已认证,允许访问:" + requestPath);
chain.doFilter(request, response);
} else {
// 用户未登录,重定向到登录页面
System.out.println("用户未登录,重定向到登录页面");
httpResponse.sendRedirect(contextPath + "/login");
}
}
@Override
public void destroy() {
System.out.println("登录认证过滤器被销毁");
}
}
案例3:请求日志记录过滤器
package com.example.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 请求日志记录过滤器 - 记录所有请求信息
*/
@WebFilter(urlPatterns = "/*")
public class LoggingFilter implements Filter {
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("日志过滤器初始化");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
// 收集请求信息
String ip = httpRequest.getRemoteAddr();
String method = httpRequest.getMethod();
String uri = httpRequest.getRequestURI();
String queryString = httpRequest.getQueryString();
String userAgent = httpRequest.getHeader("User-Agent");
String sessionId = httpRequest.getSession().getId();
String timestamp = dateFormat.format(new Date());
// 记录请求开始时间
long startTime = System.currentTimeMillis();
// 构建日志信息
StringBuilder logInfo = new StringBuilder();
logInfo.append("[").append(timestamp).append("] ");
logInfo.append("IP: ").append(ip).append(" ");
logInfo.append("Session: ").append(sessionId).append(" ");
logInfo.append("Method: ").append(method).append(" ");
logInfo.append("URI: ").append(uri);
if (queryString != null) {
logInfo.append("?").append(queryString);
}
logInfo.append(" ").append(userAgent);
// 打印日志
System.out.println("请求开始: " + logInfo.toString());
// 使用包装类记录响应状态和耗时
ResponseWrapper responseWrapper = new ResponseWrapper(httpRequest, response);
try {
// 继续执行
chain.doFilter(request, responseWrapper);
} finally {
// 计算耗时
long duration = System.currentTimeMillis() - startTime;
System.out.println("请求完成: " + uri + " | 耗时: " + duration + "ms");
}
}
@Override
public void destroy() {
System.out.println("日志过滤器被销毁");
}
}
/**
* 响应包装类(如果需要记录响应相关信息)
*/
class ResponseWrapper extends HttpServletRequestWrapper {
private ServletResponse response;
public ResponseWrapper(HttpServletRequest request, ServletResponse response) {
super(request);
this.response = response;
}
}
案例4:XSS(跨站脚本攻击)过滤过滤器
package com.example.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
import java.util.regex.Pattern;
/**
* XSS过滤器 - 防止跨站脚本攻击
*/
@WebFilter(urlPatterns = "/*")
public class XSSFilter implements Filter {
// XSS攻击模式
private static final Pattern[] XSS_PATTERNS = {
Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE),
Pattern.compile("src[\r\n]*=[\r\n]*\\'(.*?)\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE),
Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE),
Pattern.compile("</script>", Pattern.CASE_INSENSITIVE),
Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE),
Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE),
Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE),
Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE),
Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE),
Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE)
};
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("XSS过滤器初始化");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 使用自定义的请求包装类来过滤参数
chain.doFilter(new XSSRequestWrapper((HttpServletRequest) request), response);
}
@Override
public void destroy() {
System.out.println("XSS过滤器被销毁");
}
/**
* XSS请求包装类 - 对请求参数进行XSS过滤
*/
static class XSSRequestWrapper extends HttpServletRequestWrapper {
public XSSRequestWrapper(HttpServletRequest servletRequest) {
super(servletRequest);
}
@Override
public String[] getParameterValues(String parameter) {
String[] values = super.getParameterValues(parameter);
if (values == null) {
return null;
}
int count = values.length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) {
encodedValues[i] = stripXSS(values[i]);
}
return encodedValues;
}
@Override
public String getParameter(String parameter) {
String value = super.getParameter(parameter);
return stripXSS(value);
}
@Override
public String getHeader(String name) {
String value = super.getHeader(name);
return stripXSS(value);
}
/**
* 过滤XSS攻击代码
*/
private String stripXSS(String value) {
if (value == null) {
return null;
}
// 对特殊字符进行HTML转义
value = value.replaceAll("&", "&");
value = value.replaceAll("<", "<");
value = value.replaceAll(">", ">");
value = value.replaceAll("\"", """);
value = value.replaceAll("'", "'");
value = value.replaceAll("/", "/");
// 移除XSS攻击模式
for (Pattern pattern : XSS_PATTERNS) {
value = pattern.matcher(value).replaceAll("");
}
return value;
}
}
}
配置方式
使用@WebFilter注解(推荐)
@WebFilter(
urlPatterns = {"/api/*", "/admin/*"},
filterName = "myFilter",
initParams = {
@WebInitParam(name = "param1", value = "value1"),
@WebInitParam(name = "param2", value = "value2")
}
)
使用web.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 配置字符编码过滤器 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>com.example.filter.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>
<!-- 配置登录验证过滤器 -->
<filter>
<filter-name>loginFilter</filter-name>
<filter-class>com.example.filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>loginFilter</filter-name>
<url-pattern>/admin/*</url-pattern>
<url-pattern>/user/*</url-pattern>
</filter-mapping>
<!-- 配置日志过滤器 -->
<filter>
<filter-name>loggingFilter</filter-name>
<filter-class>com.example.filter.LoggingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>loggingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
过滤器链执行顺序
// 过滤器执行顺序取决于配置顺序(web.xml)或类名(@WebFilter)
@WebFilter(urlPatterns = "/*", filterName = "Filter1")
@Order(1) // 指定执行顺序
public class Filter1 implements Filter { ... }
@WebFilter(urlPatterns = "/*", filterName = "Filter2")
@Order(2)
public class Filter2 implements Filter { ... }
// 执行顺序:Filter1 -> Filter2 -> Servlet -> Filter2 -> Filter1
Maven依赖配置
<dependencies>
<!-- Servlet API -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- 如果需要使用注解方式 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
最佳实践建议
- 性能考虑:避免在过滤器中进行耗时操作
- 线程安全:过滤器是单例的,注意线程安全性
- 异常处理:适当处理异常,避免影响整个请求链
- 资源清理:在destroy()方法中释放资源
- 配置灵活:使用初始化参数提高配置灵活性
- 日志记录:适当记录日志便于调试
常见问题排查
- 过滤器未执行:检查URL模式配置是否正确
- 编码问题:确保编码过滤器在其他过滤器之前执行
- 死循环:避免过滤器自身再次调用自身
- 性能问题:尽量减少请求/响应的包装操作
这些案例涵盖了主要的过滤器开发场景,可以根据实际需求进行修改和扩展。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播