Spring Boot统一功能处理(一)

本篇主要介绍Spring Boot的统一功能处理中的拦截器。

目录

一、拦截器的基本使用

二、拦截器实操

三、浅尝源码

初始化DispatcherServerlet

处理请求(doDispatch)

四、适配器模式


一、拦截器的基本使用

在一般的学校或者社区门口,通常会安排几个保安大爷来进行身份验证,只有身份符合要求的人才会被放行,否则则会被大爷拦住,而拦截器就像我们程序的保安大爷,只有通过我们自己定义的拦截规则,请求才能被放行到目标接口上。

下面我们来看看如何在Spring Boot中使用拦截器 

 在项目中设置拦截,我们需要先自己定义一些拦截器,里面包含一些具体的拦截规则,定义拦截器的代码如下:

(1)首先创建一个拦截类,通常以“Interceptor”作为类名的后半部分,这里我们定义一个LoginInterceptor类,意为与登录相关的拦截器,然后让该类实现一个HandlerInterceptor接口,具体如下:

@Component
public class LoginInterceptor implements HandlerInterceptor {}

(2)重写三个方法:

 @Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}

其中preHandle为在目标方法执行前要执行的方法,其返回值如果为true,则会被放行去执行目标方法,为false则拦截,我们可以在这个方法里根据需求定义拦截规则。postHandle为目标方法执行后要执行的方法。afterCompletion为最后视图渲染完后最后执行的方法(由于现在都是前后端分离了,后端一般不处理视图,因此这个方法不需要过多了解)。

定义好拦截器后我们还需要配置拦截器,具体配置流程如下:

(1)创建配置类(一般以Config结尾,这里以为WebConfig),实现WebMvcConfigurer接口:

public class WebConfig implements WebMvcConfigurer {
}

(2)然后重写addInterceptor方法

@Overridepublic void addInterceptors(InterceptorRegistry registry) {}

(3)然后我们在里面添加我们需要配置的拦截器,具体如下:

这里我们可以通过@Autowired注入一个LoginInterceptor对象,也可以直接在参数里new一个,只要是传入一个实现前面的HandlerInterceptor接口的类的对象即可。

(4)然后在配置我们需要拦截的路径(即请求url中ip地址端口号的后面的部分):

 这里的”/**"表示任意路径,例如“/user/book、/user”等,另外还有“/*"他只能表示一级路径,例如:

”/user,/book"等。

(4)由于通常我们并不需要所有路径都进行拦截(例如登录请求),因此我们还需要排除一些路径,让这些路径不被拦截,具体如下:

 (5)最后我们还需要把这个类放到Spring容器里,由于这里与配置相关,所有使用@Configuration。

二、拦截器实操

 接下来我们来实操一下。首先我们创建一个Controller类,在里面定义一个login方法(这里只是简单测试一下,不进行密码校验,只是给用户设置一个登录状态而已):

 然后再添加几个测试方法:

然后我们再来定义一下拦截器,再preHandle方法中设置一下拦截规则,只有处于登录状态才能放行 ,并在另外两个方法中打印日志来进行观察:

然后在注册(配置)一下拦截器(不拦截login方法,其他全部拦截) :

最后我们通过postMan构造请求来访问一下这些方法.

先访问一下test01 

可以发现返回的响应为空,也就是说请求被拦截器拦截到了。

然后我们再来访问一下login

可以发现响应有数据了,但由于我们请求中没有传值,导致接口中的两个参数为空,所以返回了false。接下来我们补上这两个值再访问一下

 可以发现响应中返回true了,同时这也意味着我们现在已经给用户设置成登录状态了,此时我们再来访问test01

可以发现响应已经有数据了。这也就意味着这个请求已经被拦截器放行了。

最后我们再来看一下 控制台的日志:

可以发现,拦截器是严格按照顺序执行相关方法的 ,如果请求被拦截了,则只会执行postHandle方法就返回了,如果请求被放行则会按顺序执行完拦截器中的三个方法。并且对于配置中没有涉及到的路径,和被排除的路径,则根本不会进入到拦截器。

三、浅尝源码

接下来,我们来浅浅阅读一下与拦截器相关的部分源码。

初始化DispatcherServerlet

仔细观察日志可以发现,当我们的服务器接收到第一个来自前端的请求时,会初始化一个dispatcherServerlet类。

它的初始化方法为init(),具体实现是在其父类HttpServerletBean中实现的

init方法首先创建了一个PropertyValues类,这个类我并不知道是干嘛的,但根据其名称可以大体猜出来应该是去读一些配置,并且下面的if语句 判断这个对象是否为空,不为空才去执行相关逻辑,因此可以推测出if语句里应该是去根据读到的配置去进行一些设置。在init方法最后执行了一个initServerletBean方法,,我们来具体看一下这个方法,

转到定义可以发现HttpServerletBean中并未实现这个方法,接下来我们去其子类看一下 

 

 可以发现其子类FrameworkServerlet重写了这个方法,并具体进行了实现。仔细观察可以发现这个方法主要是在打印日志,日志的内容就是我们在前面控制台所看到的

 

并且 这里还进行了计时,并打印在了日志里。除去日志的部分可以发现这个方法就只剩下try-catch中的内容了:

接下来我们继续进入到其中的initWebAppliactionContext ()来看一下,

根据名字可以发现这个方法应该是用来 初始化WebApplicationContext的,并且通过代码大致可以发现这个方法会先去从类的成员属性中获取WebAppliactionContext,如果成员属性不为空,则会直接用成员属性的,如果为空,则调用findWebApplication去寻找一个并使用,如果没找到,则去创建一个。执行完上面第一个红框里的内容后,wac应该是已经不再为空了的,接下来调用onRefresh方法,可以发现这里加了锁来防止线程安全问题。接下来我们进到onRefresh方法来看一下:

可以发现FrameWorkServerlet中并未进行实现,我们再进到其子类看一下:

 可以发现子类进行了实现,并且此时这个子类就是我们要初始化的DispatchServerlet。然后我们再看看这个方法里使用的initStrategies()方法:

通过方法名称可以发现这个方法是在进行一些初始化,然后再通过具体代码可以发现这个方法初始化了九个组件,这些组件就是Spring的九大组件,其名称如下:

  • MultipartResolver:文件上传解析器
  • LocaleResolver:区域解析器
  • ThemeResolver:主题解析器
  • HandlerMappings:处理器映射器
  • HandlerAdapters:处理器适配器
  • HandlerExceptionResolvers:异常处理器解析器
  • RequestToviewNameTranslator:视图名称转换器
  • ViewResolvers:视图解析器
  • FlashMapManager:FlashMap管理器

初始化这些组件后,DispatchServerlet就初始化完了。

处理请求(doDispatch)

初始化完成后,DispatchServerlet就能进行请求的处理了,处理请求,主要通过DispatchServerlet类的doDispatch方法来对请求调度给Controller来执行,下面我们来详细看一下这个方法:

首先它会去获取一个与请求对应的处理器,然后再根据处理器去获取一个能够使用的适配器

然后再根据适配器来顺序执行拦截器的相关方法以及目标方法 然后处理视图,并执行最后的afterCompletion方法

四、适配器模式

在前面浅尝源码时,提到了适配器这个概念,适配器使用到了一种设计模式 --- 适配器模式。适配器模式能将一个类的接口,转换成符合客户期待的接口,从而使原本并不能兼容使用的接口也能使用了。简单来说,就是有一个接口,由于兼容问题并不能直接使用,需要在中间加上一个适配器才能够使用这个接口。例如我们生活中的转接头,当我们的手机是Type_c的充电口,而我们却只有苹果的数据线时,这根苹果的数据线自然是冲不了我们的手机的,此时就需要一个转接头了,通过转接头,我们就可以给手机充电了。此处转接头就相当于我们的的适配器,而转接头的设计就相当于是是适配器模式这种设计思想

可能有人会说为什么 不在一开始就设计成兼容的接口呢,这样就没必要大费周章弄一个适配器了,这样固然好,但人并不是万能的,总会有我们意想不到的情况出现,面面俱到几乎是不可能的,就像使用Type-c接口的手机厂商肯定不会想到有人会用苹果的数据线来充电,但既然这个需求是存在的,也就不能不去实现了,重新设计的话,成本又太高,因此,就只能使用适配器这一无奈之举了。

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

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

相关文章

一夜爆红的4款国产软件,却一度被大众误以为是外国人开发

在现今高度信息化的时代,计算机已经深深地渗透到了我们生活的每一个角落。 从日常的办公学习到娱乐休闲,几乎都离不开计算机技术的支持。而在这背后,软件作为计算机的灵魂,其发展历史可谓波澜壮阔。 中国软件产业经过多年的积累和…

Linux 安装KVM虚拟机

什么是KVM虚拟机? KVM 是 Kernel-based Virtual Machine 的缩写,是一种用于虚拟化的开源硬件虚拟化技术。它使用 Linux 内核的虚拟化模块,将物理服务器划分为多个虚拟机。KVM 允许虚拟机直接访问物理硬件资源,从而提供出色的性能和稳定性,同…

基于二级片内硬件堆栈的后向CFI 验证方法研究,第5章 测试及实验结果

5.1 SoC系统功能仿真 按照上一章的设计方案,采用verilog HDL语言,在玄铁E906处理器平台中分别采用延迟验证和批处理验证方法完成了二级硬件堆栈的RTL级硬件描述。为了验证二级硬件堆栈的正确性,采用斐波那契数列进行验证,设置RAB…

【R语言】组合图:散点图+箱线图+平滑曲线图+柱状图

用算数运算符轻松组合不同的ggplot图,如图: 具体代码如下: install.packages("devtools")#安装devtools包 devtools::install_github("thomasp85/patchwork")#安装patchwork包 library(ggplot2) library(patchwork) #p1是…

AMPLE: 基于图简化和增强图表征学习的漏洞检测

GNN已被证实能有效学习源代码的图表示,然而GNN难以处理代码结构图中长距离节点之间连接的局限性,导致无法捕获代码图的全局信息(即远距离节点间的依赖关系)。针对上述问题,提出漏洞检测框架AMPLE,它包括图简…

机器学习引领金融革命:重塑金融服务领域新格局,开启智能化新篇章

🧑 作者简介:阿里巴巴嵌入式技术专家,深耕嵌入式人工智能领域,具备多年的嵌入式硬件产品研发管理经验。 📒 博客介绍:分享嵌入式开发领域的相关知识、经验、思考和感悟,欢迎关注。提供嵌入式方向的学习指导…

我们一起看看《看漫画学C++》中如何介绍的字符串的用法

C中的字符串使用的是 std::string 类型,它是C标准库中提供的字符串类,提供了丰富的字符串操作方法。下面是关于C字符串的一些常用用法: 字符串拼接 字符串查找 字符串追加 购书地址:https://item.jd.com/14418856.html

【教程】一个比较良心的C++代码混淆器

这是一个比较良心的C代码混淆器,用于信息竞赛训练和保护代码免受抄袭。本文将介绍这个混淆器的使用方法、混淆效果和已知的一些bug。同时,我们也会给出一些示例来演示混淆器的具体操作。 引言 在信息竞赛训练和实际开发中,保护代码的安全性和…

Docker 学习笔记(十):Centos7 中 Docker 部署 Redis 集群,打包 SpringBoot 微服务

一、前言 记录时间 [2024-4-17] 系列文章简摘: Docker 学习笔记(六):挑战容器数据卷技术一文通,实战多个 MySQL 数据同步,能懂会用,初学必备 Docker 学习笔记(七)&#x…

关于外网后端服务访问内网minio中间件,因连接minio超时,启动失败问题

注:服务器情况:2台服务器,内网服务器包含(activemq、minio、nginx、redis、mysql、后端java服务)。外网服务器只有后端java服务,访问内网的中间件(内网服务器开放了部分指定端口) 问…

web安全学习笔记(9)

记一下第十三课的内容。 准备工作:在根目录下创建template目录,将login.html放入其中,在该目录下新建一个reg.html。在根目录下创建一个function.php 一、函数声明与传参 PHP中的函数定义和其他语言基本上是相同的。我们编辑function.php …

【C++】哈希

1. unordered系列关联式容器 STL提供了底层为红黑树结构的一系列关联式容 这里介绍 unordered_set 和 unordered_map a. unordered_map unordered_map 是存储<key, value>键值对的关联式容器&#xff0c;其允许通过 key 快速的索引到与 其对应的 value unordered_m…

nested exception is dm.jdbc.driver.DMException: 字符串截断

nested exception is dm.jdbc.driver.DMException: 字符串截断 背景问题分析问题解决 背景 今天在日常工作中遇到了一个问题&#xff0c;正常的 insert into操作报错了 ### Cause: dm.jdbc.driver.DMException: 字符串截断 ; 字符串截断; nested exception is dm.jdbc.driver…

element-ui container 组件源码分享

今日简单分享 container 组件的源码实现&#xff0c;从以下两个方面来讲解&#xff1a; 1、container 组件的页面结构 2、container 组件的属性 一、container 组件的页面结构 二、container 组件的属性 1、container 部分的 direction 属性&#xff0c;子元素的排列方向&am…

Redis(哨兵模式)

什么是哨兵机制 问题: redis 主从复制模式下, 一旦主节点由于故障不能提供服务, 需要人工进行主从切换, 同时大量客户端需要被通知切换到新的主节点上, 对于有一定规模的应用来说, 对于人力的资源消耗会很大.解决: 通过哨兵对主从结构进行监控, 一旦出现主节点挂了的情况, 自动…

利用CSS延迟动画,打造令人惊艳的复杂动画效果!

动画在前端开发中是经常遇到的场景之一&#xff0c;加入动画后页面可以极大的提升用户体验。 绝大多数简单的动画场景可以直接通过CSS实现&#xff0c;对于一些特殊场景的动画可能会使用到JS计算实现&#xff0c;通过本文的学习&#xff0c;可以让你在一些看似需要使用JS实现的…

网络编程(现在不重要)

目录 网络编程三要素与InetAddress类的使用 软件架构 面临的主要问题 网络编程三要素&#xff08;对应三个问题&#xff09; InetAddress的使用 TCP与UDP协议剖析与TCP编程案例&#xff08;了解&#xff09; TCP协议 UDP协议 例子 UDP、URL网络编程 URL&#xff1a;&…

求奖金(if)(C语言)

一、N-S流程图&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int I 0;float bonus 0;//提示用户&#xff1b;printf("请输入利润I&#xff1a;");//获取用户值&#xf…

【优选算法专栏】专题十三:队列+宽搜(一)

本专栏内容为&#xff1a;算法学习专栏&#xff0c;分为优选算法专栏&#xff0c;贪心算法专栏&#xff0c;动态规划专栏以及递归&#xff0c;搜索与回溯算法专栏四部分。 通过本专栏的深入学习&#xff0c;你可以了解并掌握算法。 &#x1f493;博主csdn个人主页&#xff1a;小…

【Linux系统编程】第四弹---基本指令(二)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、echo指令 2、cat指令 3、more指令 4、less指令 4、head指令 5、tail指令 6、时间相关的指令 7、cal指令 8、find指…