javax.servlet.Filter 介绍-笔记

news2025/5/19 7:08:27

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 {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化操作(可选)
        System.out.println("LoggingFilter initialized.");
    }

    @Override
    public 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");
    }

    @Override
    public 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 {

    @Bean
    public 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:

  • 这里顺便演示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;

    @Override
    public 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);
    }

    @Override
    public 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);
    }

    @Override
    public 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 {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化逻辑(可选)
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest)request;
        // 生成唯一 traceId
        String traceId = UUID.randomUUID().toString();
        // 将 traceId 放入httpRequest
        httpRequest.setAttribute("traceId", traceId);

        // 继续处理请求
        chain.doFilter(request, response);
    }

    @Override
    public 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 {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化逻辑(可选)
    }

    @Override
    public 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");
    }

    @Override
    public 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 {
    @Bean
    public 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;
    }

    @Bean
    public FilterRegistrationBean<TraceFilter> traceFilterRegistration() {
        FilterRegistrationBean<TraceFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new TraceFilter());
        registration.addUrlPatterns("/*");
        registration.setOrder(2); // 优先级中,执行
        return registration;
    }

    @Bean
    public 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 的执行顺序,从而确保业务逻辑的正确性与稳定性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2379108.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Win 11开始菜单图标变成白色怎么办?

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

入门OpenTelemetry——应用自动埋点

埋点 什么是埋点 埋点&#xff0c;本质就是在你的应用程序里&#xff0c;在重要位置插入采集代码&#xff0c;比如&#xff1a; 收集请求开始和结束的时间收集数据库查询时间收集函数调用链路信息收集异常信息 这些埋点数据&#xff08;Trace、Metrics、Logs&#xff09;被…

C语言链表的操作

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

芯片生态链深度解析(二):基础设备篇——人类精密制造的“巅峰对决”

【开篇&#xff1a;设备——芯片工业的“剑与盾”】 当ASML的EUV光刻机以每秒5万次激光脉冲在硅片上雕刻出0.13nm精度的电路&#xff08;相当于在月球表面精准定位一枚二维码&#xff09;&#xff0c;当国产28nm光刻机在华虹产线实现“从0到1”的突破&#xff0c;这场精密制造…

C语言指针深入详解(二):const修饰指针、野指针、assert断言、指针的使用和传址调用

目录 一、const修饰指针 &#xff08;一&#xff09;const修饰变量 &#xff08;二&#xff09;const 修饰指针变量 二、野指针 &#xff08;一&#xff09;野指针成因 1、指针未初始化 2、指针越界访问 3、指针指向的空间释放 &#xff08;二&#xff09;如何规避野指…

【unity游戏开发——编辑器扩展】使用EditorGUI的EditorGUILayout绘制工具类在自定义编辑器窗口绘制各种UI控件

注意&#xff1a;考虑到编辑器扩展的内容比较多&#xff0c;我将编辑器扩展的内容分开&#xff0c;并全部整合放在【unity游戏开发——编辑器扩展】专栏里&#xff0c;感兴趣的小伙伴可以前往逐一查看学习。 文章目录 前言常用的EditorGUILayout控件专栏推荐完结 前言 EditorG…

Linux基础第三天

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

MoodDrop:打造一款温柔的心情打卡单页应用

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

接口——类比摄像

最近迷上了买相机&#xff0c;大疆Pocket、Insta Go3、大疆Mini3、佳能50D、vivo徕卡人像大师&#xff08;狗头&#xff09;&#xff0c;在买配件的时候&#xff0c;发现1/4螺口简直是神中之神&#xff0c;这个万能接口让我想到计算机设计中的接口&#xff0c;遂有此篇—— 接…

二十、案例特训专题3【系统设计篇】web架构设计

一、前言 二、内容提要 三、单机到应用与数据分离 四、集群与负载均衡 五、集群与有状态无状态服务 六、ORM 七、数据库读写分离 八、数据库缓存Memcache与Redis 九、Redis数据分片 哈希分片如果新增分片会很麻烦&#xff0c;需要把之前数据取出来再哈希除模 一致性哈希分片是…

【数据结构与算法】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…

【图像处理基石】OpenCV中都有哪些图像增强的工具?

OpenCV 图像增强工具系统性介绍 OpenCV 提供了丰富的图像增强工具&#xff0c;主要分为以下几类&#xff1a; 亮度与对比度调整 线性变换&#xff08;亮度/对比度调整&#xff09;直方图均衡化自适应直方图均衡化&#xff08;CLAHE&#xff09; 滤波与平滑 高斯滤波中值滤波双…

WPS PPT设置默认文本框

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

PostGIS实现矢量数据转栅格数据【ST_AsRaster】

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

FAST-DDS源码分析PDP(一)

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

python打卡day29@浙大疏锦行

知识点回顾 类的装饰器装饰器思想的进一步理解&#xff1a;外部修改、动态类方法的定义&#xff1a;内部定义和外部定义 作业&#xff1a;复习类和函数的知识点&#xff0c;写下自己过去29天的学习心得&#xff0c;如对函数和类的理解&#xff0c;对python这门工具的理解等&…

【数据结构】2-3-1单链表的定义

数据结构知识点合集 知识点 单链表存储结构 优点&#xff1a;不要求大片连续空间&#xff0c;改变容量方便&#xff1b;缺点&#xff1a;不可随机存取&#xff0c;要耗费一定空间存放指针 /*单链表节点定义*/ typedef struct LNode{ElemType data;struct LNode *next; }LNo…

贝塞尔曲线原理

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

3D个人简历网站 4.小岛

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

创建型:原型模式

目录 1、核心思想 2、实现方式 2.1 基本结构 2.2 代码示例&#xff08;Java&#xff09; 3、适用场景 4、new与clone实际场景建议 1、核心思想 目的&#xff1a;通过复制&#xff08;克隆&#xff09;现有对象来创建新对象&#xff0c;而不是通过new关键字实例化。对于那…