拦截器和过滤器(原理区别)

目录

一、拦截器

拦截器是什么

拦截器的使用

拦截器的实现

导入依赖

实现HandlerInterceptor接口

注册拦截器

拦截器的生命周期

拦截器的执行顺序

拦截器的生命周期

多个拦截器的执行流程

拦截器的实际使用

拦截器实现日志记录

实现接口幂等性校验

拦截器的性能优化

二、过滤器

过滤器是什么

过滤器的使用

过滤器的实现

创建过滤器

开启URL过滤

过滤器的生命周期

多个Filter的执行顺序

三、过滤器和拦截器的区别

相同

底层原理

使用范围不同

触发时机不同

控制执行的顺序不同


一、拦截器

拦截器是什么

拦截器(Interceptor)是一种特殊的组件,它是基于反射进行实现。它可以在请求处理的过程中对请求和响应进行拦截和处理。拦截的是servlet 和 controller 之间的请求和响应。

拦截器的使用

  • 权限控制:拦截器可以在请求到达处理器之前进行权限验证,从而实现对不同用户的访问控制。

  • 日志记录:拦截器可以在请求处理过程中记录请求和响应的详细信息,便于后期分析和调试。

  • 接口幂等性校验:拦截器可以在请求到达处理器之前进行幂等性校验,防止重复提交。

  • 数据校验:拦截器可以在请求到达处理器之前对请求数据进行校验,确保数据的合法性。

  • 缓存处理:拦截器可以在请求处理之后对响应数据进行缓存,提高系统性能。

拦截器的实现

导入依赖

如果是使用的是springboot项目的话,直接导入这个依赖,spring项目需要导入 web 依赖

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

实现HandlerInterceptor接口

要在SpringBoot中实现拦截器,首先需要创建一个类并实现HandlerInterceptor接口。HandlerInterceptor接口包含以下三个方法:

preHandle:在请求到达处理器之前执行,可以用于权限验证、数据校验等操作。如果返回true,则继续执行后续操作;如果返回false,则中断请求处理。

postHandle:在处理器处理请求之后执行,可以用于日志记录、缓存处理等操作。

afterCompletion:在视图渲染之后执行,可以用于资源清理等操作。

public class MainInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("我是处理之前!");return true;   //只有返回true才会继续,否则直接结束}
​@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("我是处理之后!");}
​@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("我是完成之后!");}
}

注册拦截器

要让拦截器生效,需要将其注册到InterceptorRegistry中。这可以通过实现WebMvcConfigurer接口并重写addInterceptors方法来实现。注册成功以后,我们还可以设置拦截的规则,拦截的路径,和不拦截的路径

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Autowiredprivate MainInterceptor customInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 添加拦截器,并设置拦截路径registry.addInterceptor(customInterceptor).addPathPatterns("/**").excludePathPatterns("/exclude/**");}
}

拦截器的生命周期

拦截器的执行顺序

当有多个拦截器时,它们的执行顺序取决于注册顺序。先注册的拦截器先执行,后注册的拦截器后执行。在请求处理过程中,拦截器的preHandle方法按注册顺序执行,而postHandle和afterCompletion方法按注册顺序的逆序执行。

拦截器的生命周期

拦截器的生命周期由Spring容器管理。当Spring容器启动时,拦截器会被实例化并初始化;当Spring容器关闭时,拦截器会被销毁。

多个拦截器的执行流程

当有多个拦截器时,它们的执行流程如下:

  1. 执行所有拦截器的preHandle方法,按注册顺序执行。如果某个拦截器的preHandle方法返回false,则中断请求处理,直接执行已执

  2. 拦截器的afterCompletion方法。

  3. 执行处理器的处理方法。

  4. 执行所有拦截器的postHandle方法,按注册顺序的逆序执行。

  5. 渲染视图。

  6. 执行所有拦截器的afterCompletion方法,按注册顺序的逆序执行。

拦截器的实际使用

拦截器实现日志记录

使用拦截器记录接口访问的记录,记录访问该接口的IP地址

@Component
public class MyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("request.getRemoteHost() = " + request.getRemoteHost());System.out.println("request.getParameter(\"id\") = " + request.getParameter("id"));return true;   //只有返回true才会继续,否则直接结束}
​@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {request.getParameter("id");System.out.println("我是处理之后!");}
​@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("我是完成之后!");}
}
​

实现接口幂等性校验

拦截器可以在请求到达处理器之前进行幂等性校验,防止重复提交。以下是一个简单的幂等性校验示例:

public class IdempotentInterceptor implements HandlerInterceptor {
​private static final String IDEMPOTENT_TOKEN = "idempotentToken";
​@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {String token = request.getHeader(IDEMPOTENT_TOKEN);if (StringUtils.isEmpty(token)) {throw new RuntimeException("Idempotent token is missing");}if (!checkIdempotentToken(token)) {throw new RuntimeException("Duplicate request");}return true;}
​private boolean checkIdempotentToken(String token) {// Check the token in the cache or database// Return true if the token is valid, false otherwise}
}
​
//在上述示例中,我们在preHandle方法中检查请求头中的幂等性令牌,如果令牌无效,则抛出异常并中断请求处理。

拦截器的性能优化

拦截器在请求处理过程中可能会影响系统性能,以下是一些性能优化策略:

  • 减少拦截器数量:尽量将相关功能集中到一个拦截器中,避免创建过多的拦截器。

  • 精确配置拦截规则:通过addPathPatterns和excludePathPatterns方法精确配置拦截规则,避免不必要的拦截。

  • 使用异步处理:在拦截器中使用异步处理,避免阻塞请求处理过程。

  • 使用缓存:在拦截器中使用缓存,减少对数据库或其他资源的访问。

二、过滤器

过滤器是什么

过滤器顾名思义就是对事物进行过滤的,在Web中的过滤器,当然就是对请求进行过滤,我们使用过滤器,就可以对请求进行拦截,然后做相应的处理,实现许多特殊功能。过滤器的实现是通过函数回调进行实现。

函数回调:它指的是将一个函数作为参数传递给另一个函数,并在特定事件发生时被调用执行的函数。这种方式使得在异步编程中,当某个操作完成后,系统能够调用预先定义好的回调函数来处理结果,从而避免阻塞程序的执行,提高程序的效率和响应速度。

过滤器的使用

  • 如登录控制

  • 权限管理

  • 过滤敏感词汇等

过滤器的实现

过滤器的配置比较简单,直接实现Filter 接口即可,也可以通过@WebFilter注解实现对特定URL拦截,看到Filter 接口中定义了三个方法。

创建过滤器

init() :该方法在容器启动初始化过滤器时被调用,它在 Filter 的整个生命周期只会被调用一次。注意:这个方法必须执行成功,否则过滤器会不起作用。 FilterConfig可以获取配置信息

doFilter() :容器中的每一次请求都会调用该方法, FilterChain 用来调用下一个过滤器 Filter。

默认就会传入Request和Response,这个参数封装了请求和响应,我们直接使用就行。ServletResquest和ServletResponse可以直接强转成HttpServletRequest和HttpServletResponse,然后使用相应的方法。

destroy(): 当容器销毁 过滤器实例时调用该方法,一般在方法中销毁或关闭资源,在过滤器 Filter 的整个生命周期也只会被调用一次

@Component
@WebFilter("/*") // 定义的过滤规则,只过滤对应的url请求
public class MyFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {
​System.out.println("Filter 前置");}
​@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
​System.out.println("Filter 处理中");filterChain.doFilter(servletRequest, servletResponse);}
​@Overridepublic void destroy() {
​System.out.println("Filter 后置");}
}
开启URL过滤

开启专门的Url过滤需要在启动类添加一个注解 @ServletComponentScan

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

过滤器的生命周期

  1. 初始化阶段(Initialization): 在 Servlet 容器启动时,会实例化所有的过滤器并调用其 init 方法进行初始化。在 init 方法中,过滤器可以进行一些初始化操作,例如读取配置文件、建立数据库连接等。该方法只会在过滤器实例化时调用一次。

  2. 请求处理阶段(Request Processing): 在请求到达 Servlet 前,过滤器可以对请求进行预处理。当请求与过滤器匹配时,Servlet 容器会调用过滤器的 doFilter 方法来处理请求。在 doFilter 方法中,过滤器可以执行一些操作,例如修改请求或响应内容、记录日志、验证权限等。如果请求不符合过滤器的条件,过滤器可以选择放行请求,将请求传递给下一个过滤器或目标 Servlet。

  3. 销毁阶段(Destruction): 在 Servlet 容器关闭时,会销毁所有的过滤器并调用其 destroy 方法进行清理。在 destroy 方法中,过滤器可以进行一些清理操作,例如释放资源、关闭连接等。该方法只会在过滤器销毁时调用一次。

多个Filter的执行顺序
  • 如果我们是在web.xml中配置的过滤器,那么过滤器的执行顺序就是<filter-mapping>在web配置的顺序,配置在上面那么就会先执行。

  • 如果我们是使用@WebFilter进行配置的,那么执行顺序就是字符比较顺序来执行,例如有2个过滤器,一个是AFilter,一个是BFilter,那么AFilter就会先执行。

  • 如果注解和xml混用,那么在web.xml中配置的会先执行。

三、过滤器和拦截器的区别

相同

二者都是体现了AOP的思想,都可以实现诸如日志记录、登录鉴权等功能,但二者的不同点也是比较多的,接下来一一说明。

底层原理

拦截器是使用反射进行实现,过滤器是基于函数回调进行实现

使用范围不同

过滤器 实现的是 javax.servlet.Filter 接口,而这个接口是在Servlet规范中定义的,也就是说过滤器Filter 的使用要依赖于Tomcat等容器,导致它只能在web程序中使用。

拦截器(Interceptor) 它是一个Spring组件,并由Spring容器管理,并不依赖Tomcat等容器,是可以单独使用的。不仅能应用在web程序中,也可以用于ApplicationSwing等程序中。

触发时机不同

过滤器拦截器的触发时机也不同,我们看下边这张图

过滤器Filter是在请求进入容器后,但在进入servlet之前进行预处理,请求结束是在servlet处理完以后。

拦截器 Interceptor 是在请求进入servlet后,在进入Controller之前进行预处理的,Controller 中渲染了对应的视图之后请求结束。·

控制执行的顺序不同

拦截器:是先声明的拦截器 preHandle() 方法先执行,而postHandle()方法反而会后执行。

为什么?

两个方法中在调用拦截器数组 HandlerInterceptor[] 时,循环的顺序竟然是相反的。导致postHandle()preHandle() 方法执行的顺序相反。

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

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

相关文章

STL——map set

文章将解决一下几个问题&#xff1a; 1.什么是set 2.什么是map 3.set应用场景 4.map应用场景 序列式容器和关联式容器 数据结构有序列式容器和关联式容器&#xff0c;序列式容器一般有vector,list,deque…&#xff0c;但关联式容器中就有map&#xff0c;关联式容器也是用来存…

Gis导航控件

收费工具&#xff0c;白嫖党、学生党、闹眼子党勿扰 收费金额为100元 1 概述 最近研究了一下电子海图相关内容&#xff0c;发现海图解析和显示相关的功能&#xff0c;都没有好用的开源工具… 在Gis地图显示那一块&#xff0c;有一个导航控件小控件&#xff0c;好像还没有人专门…

《父母的觉醒》父母不是在培养一个“迷你版”的自己

简介 作者为美国哥伦比亚大学心理学博士沙法丽萨巴瑞。作者也写了《家庭的觉醒》。 作者的核心观点&#xff1a; 我们必须认识到&#xff0c;我们不是在培养一个“迷你版”的自己&#xff0c;而是在塑造一个具有独立特征的灵魂。正因为如此&#xff0c;我们必须铆足精神&#…

IDEA把中国大陆高校教育邮箱都封了?

今天本想趁着快到期前&#xff0c;用教育邮箱续命&#xff0c;没想到&#xff1a; 天不遂人愿&#xff01;只能继续申请开源项目的许可证&#xff01; 可惜了&#xff0c;没提交在每个月&#xff1a;

汇编语言程序设计 第3章:汇编语言程序格式

文章目录 1. 伪指令1.1 段定义伪指令1.2 段寄存器说明伪指令1.3 过程定义伪指令1.4 源程序结束伪指令 2. 变量/标号定义伪指令2.1 变量定义2. 2 标号定义2.3 表达式 3.地址计数器与对准伪指令3.1 地址计数器$3.2 对准伪指令 4. DOS功能调用4.1 DOS功能调用的一般方法4.2 常用的…

python垃圾回收机制

Python中的垃圾回收机制是自动的&#xff0c;它主要使用了引用计数来追踪和回收内存。 1、引用计数 当一个对象被创建时&#xff0c;就会被分配一块内存&#xff0c;然后将其引用计数设置为1。当另一个变量引用该对象时&#xff0c;引用计数就会增加1。当一个对象的引用计数变…

基于亚马逊云EC2+Docker搭建nextcloud私有化云盘

亚马逊云科技EC2云服务器&#xff08;Elastic Compute Cloud&#xff09;是亚马逊云科技AWS&#xff08;Amazon Web Services&#xff09;提供的一种云计算服务。EC2代表弹性计算云&#xff0c;它允许用户租用虚拟计算资源&#xff0c;包括CPU、内存、存储和网络带宽&#xff0…

ES解析word内容为空的问题和直接使用Tika解析文档的方案

导言 在上一篇文章最后&#xff0c;我们虽然跑通了ES文件搜索的全部流程&#xff0c;但是仍然出现了1个大的问题&#xff1a;ES7.3实测无法索引docx和doc文档&#xff0c;content有值但是无法解析到附件成为可读的可搜索的内容&#xff0c;附件内容为空&#xff08;附件中根本…

【源码独家】充电桩平台(四轮电动汽车 微服务 云快充协议)

文章目录 一、产品功能部分截图1.手机端&#xff08;小程序、安卓、ios&#xff09;2.PC端 二、小程序体验账号以及PC后台体验账号1.小程序体验账号2.PC后台体验账号关注公众号获取最新资讯 三、产品简介&#xff1f;1. 充电桩云平台&#xff08;含硬件充电桩&#xff09;&…

守护健康,从营养开始 —— 帕金森患者的饮食秘籍

亲爱的读者朋友们&#xff0c;您是否知道&#xff0c;在对抗帕金森病的道路上&#xff0c;正确的饮食和营养补充可以成为我们的有力盟友&#xff1f;今天&#xff0c;就让我们一起探索那些能够帮助帕金森患者改善症状、提高生活质量的营养素&#xff0c;开启健康生活的新篇章。…

Python数据分析-Numpy2

1.numpy读取数据 CSV:Comma-SeparatedValue,逗号分隔值文件 显示&#xff1a;表格状态 源文件&#xff1a;换行和逗号分隔行列的格式化文本,每一行的数据表示一条记录 由于csv便于展示,读取和写入,所以很多地方也是用csv的格式存储和传输中小型的数据,为了方便教学,我们会经…

mysql 主从延迟分析

一、如何分析主从延迟 分析主从延迟一般会采集以下三类信息。 从库服务器的负载情况 为什么要首先查看服务器的负载情况呢&#xff1f;因为软件层面的所有操作都需要系统资源来支撑。 常见的系统资源有四类&#xff1a;CPU、内存、IO、网络。对于主从延迟&#xff0c;一般会…

2024-3-13,14(CSS)

1.复合选择器 有两个或者多个基础选择器&#xff0c;通过不同的方式组合而成。 目的是更加准确高效的选择目标元素&#xff08;标签&#xff09; 分类&#xff1a; 后代选择器&#xff1a;选中某个元素的所有后代元素 写法&#xff1a;父选择器 子选择器 {CSS属性}&#x…

软件授权在机器视觉行业的六大创新应用

智能制造已经离不开软件&#xff0c;软件打造高效低成本的制造是趋势&#xff0c;本文介绍通过软件授权赋能机器视觉实现更多在智能制造中的创新功能应用。 机器视觉应用软件在智能制造中呈现的六大创新应用趋势&#xff1a; 一、机器视觉&#xff1a;软件投入占比越来越高 通过…

位运算#蓝桥杯

位运算#蓝桥杯 文章目录 位运算#蓝桥杯1、小蓝学位运算2、异或森林3、位移4、笨笨的机器人5、博弈论 1、小蓝学位运算 #include<bits/stdc.h> using namespace std; using LL long long; const LL N 1e97; template<int kcz> struct ModInt { #define T (*this)…

IO流(一)

前置知识&#xff1a;字符集 常见字符集 ASCII字符集:只有英文、数字、符号等&#xff0c;占1个字节GBK字符集:汉字占2个字节&#xff0c;英文、数字占1个字节UTF-8字符集:汉字占3个字节&#xff0c;英文、数字占1个字节 Unicode字符集(统一码&#xff0c;也叫万国码) Unicode…

【Redis】Redis常用命令之Hash

1.hset&#xff1a;设置hash中指定的字段&#xff08;field&#xff09;的值&#xff08;value&#xff09;。 HSET key field value [field value ...]时间复杂度&#xff1a;插⼊⼀组field为O(1),插⼊N组field为O(N)。 返回值&#xff1a;添加的字段的个数。 2.hget&#xf…

Linux学习笔记(一)Linux基本指令

文章目录 前言目录常见命令1. pwd 打印当前所在路径2. cd 改变路径、切换路径3. 家目录 回到顶级目录4. 当前路径和上一路径5. 上一次路径6. 绝对路径和相对路径7. ls 列出目录内容8. mkdir 创建目录9. rmdir 删除目录10. touch 创建文件11. mv 修改文件目录、移动路径12. cp 复…

一口吃掉Linux基础操作

一般在windows上面想要操作Linux系统就需要装软件搞一个虚拟机&#xff0c;我用的是Ubuntu22&#xff0c;就是Linux的发行版.安装Ubuntu的过程比较复杂&#xff0c;最重要的一点是安装时要断网&#xff0c;否则会很慢。 Ubuntu 配置指南 — 地震“学”科研入门教程 先介绍一个…

光伏便携式EL检测仪是什么?—科技助农

光伏便携式EL监测仪是一种专门用于检测光伏电池组件性能的高效、实用的设备。它利用电致发光&#xff08;Electroluminescence&#xff0c;EL&#xff09;原理&#xff0c;通过检测光伏板在受到光照后产生的电流所激发出的光线&#xff0c;来评估光伏板的性能。这种设备通常具有…