当前位置: 首页 > news >正文

javax.servlet.Filter 介绍-笔记

1.javax.servlet.Filter 简介

javax.servlet.Filter 是 Java Servlet API 中的一个核心接口,用于在请求到达目标资源(如 Servlet 或 JSP)之前或响应返回给客户端之前执行预处理或后处理操作。它常用于实现与业务逻辑无关的通用功能,例如:

  • 日志记录:记录请求和响应的详细信息。
  • 身份验证和授权:检查用户权限,拦截未授权的访问。
  • 字符编码设置:统一处理请求和响应的字符编码。
  • 性能监控:统计请求的处理时间。
  • 请求/响应内容修改:例如压缩响应内容或修改请求头。

Filter 接口定义如下:

package javax.servlet;import java.io.IOException;public interface Filter {void init(FilterConfig var1) throws ServletException;void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;void destroy();
}

Filter 接口包含以下三个方法:

  1. init(FilterConfig config):在 Filter 初始化时调用,用于读取 Filter 的初始化参数或执行其他初始化操作。

  2. doFilter(ServletRequest request, ServletResponse response, FilterChain chain):执行过滤逻辑的核心方法。开发者可以在此方法中:

    • 在调用 chain.doFilter() 之前执行前置处理(如权限检查)。
    • 调用 chain.doFilter() 将请求传递给下一个 Filter 或目标资源。
    • 在调用 chain.doFilter() 之后执行后置处理(如日志记录)。
  3. destroy():在 Filter 销毁时调用,用于释放资源或执行清理操作。

2. javax.servlet.Filter使用示例

2.1 代码示例

step1.定义Filter

定义一个用于记录请求信息的Filter:

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;public class LoggingFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 初始化操作(可选)System.out.println("LoggingFilter initialized.");}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletRequest httpRequest = (HttpServletRequest) request;// 前置处理:记录请求开始时间long startTime = System.currentTimeMillis();System.out.println("Request received: " + httpRequest.getRequestURI());// 继续处理链(调用下一个 Filter 或目标资源)chain.doFilter(request, response);// 后置处理:记录请求耗时long endTime = System.currentTimeMillis();System.out.println("Request completed in " + (endTime - startTime) + " ms");}@Overridepublic void destroy() {// 清理操作(可选)System.out.println("LoggingFilter destroyed.");}
}

step2. 配置Filter

LoggingFilter必须 显式注册到 Web 应用中 才能生效, Spring Boot中注册Filter有两种方式:

方式1:使用 @Component(自动注册)

  • Spring Boot 会自动识别实现了 Filter 接口的 Bean,并将其注册为过滤器。
import org.springframework.stereotype.Component;
import javax.servlet.Filter;@Component
public class LoggingFilter implements Filter {// 上述 LoggingFilter 实现的 doFilter 等方法...
}

方式2: 手动注册为 FilterRegistrationBean

  • 对于有多个Filter的场景,该方式可以通过 FilterRegistrationBean.setOrder(int) 设置优先级(值越小越靠前)。
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class FilterConfig {@Beanpublic FilterRegistrationBean<TraceFilter> traceFilterRegistration() {FilterRegistrationBean<LoggingFilter> registration = new FilterRegistrationBean<>();registration.setFilter(new LoggingFilter());registration.addUrlPatterns("/*"); // 拦截所有请求registration.setOrder(1); // 设置过滤器的顺序(可选)return registration;}
}

step3.测试 Filter

  1. 部署一个简单的 Servlet,并访问其 URL。
  2. 查看控制台输出,应能看到类似以下日志:
LoggingFilter initialized.
Request received: /example/hello
Request completed in 5 ms

2.2 注意事项

  • Filter 顺序:多个 Filter 的执行顺序可由 FilterRegistrationBean.setOrder(int) 设置值决定(值越小越靠前);响应时顺序相反。
  • 类型转换ServletRequest 和 ServletResponse 需要转换为 HttpServletRequest 和 HttpServletResponse 以访问 HTTP 特定功能。
  • 异常处理:在 doFilter 中抛出的异常会被 Servlet 容器捕获,需确保合理处理异常。

3.一个完整demo

在实际开发中,多个 Filter 的组合使用是常见的需求,在 Spring Boot 中,通过 Filter 可以优雅地实现多个通用功能的串联处理。下面我们将通过一个 “身份认证+ trace追踪 + 请求日志记录” 的典型业务场景,展示如何在 Spring Boot 中配置并使用多个 Filter,并说明它们的执行顺序。

3.1 业务场景说明

我们构建一个 Web 应用,要求如下:

  1. 身份认证(AuthFilter):检查请求头中的 Authorization 字段,若缺失或无效,返回 401。
  2. trace追踪(TraceFilter):在请求中添加traceId,便于后续追踪该请求
  3. 请求日志记录(LoggingFilter):记录请求处理耗时、请求路径等信息。

Filter 执行顺序应为:
AuthFilter →  TraceFilter → LoggingFilter
即:先进行身份验证,验证通过后,再添加traceId,最后进行日志记录。

3.2 完整代码

step1. 定义Filter

身份认证 Filter:

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class AuthFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 初始化逻辑(可选)}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletRequest httpRequest = (HttpServletRequest)request;HttpServletResponse httpResponse = (HttpServletResponse)response;String authHeader = httpRequest.getHeader("Authorization");if (authHeader == null || !authHeader.equals("valid-token")) {// 鉴权失败,返回 401 Unauthorized; 这里演示方便直接打印一条日志//httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");//return;System.out.println("[AuthFilter] check authority failed");}// 继续处理请求chain.doFilter(request, response);}@Overridepublic void destroy() {// 销毁逻辑(可选)}
}

trace追踪 Filter

import java.io.IOException;
import java.util.UUID;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;public class TraceFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 初始化逻辑(可选)}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletRequest httpRequest = (HttpServletRequest)request;// 生成唯一 traceIdString traceId = UUID.randomUUID().toString();// 将 traceId 放入httpRequesthttpRequest.setAttribute("traceId", traceId);// 继续处理请求chain.doFilter(request, response);}@Overridepublic void destroy() {// 销毁逻辑(可选)}
}

请求日志记录 Filter

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;public class LoggingFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 初始化逻辑(可选)}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletRequest httpRequest = (HttpServletRequest) request;long startTime = System.currentTimeMillis();System.out.println("[LoggingFilter] Request started: " + httpRequest.getRequestURI());System.out.println("[LoggingFilter] Request traceId: " + httpRequest.getAttribute("traceId"));// 继续处理请求chain.doFilter(request, response);long endTime = System.currentTimeMillis();System.out.println("[LoggingFilter] Request completed in " + (endTime - startTime) + " ms");}@Overridepublic void destroy() {// 销毁逻辑(可选)}
}

step2. 配置Filter

使用Spring Boot 配置类,控制 Filter 顺序

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class FilterConfig {@Beanpublic FilterRegistrationBean<AuthFilter> authFilterRegistration() {FilterRegistrationBean<AuthFilter> registration = new FilterRegistrationBean<>(new AuthFilter());registration.addUrlPatterns("/*");registration.setOrder(1); // 优先级高,先执行return registration;}@Beanpublic FilterRegistrationBean<TraceFilter> traceFilterRegistration() {FilterRegistrationBean<TraceFilter> registration = new FilterRegistrationBean<>();registration.setFilter(new TraceFilter());registration.addUrlPatterns("/*");registration.setOrder(2); // 优先级中,执行return registration;}@Beanpublic FilterRegistrationBean<LoggingFilter> loggingFilterRegistration() {FilterRegistrationBean<LoggingFilter> registration = new FilterRegistrationBean<>();registration.setFilter(new LoggingFilter());registration.addUrlPatterns("/*");registration.setOrder(3); // 优先级较低,后执行return registration;}
}

step3.定义测试controller

定义一个controller,用于测试Filter的效果:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class ServletFilterController {@GetMapping("ServletFilterController/hello")public String hello() {return "hello world";}
}

step4. 测试

✅ 正常请求(带 Authorization)

  • 请求头:Authorization: valid-token
  • 预期输出:
[LoggingFilter] Request started: /MdcTestController/hello
[LoggingFilter] Request traceId: 15b4852b-187b-42e0-a09b-98a34f17ae9b
[LoggingFilter] Request completed in 14 ms

❌ 未授权请求(无 Authorization)

  • 预期响应码:401 Unauthorized
  • trace和日志拦截器不会执行,不会有输出日志(因为请求在 AuthFilter 中被拦截)
  • 【备注】为方便演示,我们在AuthFilter里将鉴权失败逻辑中的代码改为输出日志了,所以未授权请求输出结果如下所示:

3.3 注意事项

  • 使用 FilterRegistrationBean 可以精确控制 Filter 的执行顺序,避免 Spring Boot 自动排序带来的不确定性。
  • 若 Filter 不需要作为 Spring Bean 管理,也可使用 @WebFilter + @Order,但不如 FilterRegistrationBean 灵活。
    • import javax.servlet.annotation.WebFilter;@WebFilter("/*") // 拦截所有请求
      public class LoggingFilter implements Filter {// ...(同上)
      }
      
  • 所有 Filter 默认对 /* 生效,可根据业务需求限定 URL 模式。

通过组合使用多个 Filter(身份认证 等),我们可以在 Spring Boot 中实现通用、可复用的前置/后置处理逻辑。借助 FilterRegistrationBean,我们可以清晰地控制 Filter 的执行顺序,从而确保业务逻辑的正确性与稳定性。

相关文章:

  • 邀请函|PostgreSQL培训认证报名正式开启
  • FFmpeg 与 C++ 构建音视频处理全链路实战(三)—— FFmpeg 内存模型
  • 什么情况会导致JVM退出?
  • 游戏引擎学习第275天:将旋转和剪切传递给渲染器
  • 基于TouchSocket实现WebSocket自定义OpCode扩展协议
  • 【Folium】使用离线地图
  • 百度导航广告“焊死”东鹏特饮:商业底线失守,用户安全成隐忧
  • 【NLP 72、Prompt、Agent、MCP、function calling】
  • R²AIN SUITE:AI+文档切片,重塑知识管理新标杆
  • 《驱动开发硬核特训 · 专题篇》:深入理解 I2C 子系统
  • Spring Boot 的自动配置为 Spring MVC 做了哪些事情?
  • 竞业禁止协议中AI技能限制的深度剖析
  • Java jar包程序 启动停止脚本 shell bash
  • STM32 __main汇编分析
  • 工具学习_VirusTotal使用
  • 前端学习(2)—— CSS详解与使用
  • 如何在 CentOS 7 虚拟机上配置静态 IP 地址并保持重启后 SSH 连接
  • OpenHarmony平台驱动开发(十五),SDIO
  • Android中LinearLayout线性布局使用详解
  • 块设备代码分析
  • 跨文化戏剧的拓荒者与传承者——洪深与复旦剧社的百年回响
  • 学习教育期间违规吃喝,李献林、叶金广等人被通报
  • 220名“特朗普币”持有者花1.48亿美元,获邀与特朗普共进晚餐
  • 哈马斯表示已释放一名美以双重国籍被扣押人员
  • 不到1小时就能速发证件?央媒曝光健康证办理乱象
  • 浙江省机电集团党委书记、董事长廉俊接受审查调查