Spring MVC(二)-过滤器与拦截器

 过滤器和拦截器在职责和使用场景上存在一些差异。

过滤器

拦截器

作用

对请求进行预处理和后处理。例如过滤请求参数、设置字符编码。

拦截用户请求并进行相应处理。例如权限验证、用户登陆检查等。

工作级别

Servlet容器级别,是Tomcat服务器创建的对象。可以拦截任何资源。

是Spring MVC容器的对象。只会对控制器中的方法进行拦截。

执行时机

在请求到达DispatcherServlet之前就开始执行,可以在请求被任何Spring MVC组件处理之前对请求进行修改或处理。

请求处理前、请求处理后,视图渲染前、整个请求完成后

使用场景

通常用于跨多个Controller的通用逻辑处理或者全局性的处理。例如日志记录、请求参数校验等。

用于对特定的Controller或者请求进行拦截,执行一些全局性的逻辑处理。例如权限验证。

表 过滤器与拦截器的对比

1 过滤器

图 javax.servlet.Filter 的UML

init 在Servlet容器启动时执行,destory在Servlet容器关闭时执行。

@WebFilter(urlPatterns = "/user/*")
public class UserInfoFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("filter doFilter 1"); // 处理器之前执行
        chain.doFilter(request,response); // 没有这条语句,则请求不会到处理器
        System.out.println("filter doFilter 2"); // 处理器之后执行
    }
}

OncePerRequestFilter 是Spring提供的一个常用的过滤器,其作用是确保一次HTTP请求期间只执行一次特定的过滤器逻辑,避免过滤器逻辑重复执行,提高系统的性能和效率。

图 OncePerRequestFilter 的doFilter方法

spring-web 定义了一些继承于OncePerRequestFilter的过滤器。

1.1 HttpPutFormContentFilter

主要作用是自动封装前端传递过来的PUT请求参数。在Spring MVC中,默认只有POST请求的表单数据(content-type为application/x-www-form-urlencoded)会被解析,而PUT、PATCH和DELETE请求的表单数据则不会被解析。配置了HttpPutFormContentFilter后,这三种类型的请求表单数据可以被正确解析。

(Spring 5.1开始,其被FormContentFilter 所取代,不仅支持PUT请求,还支持POST、PATCH和DELETE等表单数据解析)

图 HttpPutFormContentFilter的doFilterInternal方法

1.2 ForwardedHeaderFilter

检查请求中是否存在转发头,如果存在,则解析这个字段并提取信息。然后,使用这些信息来修改请求的主机、端口和方案,以便后续的请求处理能够基于更准确的源信息。

然后,使用转发头需要注意安全问题,因为程序无法确定这些头字段是由预期的代理服务器添加还是被恶意的客户端伪造。因此,通常建议配置信任的代理服务器来添加或删除这些不信任的外部头字段。此外也可以将其配置为只删除而不使用这些标头。

1.3 ShallowEtagHeaderFilter

是一个支持ETag的过滤器。ETag是指被请求变量的实体值,是一个可以与Web资源关联的记号,Web资源可以是一个Web页,也可以是JSON或XML文档。服务器负责判断记号是什么,并在HTTP响应头中将其传送到客户端。

过滤器的主要作用是根据响应中缓存的内容创建Shallow ETag并计算MD5,当客户端下一次发送请求时,会执行相同操作,并将计算的值与if-None-Match请求头进行比较,如果相等,则返回304(表示资源没有发送变化)。

该过滤器只能节省带宽,并不能提高服务器性能,因为它必须为每个请求计算完整的响应。

2 拦截器

图 Spring的HandlerInterceptor UML

preHandle: 在处理器方法被调用之前执行,如果返回false,则拦截链下的其他拦截器将不会被执行,处理器也不会被执行。

postHandle: 在处理器方法执行完后、视图渲染前执行。

afterCompletion: 在请求完全执行完后执行。通常用于清理工作。

2.1 拦截器原理

拦截器是基于AOP思想实现,但在实现细节上并不是直接通过Spring AOP的代理机制来完成。而是通过Spring MVC的内部机制来实现。在DispatcherServlet的请求处理中被集成及调用。

HandlerInterceptorRegistry

注册和管理拦截器。

HandlerMapping

根据请求找到对应的处理器,在其实现类中,会考虑将已注册的拦截器和处理器一起封装成一个HandlerExecutionChain对象。

HandlerAdapter

负责调用处理器(Controller方法)。在调用处理器之前和之后,会与拦截器进行交互,确保拦截器的preHandle、postHandle等方法在正确时机被调用。

DispatcherServlet

负责处理所有的请求。在请求处理流程中,会根据HandlerMapping 找到HandlerExecutionChain,然后依次调用链中拦截器的preHandle方法。处理器执行完毕后,会调用postHandle方法,最后调用afterCompletion方法。

表 跟拦截器有关的类与接口

图 DispatcherServlet 的doDisspatch方法部分代码

2.1.1 HandlerMapping

用于定义请求与处理器之间的映射。

图 HandlerMapping UML

在Spring MVC 的WebApplicationContext 容器被启动时,会执行DispatcherServlet 的初始化方法,其会查找容器中所有被注册为bean的HandlerMapping。

图 DispatcherServlet 的 initStrategies方法

每次执行DispatcherServlet 的doDispatch方法(处理请求)时,会轮询每一个handlerMapping实例,并调用其getHanler方法,来查找该请求的请求链。

图DispatcherServlet 的getHandler方法

HanlerMapping 的getHandler 方法会查找该请求对应的处理器,如果没找到,则返回null,否则将处理器实例与请求对应的拦截器一起封装为一个请求链。

图 HandlerMapping 默认实现AbstractHandlerMapping 的getHandler方法

图 HandlerMapping 默认实现AbstractHandlerMapping 的getHandlerExecutionChain方法

 2.1.2 HandlerMapping 与 @RequestMapping

Spring 会扫描带有@RequestMapping注解的方法与类,并把它们注册为HandlerMapping类型的bean。这个工作主要是由RequestMappingHandlerMapping来完成。

图 RequestMappingHandlerMapping UML

其同时实现了HandlerMapping及InitializingBean(当IoC容器中bean的所有属性被初始化之后,会调用其afterPropertiesSet()方法)接口。

图 RequestMappingHandlerMapping的父类的afterPropertiesSet方法

RequestMappingHandlerMapping 实例是在何时被注册成bean的呢?

在DispatcherServlet初始化时,会初始化HandlerMapping.

图  DispatcherServlet的initHandlerMappings方法

而默认的DispatcherServlet 类在Spring-webmvc的DispatcherServlet.properties文件中配置。

图 DispatcherServlet.properties 文件

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Docker 中 Nginx 反向代理

本文主角:Nginx Proxy Manager 。 使用docker安装Nginx Proxy Manager。 1、找到C:\Windows\System32\drivers\etc下的hosts文件,添加 “域名 IP"即可。 使用vscode编辑文件,保存时会提示用管理员权限保存即可。 2、Nginx Proxy Mana…

AD实用设置教程

一、“ 多边形敷铜 ” 设置 “ 最小间隔 ” 在AD9中设置多边形敷铜的间距,可以按照以下步骤进行: 打开一个PCB文件,在PCB工程界面选择“设计”->“规则”->“Electrical”->“Clearance”。在“Clearance”上右键选择“新建规则”…

C语言刷题1

和黛玉学编程呀 这期就是普普通通题目和答案啦,大都也比较基础,适合初学者,下期我们就更单链表啦 求Snaaaaaaaaaaaaaaa的前5项之和,其中a是一个数字, 例如:222222222222222 int main() {int a 0;int n …

安装调试kotti_ai:AI+互联网企业级部署应用软件包@riscv+OpenKylin

先上结论:riscvOpenKylin可以安装pyramidkottikotti_ai 但是paddle_serving_client无法安装,项目的AI实现部分需要改用其它方法,比如onnx。最终onnx也没有装成,只好用飞桨自己的推理。 安装kotti pip install kotti 安装kotti和…

多人命题系统|基于SSM框架+ Mysql+Java+ B/S结构的多人命题系统设计与实现(可运行源码+数据库+设计文档)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 2024年56套包含java,ssm,springboot的平台设计与实现项目系统开发资源(可…

JavaSE:数据类型与变量

目录 一、前言 二、数据类型与变量 (一)字面常量 (二)数据类型 (三)变量 1.变量概念 2.语法格式 3.整型变量 3.1整型变量 3.2长整型变量 3.3短整型变量 3.4字节型变量 4.浮点型变量 4.1双精…

谷歌DeepMind推出SIMA智能体,可以跟人一起玩游戏

谷歌 DeepMind 推出了 SIMA,这是一种通过训练学习游戏技能的人工智能代理,因此它玩起来更像人类,而不是一个只做自己事情的强大人工智能。 从早期与 Atari 游戏合作,到以人类大师级别玩《星际争霸 II》的 AlphaStar 系统&#xf…

PyGWalker:Python中的Tableau,数据可视化变得如此简单!

文章目录 1介绍2 安装3 使用4 将数据可视化导出为代码5 总结 1介绍 在数据分析和可视化的领域,Tableau凭借其强大的功能和直观的界面,一直以来都是专业人士的首选工具。然而,对于许多用户而言,Tableau的封闭性和高昂的成本使其难…

leetcode刷题(javaScript)——BFS广度优先遍历相关场景题总结

广度优先搜索(BFS)在JavaScript编程中有许多实际应用场景,特别是在解决图、树等数据结构相关问题时非常常见。在JavaScript中,可以使用队列来实现广度优先搜索算法。通过将起始节点加入队列,然后迭代地将节点的邻居节点…

60 个深度学习教程:包含论文、实现和注释 | 开源日报 No.202

labmlai/annotated_deep_learning_paper_implementations Stars: 44.0k License: MIT annotated_deep_learning_paper_implementations 是一个包含深度学习论文的 60 个实现/教程,附带并排注释;包括 transformers(原始、xl、switch、feedbac…

2023年五级区划省市县乡镇行政村社区边界数据

行政区划数据是重要的基础地理信息数据,根据国家统计局公布的数据,行政区划共分为五级,分别为省级、地级、县级、乡镇/街道级、村/社区级。 该套数据以2020-2023年国家基础地理信息数据中的县区划数据作为矢量基础,辅以高德行政区…

Leetcode 19. 删除链表的倒数第 N 个结点

题目描述: 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 示例 1: 输入:head [1,2,3,4,5], n 2 输出:[1,2,3,5] 示例 2: 输入:head [1], n 1 输出&#xf…

图论中的最小生成树:Kruskal与Prim算法深入解析

🎬慕斯主页:修仙—别有洞天 ♈️今日夜电波:アンビバレント—Uru 0:24━━━━━━️💟──────── 4:02 🔄 ◀️ ⏸ ▶️ ☰ …

Linux第79步_使用自旋锁保护某个全局变量来实现“互斥访问”共享资源

自旋锁使用注意事项:自旋锁保护的“临界区”要尽可能的短。 因此,在open()函数中申请“spinlock_t自旋锁结构变量”,然后在release()函数中释放“spinlock_t自旋锁结构变量”,这种方法就行不通了。如果使用一个变量“dev_stats”来表示“共享…

【前端Vue】Vue3+Pinia小兔鲜电商项目第2篇:什么是pinia,1. 创建空Vue项目【附代码文档】

全套笔记资料代码移步: 前往gitee仓库查看 感兴趣的小伙伴可以自取哦,欢迎大家点赞转发~ 全套教程部分目录: 部分文件图片: 什么是pinia Pinia 是 Vue 的专属状态管理库,可以实现跨组件或页面共享状态,是…

javaSwing扫雷

一、介绍 1.1 背景 在1964年 有一个叫“方 块”的游戏,这是扫雷最原始的版本。后来,这个游戏被改成了另一种游戏,叫做“Rlogic”。在这个游戏中,玩家扮演了一名军队的军人,接受了一项艰难的任务:为指挥中…

Linux--gdb调试

一.安装gdb sudo apt install gdb 二.使用gdb 三.gdb的相关操作 gdb 可执行文件名 显示代码: l 加断点: b 行号 启动程序:r(运行之前一定要加断点) 查看断点信息: info break/info b 删除断点信息:delete 断点编号 单步执行:n 打印 :p 显示:display 变量名: 退出:q …

分布式系统的基本特性

一般,分布式系统需要支持以下特性: 资源共享 开放性 并发性 可伸缩性 容错性 透明性 下面分别讨论。 容易理解的 资源共享 一旦授权,可以访问环境中的任何资源。 资源:包括硬件(e.g. printer, scanner, camera)、软件&a…

8.2K star!史上最强Web应用防火墙

🚩 0x01 介绍 长亭雷池SafeLine是长亭科技耗时近 10 年倾情打造的WAF(Web Application Firewall),一款敢打出口号 “不让黑客越雷池一步” 的 WAF,我愿称之为史上最强的一款Web应用防火墙,足够简单、足够好用、足够强的免费且开源…

详解main函数参数argc、argv及如何传参

目录 1、main()函数参数 2、main函数如何传参 2.1 环境准备 2.2 通过 Powershell 窗口传参 2.3 通过vs界面传参 3、int main() 和 int main(int argc, char *argv[]) 特点 1、main()函数参数 在C语言中,main函数可以带参数。main函数的原型通常为以下两种形式…