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
接口包含以下三个方法:
-
init(FilterConfig config):
在 Filter 初始化时调用,用于读取 Filter 的初始化参数或执行其他初始化操作。 -
doFilter(ServletRequest request, ServletResponse response, FilterChain chain):
执行过滤逻辑的核心方法。开发者可以在此方法中:- 在调用
chain.doFilter()
之前执行前置处理(如权限检查)。 - 调用
chain.doFilter()
将请求传递给下一个 Filter 或目标资源。 - 在调用
chain.doFilter()
之后执行后置处理(如日志记录)。
- 在调用
-
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
- 部署一个简单的 Servlet,并访问其 URL。
- 查看控制台输出,应能看到类似以下日志:
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 应用,要求如下:
- 身份认证(AuthFilter):检查请求头中的
Authorization
字段,若缺失或无效,返回 401。 - trace追踪(TraceFilter):在请求中添加traceId,便于后续追踪该请求
- 请求日志记录(LoggingFilter):记录请求处理耗时、请求路径等信息。
Filter 执行顺序应为:
AuthFilter
→ TraceFilter →LoggingFilter
即:先进行身份验证,验证通过后,再添加traceId,最后进行日志记录。
3.2 完整代码
step1. 定义Filter
身份认证 Filter:
- 这里顺便演示
init()
方法的用法,可以通过init()
方法的参数FilterConfig.getInitParameter获取在
FilterRegistrationBean.addInitParameter()
设置参数
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 {private String authFilterParam;@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 初始化逻辑(可选)//在FilterConfig里配置Filter时,可以通过 registration.addInitParameter("paramName", "paramValue") 或 registrationBean.setInitParameters(params) 设置初始化参数authFilterParam = filterConfig.getInitParameter("AuthFilterParam");System.out.println("AuthFilter init param: " + authFilterParam);}@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("/*");//配置AuthFilter init方法所需的参数,也可以通过registrationBean.setInitParameters(params)放一个map参数registration.addInitParameter("AuthFilterParam", "authFilterParamValue"); 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 的执行顺序,从而确保业务逻辑的正确性与稳定性。
相关文章:

javax.servlet.Filter 介绍-笔记
1.javax.servlet.Filter 简介 javax.servlet.Filter 是 Java Servlet API 中的一个核心接口,用于在请求到达目标资源(如 Servlet 或 JSP)之前或响应返回给客户端之前执行预处理或后处理操作。它常用于实现与业务逻辑无关的通用功能ÿ…...
从40秒到11毫秒:TiDB环境下一次SQL深潜优化实战
作者: meathill 原文来源: https://tidb.net/blog/edb6061b 在数据库应用中,慢SQL是常见的性能瓶颈。本文将详细记录一次针对TiDB Cloud v7.5.2环境中复杂评论查询的SQL优化过程,如何通过分析执行计划、添加索引、改写SQL&…...

Win 11开始菜单图标变成白色怎么办?
在使用windows 11的过程中,有时候开始菜单的某些程序图标变成白色的文件形式,但是程序可以正常打开,这个如何解决呢? 这通常是由于快捷方式出了问题,下面跟着操作步骤来解决吧。 1、右键有问题的软件,打开…...

入门OpenTelemetry——应用自动埋点
埋点 什么是埋点 埋点,本质就是在你的应用程序里,在重要位置插入采集代码,比如: 收集请求开始和结束的时间收集数据库查询时间收集函数调用链路信息收集异常信息 这些埋点数据(Trace、Metrics、Logs)被…...

C语言链表的操作
初学 初学C语言时,对于链表节点的定义一般是这样的: typedef struct node {int data;struct node *next; } Node; 向链表中添加节点: void addNode(Node **head, int data) {Node *newNode (Node*)malloc(sizeof(Node));newNode->dat…...

芯片生态链深度解析(二):基础设备篇——人类精密制造的“巅峰对决”
【开篇:设备——芯片工业的“剑与盾”】 当ASML的EUV光刻机以每秒5万次激光脉冲在硅片上雕刻出0.13nm精度的电路(相当于在月球表面精准定位一枚二维码),当国产28nm光刻机在华虹产线实现“从0到1”的突破,这场精密制造…...

C语言指针深入详解(二):const修饰指针、野指针、assert断言、指针的使用和传址调用
目录 一、const修饰指针 (一)const修饰变量 (二)const 修饰指针变量 二、野指针 (一)野指针成因 1、指针未初始化 2、指针越界访问 3、指针指向的空间释放 (二)如何规避野指…...

【unity游戏开发——编辑器扩展】使用EditorGUI的EditorGUILayout绘制工具类在自定义编辑器窗口绘制各种UI控件
注意:考虑到编辑器扩展的内容比较多,我将编辑器扩展的内容分开,并全部整合放在【unity游戏开发——编辑器扩展】专栏里,感兴趣的小伙伴可以前往逐一查看学习。 文章目录 前言常用的EditorGUILayout控件专栏推荐完结 前言 EditorG…...

Linux基础第三天
系统时间 date命令,date中文具有日期的含义,利用该命令可以查看或者修改Linux系统日期和时间。 基本格式如下: gecubuntu:~$ date gecubuntu:~$ date -s 日期时间 // -s选项可以设置日期和时间 文件权限 chmod命令,是英文…...

MoodDrop:打造一款温柔的心情打卡单页应用
我正在参加CodeBuddy「首席试玩官」内容创作大赛,本文所使用的 CodeBuddy 免费下载链接:腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴 起心动念:我想做一款温柔的情绪应用 「今天的你,心情如何?」 有时候&#x…...

接口——类比摄像
最近迷上了买相机,大疆Pocket、Insta Go3、大疆Mini3、佳能50D、vivo徕卡人像大师(狗头),在买配件的时候,发现1/4螺口简直是神中之神,这个万能接口让我想到计算机设计中的接口,遂有此篇—— 接…...
【上位机——WPF】布局控件
布局控件 常用布局控件Panel基类Grid(网格)UniformGrid(均匀分布)StackPanel(堆积面板)WrapPanel(换行面板)DockerPanel(停靠面板)Canvas(画布布局)Border(边框)GridSplitter(分割窗口)常用布局控件 Grid:网格,根据自定义行和列来设置控件的布局StackPanel:栈式面板,包含的…...
深入解析Spring Boot与Kafka集成:构建高性能消息驱动应用
深入解析Spring Boot与Kafka集成:构建高性能消息驱动应用 引言 在现代分布式系统中,消息队列是实现异步通信和解耦的重要组件。Apache Kafka作为一种高性能、分布式的消息系统,被广泛应用于大数据和实时数据处理场景。本文将详细介绍如何在…...

二十、案例特训专题3【系统设计篇】web架构设计
一、前言 二、内容提要 三、单机到应用与数据分离 四、集群与负载均衡 五、集群与有状态无状态服务 六、ORM 七、数据库读写分离 八、数据库缓存Memcache与Redis 九、Redis数据分片 哈希分片如果新增分片会很麻烦,需要把之前数据取出来再哈希除模 一致性哈希分片是…...

【数据结构与算法】ArrayList 与顺序表的实现
目录 一、List 接口 1.1 List 接口的简单介绍 1.1 常用方法 二、顺序表 2.1 线性表的介绍 2.2 顺序表的介绍 2.3 顺序表的实现 2.3.1 前置条件:自定义异常 2.3.2 顺序表的初始化 2.3.2 顺序表的实现 三、ArrayList 实现类 3.1 ArrayList 的两种使用方式 3.2 Array…...
处理金融数据,特别是股票指数数据,以计算和分析RSRS(相对强度指数)
Python脚本,用于处理金融数据,特别是股票指数数据,以计算和分析RSRS(相对强度指数)指标。以下是代码的逐部分解释: 1. **导入库**: - `pandas`:用于数据处理和CSV文件操作。 - `numpy`:用于数值计算。 - `ElasticNet`:来自`sklearn.linear_model`,用于线性…...

【图像处理基石】OpenCV中都有哪些图像增强的工具?
OpenCV 图像增强工具系统性介绍 OpenCV 提供了丰富的图像增强工具,主要分为以下几类: 亮度与对比度调整 线性变换(亮度/对比度调整)直方图均衡化自适应直方图均衡化(CLAHE) 滤波与平滑 高斯滤波中值滤波双…...

WPS PPT设置默认文本框
被一个模板折磨了好久,每次输入文本框都是很丑的24号粗体还有行标,非常恶心,我甚至不知道如何描述自己的问题,非常憋屈,后来终于知道怎么修改文本框了。这种软件操作问题甚至不知道如何描述问题本身,非常烦…...

PostGIS实现矢量数据转栅格数据【ST_AsRaster】
ST_AsRaster函数应用详解:将矢量数据转换为栅格数据 [文章目录] 一、函数概述 二、函数参数与分组说明 三、核心特性与注意事项 四、示例代码 五、应用场景 六、版本依赖 七、总结 一、函数概述 ST_AsRaster是PostGIS中用于将几何对象(如点、线…...

FAST-DDS源码分析PDP(一)
准备开一个FAST-DDS源码分析系列,源码版本FAST-DDS 1.1.0版本。 FAST-DDS这种网络中间件是非常复杂的,所以前期先去分析每个类的作用是什么,然后在结合RTPS DOC,FAST-DDS DEMO,以及FAST-DDS的doc去串起来逻辑。 Builtin Discovery…...

python打卡day29@浙大疏锦行
知识点回顾 类的装饰器装饰器思想的进一步理解:外部修改、动态类方法的定义:内部定义和外部定义 作业:复习类和函数的知识点,写下自己过去29天的学习心得,如对函数和类的理解,对python这门工具的理解等&…...

【数据结构】2-3-1单链表的定义
数据结构知识点合集 知识点 单链表存储结构 优点:不要求大片连续空间,改变容量方便;缺点:不可随机存取,要耗费一定空间存放指针 /*单链表节点定义*/ typedef struct LNode{ElemType data;struct LNode *next; }LNo…...

贝塞尔曲线原理
文章目录 一、 低阶贝塞尔曲线1.一阶贝塞尔曲线2. 二阶贝塞尔曲线3. 三阶贝塞尔曲线 一、 低阶贝塞尔曲线 1.一阶贝塞尔曲线 如下图所示, P 0 P_0 P0, P 1 P_1 P1 是平面中的两点,则 B ( t ) B ( t ) B(t) 代表平面中的一段线段。…...

3D个人简历网站 4.小岛
1.模型素材 在Sketchfab上下载狐狸岛模型,然后转换为素材资源asset,嫌麻烦直接在网盘链接下载素材, Fox’s islandshttps://sketchfab.com/3d-models/foxs-islands-163b68e09fcc47618450150be7785907https://gltf.pmnd.rs/ 素材夸克网盘&a…...

创建型:原型模式
目录 1、核心思想 2、实现方式 2.1 基本结构 2.2 代码示例(Java) 3、适用场景 4、new与clone实际场景建议 1、核心思想 目的:通过复制(克隆)现有对象来创建新对象,而不是通过new关键字实例化。对于那…...
浅谈“量子计算应用:从基础原理到行业破局”
量子计算应用:从基础原理到行业破局 引言:量子计算为何成为科技革命新引擎? 量子计算利用量子力学原理(叠加态、纠缠态、量子干涉)突破经典计算的极限,在特定领域可实现指数级加速。根据中研普华预测,2025年全球量子计算市场规模将突破80亿美元,2035年可达8117亿美元。…...
Java面试攻略:从Spring Boot到微服务架构的深入探讨
Java面试攻略:从Spring Boot到微服务架构的深入探讨 场景设定 在一家知名互联网大厂的会议室里,资深面试官王老师正在对一位求职者谢飞机进行技术面试。谢飞机是一位幽默风趣的程序员,他的回答有时让人捧腹大笑。 第一轮:核心技…...
关于文件分片的介绍和应用
文件分片,顾名思义,就是将一个大文件分割成多个小的文件块(chunk)。每个文件块都是原始文件的一部分,并可以通过特定的方式将这些小文件块重新组装成原始文件。 1. 基本原理: 文件分片从底层来看,主要是对…...

Tapered Off-Policy REINFORCE_ 如何为LLM实现稳定高效的策略优化?
Tapered Off-Policy REINFORCE: 如何为LLM实现稳定高效的策略优化? 在大语言模型(LLM)的微调领域,强化学习(RL)正成为提升复杂任务性能的核心方法。本文聚焦于一篇突破性论文,其提出的Tapered …...
使用lvm进行磁盘分区
使用lvm进行磁盘分区 目的: 使用/dev/vdb创建一个5g的逻辑卷挂载到/mnt/lvmtest 前提: /dev/vdb是一块干净的空磁盘,数据会被清空!!! 1. 创建物理卷(PV): pvcreate /dev/sdb2. 验证…...