Java过滤器(Filter)使用详解

一、过滤器基础概念

1. 什么是过滤器

过滤器(Filter)是Java Web中的一种组件,可以在请求到达Servlet之前或响应返回客户端之前对HTTP请求和响应进行预处理和后处理。

2. 过滤器的作用

认证和授权:检查用户是否登录,是否有权限访问资源

日志记录:记录请求和响应信息

数据压缩:压缩响应数据

字符编码转换:统一请求和响应的编码

数据加密/解密:对敏感数据进行处理

XSS防护:过滤恶意脚本

3. 过滤器的工作原理

客户端请求 → 过滤器1 → 过滤器2 → ... → Servlet → 过滤器2 → 过滤器1 → 客户端响应

二、过滤器的创建与配置

1. 创建过滤器类

实现javax.servlet.Filter接口:

import javax.servlet.*;

import javax.servlet.annotation.WebFilter;

import java.io.IOException;

@WebFilter("/*") // 过滤所有请求

public class MyFilter 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 {

// 过滤处理方法

System.out.println("请求到达过滤器...");

// 预处理代码

request.setCharacterEncoding("UTF-8");

response.setContentType("text/html;charset=UTF-8");

// 放行到下一个过滤器或目标资源

chain.doFilter(request, response);

// 后处理代码

System.out.println("响应经过过滤器...");

}

@Override

public void destroy() {

// 销毁方法,在过滤器销毁时调用

System.out.println("过滤器销毁...");

}

}

2. 配置过滤器的两种方式

方式一:注解配置(Servlet 3.0+)

@WebFilter(

urlPatterns = {"/user/*", "/admin/*"}, // 过滤路径

initParams = {

@WebInitParam(name = "encoding", value = "UTF-8"),

@WebInitParam(name = "key", value = "value")

},

dispatcherTypes = {DispatcherType.REQUEST, DispatcherType.FORWARD}

)

public class MyFilter implements Filter {

// ...

}

方式二:web.xml配置

myFilter

com.example.MyFilter

encoding

UTF-8

myFilter

/*

REQUEST

FORWARD

三、过滤器的核心方法详解

1. init(FilterConfig config)

在过滤器实例创建后立即调用

用于初始化过滤器的配置参数

FilterConfig对象可以获取初始化参数和ServletContext

@Override

public void init(FilterConfig filterConfig) {

String encoding = filterConfig.getInitParameter("encoding");

this.encoding = encoding != null ? encoding : "UTF-8";

this.servletContext = filterConfig.getServletContext();

}

2. doFilter(ServletRequest, ServletResponse, FilterChain)

每次请求都会调用该方法

核心过滤逻辑写在这里

必须调用chain.doFilter()方法将请求传递给下一个过滤器或目标资源

@Override

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)

throws IOException, ServletException {

HttpServletRequest request = (HttpServletRequest) req;

HttpServletResponse response = (HttpServletResponse) resp;

// 预处理

System.out.println("拦截到请求: " + request.getRequestURI());

long startTime = System.currentTimeMillis();

// 放行

chain.doFilter(request, response);

// 后处理

long endTime = System.currentTimeMillis();

System.out.println("请求处理耗时: " + (endTime - startTime) + "ms");

}

3. destroy()

在过滤器实例销毁前调用

用于释放资源

@Override

public void destroy() {

// 清理资源

this.encoding = null;

this.servletContext = null;

}

四、过滤器的高级应用

1. 多过滤器执行顺序

多个过滤器的执行顺序:

web.xml中的配置顺序

注解配置时按过滤器类名的字母顺序

可以通过@Order注解指定顺序(Spring环境中):

@Order(1)

@WebFilter("/*")

public class FilterA implements Filter { /*...*/ }

@Order(2)

@WebFilter("/*")

public class FilterB implements Filter { /*...*/ }

2. 拦截不同类型的请求

通过dispatcherTypes属性可以指定拦截的请求类型:

@WebFilter(

urlPatterns = "/*",

dispatcherTypes = {

DispatcherType.REQUEST, // 直接请求

DispatcherType.FORWARD, // 转发

DispatcherType.INCLUDE, // 包含

DispatcherType.ERROR, // 错误

DispatcherType.ASYNC // 异步

}

)

3. 防止XSS攻击的过滤器示例

@WebFilter("/*")

public class XssFilter implements Filter {

@Override

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)

throws IOException, ServletException {

HttpServletRequest request = (HttpServletRequest) req;

XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(request);

chain.doFilter(xssRequest, resp);

}

// XSS请求包装类

public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {

public XssHttpServletRequestWrapper(HttpServletRequest request) {

super(request);

}

@Override

public String getParameter(String name) {

return cleanXSS(super.getParameter(name));

}

@Override

public String[] getParameterValues(String name) {

String[] values = super.getParameterValues(name);

if (values == null) return null;

String[] cleanedValues = new String[values.length];

for (int i = 0; i < values.length; i++) {

cleanedValues[i] = cleanXSS(values[i]);

}

return cleanedValues;

}

private String cleanXSS(String value) {

if (value == null) return null;

return value.replaceAll("<", "<").replaceAll(">", ">");

}

}

}

4. 登录验证过滤器示例

@WebFilter("/admin/*")

public class LoginFilter implements Filter {

@Override

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)

throws IOException, ServletException {

HttpServletRequest request = (HttpServletRequest) req;

HttpServletResponse response = (HttpServletResponse) resp;

HttpSession session = request.getSession(false);

String loginURI = request.getContextPath() + "/login";

boolean loggedIn = session != null && session.getAttribute("user") != null;

boolean loginRequest = request.getRequestURI().equals(loginURI);

if (loggedIn || loginRequest) {

chain.doFilter(request, response);

} else {

response.sendRedirect(loginURI);

}

}

}

五、常见问题与解决方案

1. 过滤器不生效的可能原因

过滤器类没有实现javax.servlet.Filter接口

没有配置@WebFilter注解或web.xml配置错误

URL模式不匹配当前请求路径

过滤器抛出了异常没有正确处理

在doFilter方法中没有调用chain.doFilter()

2. 获取不到HttpServletRequest对象

需要将ServletRequest强制转换为HttpServletRequest:

HttpServletRequest httpRequest = (HttpServletRequest) request;

3. 过滤器中的异常处理

@Override

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) {

try {

// 预处理

chain.doFilter(req, resp);

// 后处理

} catch (Exception e) {

// 处理异常

((HttpServletResponse) resp).sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);

}

}

4. 性能监控过滤器示例

@WebFilter("/*")

public class PerformanceFilter implements Filter {

@Override

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)

throws IOException, ServletException {

long startTime = System.currentTimeMillis();

chain.doFilter(req, resp);

long endTime = System.currentTimeMillis();

HttpServletRequest request = (HttpServletRequest) req;

System.out.printf("%s 请求 %s 耗时 %d ms%n",

request.getMethod(),

request.getRequestURI(),

(endTime - startTime));

}

}

六、Spring Boot中的过滤器

在Spring Boot中使用过滤器:

1. 使用@WebFilter注解

@WebFilter(urlPatterns = "/*")

public class MySpringFilter implements Filter {

// 实现方法

}

需要在启动类添加@ServletComponentScan注解:

@SpringBootApplication

@ServletComponentScan

public class Application {

public static void main(String[] args) {

SpringApplication.run(Application.class, args);

}

}

2. 使用FilterRegistrationBean注册

@Configuration

public class FilterConfig {

@Bean

public FilterRegistrationBean myFilterRegistration() {

FilterRegistrationBean registration = new FilterRegistrationBean<>();

registration.setFilter(new MyFilter());

registration.addUrlPatterns("/*");

registration.setName("myFilter");

registration.setOrder(1); // 设置顺序

return registration;

}

}

3. Spring Security中的过滤器链

Spring Security本身就是基于过滤器链实现的,了解其过滤器顺序有助于自定义过滤器:

ChannelProcessingFilter

SecurityContextPersistenceFilter

ConcurrentSessionFilter

认证处理过滤器(UsernamePasswordAuthenticationFilter等)

SecurityContextHolderAwareRequestFilter

RememberMeAuthenticationFilter

AnonymousAuthenticationFilter

ExceptionTranslationFilter

FilterSecurityInterceptor

七、最佳实践

合理设计过滤器链:将功能单一化,每个过滤器只处理一件事情

注意性能影响:过滤器中避免耗时操作

异常处理:确保过滤器中的异常被正确处理

线程安全:过滤器是单例的,注意实例变量的线程安全

合理设置过滤路径:避免过度拦截影响性能

日志记录:重要的过滤操作应该记录日志

与拦截器区分:在Spring环境中,简单功能用拦截器,Servlet相关用过滤器

八、总结

过滤器是Java Web开发中非常重要的组件,它提供了一种声明式的处理HTTP请求和响应的机制。通过本文的详细介绍,你应该已经掌握了:

过滤器的基本概念和工作原理

如何创建和配置过滤器

过滤器的核心方法和生命周期

过滤器的高级应用场景

常见问题解决方案

Spring Boot中的过滤器使用

过滤器的最佳实践

合理使用过滤器可以大大提高Web应用的安全性、可维护性和性能。