SpringBoot十二、SpringBoot系列web篇之过滤器Filte详解

news2025/6/9 18:24:50

一、前言

JavaWeb三大组件Servlet、Filter、Listener,其中之一便是过滤器Filter。

其实,Filter我们平常用的不多,一般多为项目初期搭建web架构的时候使用,后面用的就少了,在日常业务开发中不太可能碰到需要手写Filter的场景。

下面我们两带着以下几个问题,学习一下SpringBoot中怎样使用Filter。

  • 在SpringBoot中如何配置Filter过滤器?
  • 过滤器Filter在SpringBoot中的执行顺序是怎样的?
  • 如何在SpringBoot中使用自定义的Filter过滤器?

 

二、Filter过滤器

1. Filter简介

Filter,过滤器,属于Servlet规范,并不是Spring独有的。Filter在web服务器中,位于浏览器与Servlet之间。
其作用是拦截一个请求,做一些业务逻辑操作,比如:登录校验、统一编码处理、敏感字符处理等。

 

2. 简介Filter流程

Filter在web服务器中,位于浏览器与Servlet之间,当请求进入web服务器时进行预处理,然后交Servlet,Servlet处理完成后,将响应传递给Filter进行后处理,之后才到达客户端的浏览器。
有时会设置多个Filter过滤器,经过Filter1处理后进入Filter2,之后也许还有Filter3,这样就形成了Filter链。而在Filter链中,只要有一处不放行,后续的检测都不会发生。
过滤器通过后,就可以访问web服务器上的资源。
在这里插入图片描述

 

三、自定义Filter过滤器

1. 引入web依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

 

2. 自定义过滤器

第1步:创建过滤器类
定义一个类MyFilter,实现 Filter 接口,并重写其所有方法。

第2步:配置过滤器
在自定义过滤器MyFilter类上加 @WebFilter 注解,配置拦截资源的路径。

public class MyFilter implements Filter {
    @Override //初始化方法, 只调用一次
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init 初始化方法执行了");
    }

    @Override //拦截到请求之后调用, 调用多次
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("Demo 拦截到了请求...放行前逻辑");
        //放行
        chain.doFilter(request,response);
    }

    @Override //销毁方法, 只调用一次
    public void destroy() {
        System.out.println("destroy 销毁方法执行了");
    }
}

说明:

  • init方法:过滤器的初始化方法。在web服务器启动> 的时候会自动的创建Filter过滤器对象,在创建过滤> 器对象的时候会自动调用init初始化方法,这个方法> 只会被调用一次。
  • doFilter方法:这个方法是在每一次拦截到请求之后都会被调用,所以这个方法是会被调用多次的,每拦截到一次请求就会调用一次doFilter()方法。
  • destroy方法: 是销毁的方法。当我们关闭服务器的时候,它会自动的调用销毁方法destroy,而这个销毁方法也只会被调用一次。

 

3. Filter的配置

在定义完Filter之后,Filter其实并不会生效,并不会被SpringBoot加载,还需要完成Filter的配置。

SpringBoot项目中,配置Filter生效有三种常见方式(注解和配置Bean):

  • @WebFilter(如果存在多个Filter,则不推荐;单个Filter推荐。)
  • FilterRegistrationBean注册方式
  • 在web.xml中配置

 

3.1 方式一、@WebFilter注解方式

Filter的配置注解方式非常简单:

  1. 只需要在自定义过滤器MyFilter类上添加一个注解:@WebFilter,并指定属性urlPatterns(通过这个属性指定过滤器要拦截哪些请求);
  2. 在启动类上面加上一个注解@ServletComponentScan,通过这个@ServletComponentScan注解来开启SpringBoot项目对于Servlet组件的支持。

注解方式加载-自定义过滤器:

@WebFilter(urlPatterns = "/*") //配置过滤器要拦截的请求路径( /* 表示拦截浏览器的所有请求 )
public class MyFilter implements Filter {
    @Override //初始化方法, 只调用一次
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init 初始化方法执行了");
    }

    @Override //拦截到请求之后调用, 调用多次
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("Demo 拦截到了请求...放行前逻辑");
        //放行
        chain.doFilter(request,response);
    }

    @Override //销毁方法, 只调用一次
    public void destroy() {
        System.out.println("destroy 销毁方法执行了");
    }
}

启动类上加@ServletComponentScan注解:

@ServletComponentScan
@SpringBootApplication
public class TliasWebManagementApplication {
    public static void main(String[] args) {
        SpringApplication.run(TliasWebManagementApplication.class, args);
    }
}

注意: 注解方式配置Filter会有个小问题,即指定Filter的优先级比较麻烦,如果存在多个FIlter,则无法指定优先级。这个问题后续说明!!!

 

3.2 @WebFilter注解说明
  • @WebFilter注解属于Servlet3+,与Spring也没有什么关系。

  • @WebFilter注解常用属性如下,其中urlPatterns最为常用,表示这个filter适用于哪些url请求(默认场景下全部请求都被拦截)。

WebFilter常用属性:

属性名类型描述
filterNameString指定过滤器的 name 属性,等价于 <filter-name>
valueString[]该属性等价于 urlPatterns 属性。但是两者不应该同时使用。
urlPatternsString[]指定一组过滤器的 URL 匹配模式。等价于 <url-pattern> 标签。比如:/*指的是所有请求。
servletNamesString[]指定过滤器将应用于哪些 Servlet。取值是 @WebServlet 中的 name 属性的取值,或者是 web.xml 中<servlet-name> 的取值。
dispatcherTypesDispatcherType指定过滤器的转发模式。具体取值包括:ASYNC、ERROR、FORWARD、INCLUDE、REQUEST。
initParamsWebInitParam[]指定一组过滤器初始化参数,等价于 <init-param> 标签。
asyncSupportedboolean声明过滤器是否支持异步操作模式,等价于 <async-supported> 标签。
descriptionString该过滤器的描述信息,等价于 <description> 标签。
displayNameString该过滤器的显示名,通常配合工具使用,等价于 <display-name> 标签。

 
拦截路径(urlPatterns)说明:

拦截路径urlPatterns值含义
拦截具体路径/login只有访问 /login 路径时,才会被拦截
目录拦截/liupy/*访问/liupy下的所有资源,都会被拦截
拦截所有/*访问所有资源,都会被拦截

 

3.3 方式二、FilterRegistrationBean 注册方式

下面是使用包装bean注册方式。
首先需要新建一个配置类MybootWebConfig,该配置类中定义一个Bean,在该bean中注册自定义的过滤器。

自定义过滤器:

public class MyFilter implements Filter {
    @Override //初始化方法, 只调用一次
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init 初始化方法执行了");
    }

    @Override //拦截到请求之后调用, 调用多次
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("Demo 拦截到了请求...放行前逻辑");
        //放行
        chain.doFilter(request,response);
    }

    @Override //销毁方法, 只调用一次
    public void destroy() {
        System.out.println("destroy 销毁方法执行了");
    }
}

自定义配置文件:

@Configuration
public class MybootWebConfig implement WebMvcConfig {
public MybootWebConfig(){}
@Bean
public FilterRegistrationBean<Filter> orderFilter() {
    FilterRegistrationBean<Filter> filter = new FilterRegistrationBean<>();
    filter.setName("reqFilter");
    //注册自定义过滤器
    filter.setFilter(new MyFilter()); //MyFilter是自定义过滤器
    // 指定优先级
    filter.setOrder(-1);
    filter.addUrlPatterns(new String[]{"/*"});
    return filter;
}
}

 

四、过滤器链

过滤器链:指的是在一个web应用程序当中,可以自定义并配置多个过滤器,多个过滤器就形成了一个过滤器链。

比如:在我们web服务器当中,定义了两个过滤器,这两个过滤器就形成了一个过滤器链。而这个链上的过滤器在执行的时候会一个一个的执行,会先执行第一个Filter,放行之后再来执行第二个Filter,如果执行到了最后一个过滤器放行之后,才会访问对应的web资源。

访问完web资源之后,按照我们刚才所介绍的过滤器的执行流程,还会回到过滤器当中来执行过滤器放行后的逻辑,而在执行放行后的逻辑的时候,顺序是反着的。先要执行过滤器2放行之后的逻辑,再来执行过滤器1放行之后的逻辑,最后在给浏览器响应数据。

在这里插入图片描述

 

五、Filter链的处理顺序

5.1. 指定FIlter顺序遇到的问题

上面我们说过,如果web项目中存在多个Filter过滤器(即过滤器链),注解方式在指定Filter过滤器的执行顺序时,很难控制执行顺序。

如果设置了多个Filter,如何设置多个Filter之间的处理顺序?有以下两种做法:

  • 注解方式(不推荐):@Order(1)注解无法明确控制不同Filter的执行顺序,此时会按Filter类名字母顺序进行处理。如AFilter会先于BFilter执行; 如果只有一个Filter过滤器,则推荐,因为配置简单。
  • web.xml方式(推荐):当请求到来时按照<filter-mapping></filter-mapping>中的顺序,从上到下进行处理。 当响应返回时,按照<filter-mapping></filter-mapping>中,从下到上进行处理(逆序)。
  • 配置类中bean注册方式(推荐)。在配置类中,注册自定义Filter过滤器时,可以设置顺序:myFilter.setOrder(-1)。

 

5.2. 指定FIlter顺序演示

如下为自定义FIlter过滤器:

@Order(2)
@WebFilter
public class AnyFilter implements Filter, Ordered {
  ...
}

@Order(1)
@WebFilter
public class ReqFilter implements Filter, Ordered {
  ...
}

public class OrderFilter implements Filter {
}

/** 启动类 */
@ServletComponentScan
@SpringBootApplication
public class Application {

	/** 注册自定义过滤器 OrderFilter*/
    @Bean
    public FilterRegistrationBean<OrderFilter> orderFilter() {
        FilterRegistrationBean<OrderFilter> filter = new FilterRegistrationBean<>();
        filter.setName("orderFilter");
        filter.setFilter(new OrderFilter());
        //设定优先级
        filter.setOrder(-1);
        return filter;
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }
}
  • 通过实际测试,@Order注解没有用,继承 Ordered接口也没有用,再不考虑web.xml配置的场景下,只能通过在注册Bean的时候指定优先级。
  • 如上实例:三个Filter,两个通过@WebFilter注解方式注册,一个通过FilterRegistrationBean方式注册。

结论:

  1. 自定义Filter过滤器的优先级为:OrderFiler > AnyFilter >ReqFilter ;
  2. 显然,OrderFilter过滤器的优先级最高,因为OrderFilter是通过FilterRegistrationBean方式注册,并且手动注册时,并设置优先级为-1,所以先执行。
  3. AnyFilter 、ReqFilter 这两个自定义过滤器,都是注解方式,AnyFilter 设置为2,ReqFilter 设置为1,但是结果却是AnyFilter 优先级大于ReqFilter ,说明@Order注解不能指定Filter的优先级。
  4. 采用@WebFilter注解方式使用过滤器时,会按照 “自定义过滤器Filter类名字母先后顺序” 进行处理, 所以AnyFilter 会先于ReqFilter 执行。

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

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

相关文章

【RTSP从零实践】1、根据RTSP协议实现一个RTSP服务

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

行为设计模式之Iterator(迭代器)

行为设计模式之Iterator&#xff08;迭代器&#xff09; 摘要&#xff1a; 迭代器模式(Iterator)是一种行为设计模式&#xff0c;它提供顺序访问聚合对象元素的方法&#xff0c;同时不暴露内部结构。该模式由迭代器接口(Iterator)、具体迭代器(ConcreteIterator)、聚合接口(Ag…

FPGA点亮ILI9488驱动的SPI+RGB接口LCD显示屏(一)

FPGA点亮ILI9488驱动的SPIRGB接口LCD显示屏 ILI9488 RGB接口初始化 目录 前言 一、ILI9488简介 二、3线SPI接口简介 三、配置寄存器介绍 四、手册和初始化verilog FPGA代码 总结 前言 ILI9488是一款广泛应用于嵌入式系统和电子设备的彩色TFT LCD显示控制器芯片。本文将介…

如何实现本地mqtt服务器和云端服务器同步?

有时候&#xff0c;一个物联网项目&#xff0c;A客户想要本地使用&#xff0c;B客户想要线上使用&#xff0c;C客户想要本地部署&#xff0c;当有网环境时能线上使用。这个时候就需要本地MQTT服务和线上MQTT服务能相互自动转发。 后来经我一翻研究&#xff0c;其实Activemq支持…

windows10下搭建nfs服务器

windows10下搭建nfs服务器 有参考这篇博客 Windows10搭建NFS服务 - fuzidage - 博客园 下载 NFS Server这个app 通过网盘分享的文件&#xff1a;nfs1268 (1).exe 链接: https://pan.baidu.com/s/1rE4h710Uh-13kWGXvjkZzw 提取码: mwa4 --来自百度网盘超级会员v5的分享 下载后…

华为云Flexus+DeepSeek征文|Dify - LLM 云服务单机部署大语言模型攻略指南

前言&#xff1a;在当今人工智能快速发展的时代&#xff0c;华为云推出的 Dify - LLM 对话式 AI 开发平台为企业和开发者提供了便捷的大语言模型应用开发解决方案。 通过在华为云 Flexus 云服务器上单机部署 Dify&#xff0c;并成功集成 DeepSeek 模型&#xff0c;我们能够快速…

JAVA反序列化应用 : URLDNS案例

反序列化的基本原理 基础普及 &#xff1a; 对象初始化数据方法 &#xff1a;1、使用构造方法 2、使用封装中的 set,get方法 这边我们就使用 1 注意 我们之后还需要进行 接入 序列化的接口 &#xff1a; 先进行序列化 &#xff1a; 反序列化&#xff1a; 反序列化导致的安…

Vue-Leaflet地图组件开发(三)地图控件与高级样式设计

第三篇&#xff1a;Vue-Leaflet地图控件与高级样式设计 1. 专业级比例尺组件实现 1.1 比例尺控件集成 import { LControl } from "vue-leaflet/vue-leaflet";// 在模板中添加比例尺控件 <l-control-scaleposition"bottomleft":imperial"false&qu…

174页PPT家居制造业集团战略规划和运营管控规划方案

甲方集团需要制定一个清晰的集团价值定位&#xff0c;从“指引多元”、“塑造 能力”以及“强化协同”等方面引领甲方做大做强 集团需要通过管控模式、组织架构及职能、授权界面、关键流程、战略 实施和组织演进路径&#xff0c;平衡风险控制和迅速发展&#xff0c;保证战略落地…

wsl开启即闪退

[ 问题 ]&#xff1a; 在一次电脑卡住&#xff0c;强制关机重启后&#xff0c;遇到打开WSL就闪退的问题在CMD中打开WSL&#xff0c;出现如上图的描述&#xff1a; C:\Users\admin>wsl wsl: 检测到 localhost 代理配置&#xff0c;但未镜像到 WSL。NAT 模式下的 WSL 不支持…

【P2P】直播网络拓扑及编码模式

以下从 P2P 直播的常见拓扑模式出发,分析各种方案的特点与适用场景,并给出推荐。 一、P2P 直播的核心挑战 实时性要求高 直播场景下,延迟必须控制在可接受范围(通常 <2 秒),同时要保证画面连贯、不卡顿。带宽分布不均 每个节点(观众)上传带宽与下载带宽差异较大,且…

Python数据可视化科技图表绘制系列教程(二)

目录 表格风格图 使用Seaborn函数绘图 设置图表风格 设置颜色主题 图表分面 绘图过程 使用绘图函数绘图 定义主题 分面1 分面2 【声明】&#xff1a;未经版权人书面许可&#xff0c;任何单位或个人不得以任何形式复制、发行、出租、改编、汇编、传播、展示或利用本博…

低空城市场景下的多无人机任务规划与动态协调!CoordField:无人机任务分配的智能协调场

作者&#xff1a;Tengchao Zhang 1 ^{1} 1 , Yonglin Tian 2 ^{2} 2 , Fei Lin 1 ^{1} 1, Jun Huang 1 ^{1} 1, Patrik P. Sli 3 ^{3} 3, Rui Qin 2 , 4 ^{2,4} 2,4, and Fei-Yue Wang 5 , 1 ^{5,1} 5,1单位&#xff1a; 1 ^{1} 1澳门科技大学创新工程学院工程科学系&#xff0…

算法-构造题

#include<iostream> #include<bits/stdc.h> using namespace std; typedef long long ll; const ll N 5e5 10; int main() {ll n, k;cin >> n >> k; ll a[N] {0}; // 初始化一个大小为N的数组a&#xff0c;用于存储排列// 构造满足条件的排列for (l…

【Linux】进程的基本概念

目录 概念描述进程-PCB如何查看进程通过系统目录进行查看通过ps指令进行查看 通过系统调用获取进程的PID和PPID(进程标⽰符)通过系统调用创建子进程通过一段代码来介绍fork为什么要有子进程&#xff1f;fork为什么给子进程返回0&#xff0c;给父进程返回子进程的PIDfork函数到底…

设备驱动与文件系统:05 文件使用磁盘的实现

从文件使用磁盘的实现逻辑分享 我们现在讲第30讲&#xff0c;内容是文件使用磁盘的具体实现&#xff0c;也就是相关代码是如何编写的。上一节我们探讨了如何从字符流位置算出盘块号&#xff0c;这是文件操作磁盘的核心。而这节课&#xff0c;我们将深入研究实现这一核心功能的…

AI数据分析在体育中的应用:技术与实践

在现代体育竞技领域&#xff0c;"数据驱动"已不再是一个遥远的概念。尤其随着人工智能&#xff08;AI&#xff09;和大数据分析的不断成熟&#xff0c;从职业俱乐部到赛事直播平台&#xff0c;从运动员训练到球迷观赛体验&#xff0c;AI正以前所未有的方式渗透并改变…

zabbix 6 监控 docker 容器

zabbix 6 监控 docker 容器 1.安装zabbix_agent2 curl -s http://10.26.211.56:8080/centos7-agent2-install.sh | bash2.在zabbix server 端测试 zabbix_get -s 10.26.219.180 -k docker.infoZBX_NOTSUPPORTED: Cannot fetch data: Get "http://1.28/info": dial…

正则持续学习呀

源匹配为 (.*): (.*)$ 替换匹配为 "$1": "$2", 可将headers改为字典 参考 【爬虫军火库】如何优雅地复制请求头 - 知乎

Go基本语法——go语言中的四种变量定义方法

前言 在go语言中&#xff0c;定义一个变量有四种方式&#xff0c;本文单从语法的层面来介绍这几种方式 单变量定义方法 1.var 变量名 类型&#xff0c;不进行初始化 例如&#xff0c;定义一个变量a后为其赋值&#xff0c;并且打印其值&#xff0c;运行结果如下 //1.不进行…