您当前的位置: 首页 >  学无止境 >  文章详情

Java Web卫士:自定义过滤器的原理、实现与实战

时间: 2025-09-15 【学无止境】 阅读量:共4人围观

简介 在Java Web开发中,过滤器(Filter)是Servlet规范提供的一种强大而灵活的组件,它允许你在HTTP请求到达Servlet之前和响应发送给客户端之前“拦截”并处理它们。你可以将过滤器想象成一道安全闸门或一个流水线工作站,对流通的数据进行统一加工。本文将深入讲解如何创建自定义过滤器,并探讨其核心原理和常见应用场景。

一、 什么是过滤器?它的生命周期是怎样的?

过滤器是实现了javax.servlet.Filter接口的Java类。它的核心生命周期由三个方法定义,由Web容器(如Tomcat)管理:

  1. init(FilterConfig config): 容器在启动时初始化过滤器,调用一次。用于加载配置参数、初始化资源。

  2. doFilter(ServletRequest request, ServletResponse response, FilterChain chain): 核心方法。每次请求与过滤器关联的URL时都会被调用。在这里编写你的过滤逻辑。

  3. destroy(): 容器在销毁过滤器实例前调用一次。用于释放资源,如关闭数据库连接。

核心机制:FilterChain

doFilter方法中有一个至关重要的参数:FilterChain chain。它代表了过滤器链。当你调用chain.doFilter(request, response)时,表示“当前过滤器的处理已完成,请将请求和响应传递给链中的下一个过滤器(或最终的目标Servlet)”。是否调用此方法,决定了请求是继续向下传递还是被拦截终止。

二、 如何实现一个自定义过滤器?

实现一个自定义过滤器非常简单,只需三步。下面我们以实现一个“记录请求耗时”的过滤器为例。

第1步:实现Filter接口,重写方法

import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; // 使用@WebFilter注解声明这是一个过滤器,并指定它过滤哪些URL @WebFilter(filterName = "timingFilter", urlPatterns = "/*") // "/*" 表示过滤所有请求 public class TimingFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { // 初始化代码,可以读取web.xml或注解中的初始化参数 System.out.println("TimingFilter initialized..."); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 1. 在调用chain.doFilter之前:预处理请求(AOP中的@Before) long startTime = System.currentTimeMillis(); System.out.println("Request started at: " + startTime); // 2. 关键操作:将请求和响应传递给过滤器链的下一个节点(可能是下一个过滤器,也可能是Servlet) // 如果不调用此方法,请求将被拦截在此,不会继续向下处理。 chain.doFilter(request, response); // 3. 在chain.doFilter之后:后处理响应(AOP中的@After) long endTime = System.currentTimeMillis(); long duration = endTime - startTime; System.out.println("Request completed in: " + duration + " ms"); // 你也可以将耗时信息添加到响应头中 ((HttpServletResponse) response).setHeader("X-Response-Time", duration + "ms"); } @Override public void destroy() { // 清理代码 System.out.println("TimingFilter destroyed..."); } }

第2步:配置过滤器(两种方式)

  • 方式一:注解配置(推荐,如上例所示)
    使用@WebFilter注解,简单明了。urlPatterns指定要拦截的URL模式,如/api/, /, *.do等。

  • 方式二:web.xml配置(传统方式)
    如果你不喜欢注解或需要更复杂的配置(如指定过滤器顺序),可以在web.xml中配置。

<filter> <filter-name>timingFilter</filter-name> <filter-class>com.yourpackage.TimingFilter</filter-class> <!-- 可以添加初始化参数 --> <init-param> <param-name>logLevel</param-name> <param-value>DEBUG</param-value> </init-param> </filter> <filter-mapping> <filter-name>timingFilter</filter-name> <url-pattern>/*</url-pattern> <!-- 还可以指定Dispatcher类型 --> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> </filter-mapping>

第3步:部署并测试

将应用部署到Servlet容器(如Tomcat)后,访问任何URL,你都会在控制台看到请求耗时的日志。

三、 核心应用场景实战

自定义过滤器的用途极其广泛,以下是几个经典场景:

1. 认证与授权(Authentication & Authorization)

@WebFilter("/admin/*") public class AuthFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpReq = (HttpServletRequest) request; HttpServletResponse httpResp = (HttpServletResponse) response; HttpSession session = httpReq.getSession(false); // 检查session中是否存在已登录的用户 if (session == null || session.getAttribute("user") == null) { // 如果未登录,重定向到登录页,并终止请求(不调用chain.doFilter) httpResp.sendRedirect(httpReq.getContextPath() + "/login"); return; } // 如果已登录,继续执行后续流程 chain.doFilter(request, response); } }

2. 日志记录与审计

记录每个请求的IP、URL、方法、用户代理、耗时等信息,用于监控和问题排查。

3. 统一字符编码处理

解决中文乱码问题的经典用法。

@WebFilter("/*") 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"); response.setContentType("text/html; charset=UTF-8"); chain.doFilter(request, response); } }

4. 防止XSS攻击(跨站脚本攻击)

对请求参数进行转义,过滤恶意脚本。

// 通常需要包装Request对象,重写其getParameter等方法来实现过滤 public class XSSFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 使用自定义的包装类 chain.doFilter(new XSSRequestWrapper((HttpServletRequest) request), response); } }

四、 进阶技巧与注意事项

  1. 过滤器执行顺序:

    • 注解配置:顺序不确定,通常按类名排序。若要严格控制顺序,需使用web.xml配置,其执行顺序由的声明顺序决定。

    • Spring Boot中可以使用@Order注解来定义过滤器在过滤器链中的顺序。

  2. 包装请求和响应(Wrapper):

    过滤器可以对ServletRequest和ServletResponse进行包装,重写其方法以实现高级功能(如修改请求参数、压缩响应内容)。上面的XSS过滤就是一个典型例子。

  3. 性能考量:

    过滤器的逻辑应尽可能高效,避免在doFilter方法中进行复杂的同步操作或耗时IO,以免成为系统瓶颈。

总结

自定义过滤器是Java Web开发中处理横切关注点(Cross-Cutting Concerns)的利器。它通过一种标准化的、非侵入式的方式,为Web请求提供了统一的预处理和后处理能力。无论是处理安全、日志、编码还是性能监控,过滤器都是架构中不可或缺的“卫士”。掌握其原理和实现,能让你更好地控制Web请求的生命周期,构建出更健壮、更安全的应用程序。

文章评论
总共 0 条评论
这篇文章还没有收到评论,赶紧来抢沙发吧~
Copyright (C) 2023- 小祥驿站 保留所有权利 蜀ICP备 17034318号-2  公安备案号 50010302004554