Springboot项目快速实现过滤器功能

news2025/2/25 7:05:40

前言

很多时候,当你以为掌握了事实真相的时间,如果你能再深入一点,你可能会发现另外一些真相。比如面向切面编程的最佳编程实践是AOP,AOP的主要作用就是可以定义切入点,并在切入点纵向织入一些额外的统一操作,避免与业务代码过度耦合。熟悉java web项目的都知道,另外还有过滤器(filter)、拦截器(interceptor)也有类似AOP的功能特性,那么问题来了:为什么一般说面向切面编程就是指AOP,而不是过滤器和拦截器?过滤器和拦截器在Spring boot中怎么实现?这三者之间有什么区别?Springboot项目快速实现Aop功能中分享了AOP的相关实现,下面将再用两到三篇文章,分别和大家分享一下过滤器、拦截器的实现,以及AOP、过滤器、拦截器之间的横向对比,以便在业务开发中,能够快速、正确选对具体实现方法。

环境配置

jdk版本:1.8

开发工具:Intellij iDEA 2020.1

springboot:2.3.9.RELEASE

Filter简介

Filter, 中文意思是过滤器,Filter的全限定类名是javax.servlet.Filter,可以看出这是与servelt相关的一个接口;SpringMVC核心是DispatcherServlet,而DispatcherServlet又继承了Servlet,进而可以推测出Filter与SpringMVC也是关联关系。

事实上这样的推测也是正确的,在SpringMVC项目中,filter在浏览器与服务器之间起过滤的作用,可以截取客户端和服务端之间的请求和响应信息,并根据这些请求-响应信息作一些其他的操作,但是要注意,filter并不能改变请求-响应信息;

核心类

Filter

Filter接口的全限定类名是javax.servlet.Filter,该接口有三个方法,分别是

1、init(...):用于初始化Filter;

2、doFilter(...):过滤请求和拦截响应信息的具体实现在这个方法里;

3、destroy(...):Filter对象被销毁时触发,主要用于做一些收尾工作,如资源的释放等;

FilterConfig

FilterConfig接口的全限定类名是javax.servlet.FilterConfig,该接口主要有四个方法,分别是:

1、getFilterName() 获取Filter的名字;

2、getServletContext() 获取ServletContext对象(即application);

3、getInitParameter() 获取Filter的初始化参数;

4、getInitParameterNames() 获取所有初始化参数的名字;

FilterChain

FilterChainr接口的全限定类名是javax.servlet.FilterChain,该接口只有一个方法,是doFilter()方法,用于调用Filter链上的下一个过滤器,如果当前过滤器为最后一个或只有一个过滤器,则该过滤器则将请求发送到目标资源。

MyFilter2是自己实现的过滤器,实现了Filter接口;Filter接口依赖FilterChain接口和FilterConfig接口,其中FilterChain接口的实现类是org.apache.catalina.core.ApplicationFilterChain,FilterConfig接口的实现类是org.apache.catalina.core.ApplicationFilterConfig;

工作原理

1、项目启动的时候,先执行Filter的构造方法,完成相关Filter对象的注册;

2、紧接着,Filter对象的init()方法被调用,开始对Filter做一些初始化操作;

3、项目启动完成后,客户端每次向服务端发起请求时,如果请求地址与过滤器定义的地址匹配,则会执行Filter的doFilter();如果匹配上多个过滤器,则会形成一个链路,依次调用各个过滤器对象的doFilter();服务端作出响应后,也会再次执行到各个过滤器对象的doFilter();请求和响应时,过滤器链的执行顺序是先进后出;

4、服务器停止时调用Filter的destroy()方法,用来释放资源。

实现方式

Springboot项目中一般有两种方式:

1、@WebFilter注解,即javax.servlet.annotation.WebFilter;

2、FilterRegistrationBean,即org.springframework.boot.web.servlet.FilterRegistrationBean;

两种方式,都需要在启动类上增加注解@ServletComponentScan,用于开启servlet相关bean的扫描,其中包含有过滤器(Filter);

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

代码实现

1、WebFilter注解里,定义一下过滤器的名字,以及要对哪些请求进行过滤,“/*”表示对所有的请求都过滤,在实际业务中,可具体对待;如果在初始化的时候,需要携带一些初始化的参数,可以在initParams属性上,使用@WebInitParam注解来定义初始化参数名称和具体的值,这些参数可以在filter对象初始化的时候获取到;MyFIlter1和MyFIlter2使用的注解方式定义的过滤器;

@Slf4j
@WebFilter(filterName = "myFilter1", urlPatterns = "/*", initParams = {@WebInitParam(name = "creator", value = "fanfu")})
public class MyFilter1 implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("//myFilter1初始化开始");
        String creator = filterConfig.getInitParameter("creator");
        log.info("//初始化参数creator:{}",creator);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        log.info("//myFilter1开始执行");
        chain.doFilter(request, response);
        log.info("//myFilter1结束执行");
    }

    @Override
    public void destroy() {
        log.info("//myfilter1被销毁");
    }
}
@Slf4j
@WebFilter(filterName = "myFilter2", urlPatterns = "/*")
public class MyFilter2 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("//myFilter2初始化开始");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        log.info("//myFilter2开始执行");
        chain.doFilter(request, response);
        log.info("//myFilter2结束执行");
    }

    @Override
    public void destroy() {
        log.info("//myFilter2被销毁");
    }
}

2、FilterRegistrationBean方式

在Springboot项目的配置类中,使用FilterRegistrationBean来包装自定义的过滤器,这种方式的最大好处就是可以自定义过滤器的执行顺序,数字越小,执行时的优先级就越高;MyFIlter3和MyFIlter4是使用FilterRegistrationBean方式定义的过滤器;

@Configuration
public class WebConfig {

    @Bean
    public FilterRegistrationBean filterRegistration1() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new MyFilter3());
        filterRegistrationBean.addUrlPatterns("/*");//定义过滤器对哪些请求路径进行过滤,/*表示对所有请求都过滤
        filterRegistrationBean.setOrder(2);//定义过滤器的执行优先级,数据越小优先级越高
        return filterRegistrationBean;
    }

    @Bean
    public FilterRegistrationBean filterRegistration2() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new MyFilter4());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.setOrder(1);
        return filterRegistrationBean;
    }
}
@Slf4j
public class MyFilter3 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    log.info("//MyFilter3初始化开始");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        log.info("//MyFilter3开始执行");
        chain.doFilter(request,response);
        log.info("//MyFilter3结束执行");
    }

    @Override
    public void destroy() {
        log.info("//MyFilter3被销毁");
    }
}
@Slf4j
public class MyFilter4 implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("//MyFilter4初始化开始");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        log.info("//MyFilter4开始执行");
        chain.doFilter(request,response);
        log.info("//MyFilter4结束执行");
    }

    @Override
    public void destroy() {
        log.info("//MyFilter4被销毁");
    }
}

未定义myFilter3、myFilter4的执行优先级,即采取自然排序时的执行结果:在请求前myFilter3的执行时机早于myFilter4,响应后myFilter3的执行时机要晚于myFilter4;

定义myFilter4的优先级高于myFilter3时,执行结果:在请求前myFilter4的执行时机早于myFilter3,响应后的myFilter4的执行时机要晚于myFilter3;

总结

过滤器的实现是比较简单,通过梳理这个过程,我get到以下几个点:

1、过滤器是用于SpringMVC项目中,即与servlet相关的项目;

2、过滤器的执行时机是在请求前和响应后,有两种实现方式,即@WebFilter注解和FilterRegistrationBean;如果对过滤器的执行顺序没有限制要求,则可以使用第一种;如果对过滤器的执行顺序有明确限制,则可以使用第二种;

3、如果有多个过滤器对象时,会形成一个过滤器链,过滤器的执行顺序是先进后出;

4、过滤器可以过滤请求和拦截响应,但是不能改变请求值和响应值;

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

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

相关文章

尚硅谷大数据技术Spark教程-笔记01【Spark(概述、快速上手、运行环境、运行架构)】

视频地址:尚硅谷大数据Spark教程从入门到精通_哔哩哔哩_bilibili 尚硅谷大数据技术Spark教程-笔记01【Spark(概述、快速上手、运行环境、运行架构)】尚硅谷大数据技术Spark教程-笔记02【SparkCore(核心编程、案例实操)】尚硅谷大数据技术Spark教程-笔记03【SparkSQL…

Scala之面向对象(2)

目录 单例对象(伴生对象): 创建对象常用的两种方法: (1)使用构造器构造(new) (2)使用静态方法 伴生对象的定义: apply方法: app…

图像分割技术及经典实例分割网络Mask R-CNN(含基于Keras Python源码定义)

图像分割技术及经典实例分割网络Mask R-CNN(含Python源码定义) 文章目录图像分割技术及经典实例分割网络Mask R-CNN(含Python源码定义)1. 图像分割技术概述2. FCN与语义分割2.1 FCN简介2.2 反卷积2.2 FCN与语义分割的关系3. Mask …

Midjourney以图生图的详细教程(含6种案例介绍)

🏆 文章目标:学习并介绍Midjourney以图生图的详细教程 🍀 Midjourney以图生图的详细教程 ✅ 创作者:熊猫Jay 🎉 个人主页:Jay的个人主页 🍁 展望:若本篇讲解内容帮助到您&#xff0c…

SQL Server 单表数据查询

提示: 本篇文章详细介绍怎样向SQLServer中导入表格数据,导入之后根据不同的查询条件完成查询任务. 文章目录前言一、向SQL Server中导入数据二、例题1.查询所有学生的全部信息2.查询学生的学号和姓名3.查询所有学生的姓名和出生年4. 查询所有学生的姓名和出生年&…

【关于Linux中----生产消费模型】

文章目录一、生产消费模型1.1概念的引入1.2 321原则二、条件变量2.1概念的引入2.2理解条件变量2.3条件变量的使用三、基于BlockingQueue的生产者消费者模型3.1BlockingQueue的介绍3.2C queue模拟阻塞队列的生产消费模型3.3对生产消费任务的模拟封装四、遗留问题一、生产消费模型…

基于YOLOv5的水下海洋目标检测

摘要:水下海洋目标检测技术具有广泛的应用前景,可以用于海洋环境监测、海洋资源开发、海洋生物学研究等领域。本文提出了一种基于 YOLOv5 的水下海洋目标检测方法,使用数据增强方法进行了大量实验,并与其他方法进行了对比&#xf…

(SQL学习随笔3)SQL语法——SELECT语句

导航基本认识FROM关键字LIMIT与OFFSETORDER BYWHERE条件查询单值比较多条件组合范围筛选空值匹配LIKE通配条件分组运算符和函数数据变换分组运算表连接内连接左(右)外连接全外连接外键约束窗口函数UNION:表上下拼接子查询条件判断PostgreSQLMySQL基本认识 SELECT t…

【论文阅读】BiSeNet V2用于实时语义分割的双边网络

前言BiSeNet V2延续了v1版本的双边结构,分别处理空间细节信息、高层语义信息。同时设计更简洁高效的结构,进行特征提取,实现高精度和高速度。在训练模型时,使用了增强训练策略 ,添加多个辅助训练分支来促进不同浅层网络…

Spring-aop面向切面

1、理解必要的专业术语 先看看上面图,这是我的个人理解。(画的丑,主打真实) 1)Advice,通知/增强:类方法中提出来的共性功能(大白话就是提出来的重复代码) 2)Pointcut,切入点/切点&#…

【微服务】微服务架构下你不得不知的3种部署策略

文章目录前言滚动部署蓝绿部署金丝雀部署总结前言 不知道大家有了解过你们公司的软件产品是如何部署的么?采用的什么部署策略?其实在软件开发生命周期中,部署是非常关键的一环,你需要考虑多方面的因素,如何保证你部署…

【推荐算法】CTR中embedding层的学习和训练

note 连续特征处理:facebook DLRM模型,对连续值的处理方式是把所有的连续值输入到一个神经网络,然后通过神经网络把它压缩到一个embedding维度大小的一个向量上,然后将Embedding和其他离散特征Embedding Concat起来,再…

springboot-分页功能

1.分页功能的作用 分页功能作为各类网站和系统不可或缺的部分(例如百度搜索结果的分页等) ,当一个页面数据量大的时候分页作用就体现出来的,其作用有以下5个。 (1)减少系统资源的消耗 (2&#…

redis设计与实现读书笔记

这里主要记录一下在阅读redis设计与实现中碰到的一些没有记录过的知识。 引用计数技术 Redis的对象系统实现了基于引用计数技术的内存回收机制,当程序不再使用某个对象的时候,这个对象所占用的内存就会被自动释放;另外,Redis还通过引用计数…

低调且强大--iVX低代码平台

iVX目录前言一、低代码那么多 为什么选择iVX?二、“拼”出来的低代码平台,真的好用吗?三、iVX与其他低代码有啥可比性?前言 首先我们应该明白自动编程突破可能是:领域内Mini LLM 现在的思路都是搞LLM,几乎像…

通俗举例讲解动态链接、静态链接

参考动态链接 - 知乎 加上我自己的理解,比较好懂,但可能在细节方面有偏差,但总体是一致的 静态链接的背景 静态链接使得不同的程序开发者和部门能够相对独立的开发和测试自己的程序模块,从某种意义上来讲大大促进了程序开发的效率&#xf…

NPC 也有了生命?当 ChatGPT 注入游戏你能想象吗

🍎道阻且长,行则将至。🍓 目录引言:西部世界元宇宙,还记得吗ChatGPT 的世界?下图就是一个 ChatGPT 小镇: 引言:西部世界 《西部世界》以一个虚构的游戏般的“西部世界”为背景&am…

springboot验证码生成及验证功能

1.easy-captcha工具包 生成验证码的方式有许多种,这里选择的是easy-captcha工具包。 github开原地址为:easy-captcha工具包 其支持Java图形验证码,支持gif、中文、算术等类型,可用于Java Web、JavaSE等项目。 2添加依赖 首先需…

SQL Server的死锁说明

死锁指南一、了解死锁二、检测并结束死锁2.1、可能死锁的资源三、处理死锁四、最大限度地减少死锁4.1、以相同的顺序访问对象4.2、避免事务中的用户交互4.3、保持交易简短且在一个批次中4.4、使用较低的隔离级别4.5、使用基于行版本控制的隔离级别4.6、使用绑定连接4.7、停止事…

【云原生|Docker】04-docker的资源限制

目录 前言 容器的生命周期 1. 容器的启动过程 2. 容器的生命周期 ​编辑 内存限制 1. 内存限制的相关参数 2. 内存限制方式 2.1 设置-m,--memory,不设置--memory-swap 2.2 设置-m,--memorya,--memory-swapb,且b >a 2.…