SpringBoot统一功能

news2024/11/15 7:29:26

目录

前言1:首先要明白,什么是统一功能?

前言2:统一功能包括哪些呢?展开说说?

一、拦截器(interceptor)

1、介绍

2、如何使用拦截器

3、拦截器的在程序内部的执行流程是啥呢?

4、拦截器在代码底层是如何被成功执行的?(源码分析)

二、统一异常处理

1、大概介绍

2、具体操作

三、统一数据返回处理

1、大概介绍

2、具体讲解

3、出现的问题

4、解决办法

5、为什么会报错

四、补充知识(适配器模式)

1、大概介绍

2、代码讲解

五、在源码层面进行分析,统一异常处理和统一数据格式处理是咋执行的

1、大概讲解

2、插播几条知识

3、具体讲解


前言1:首先要明白,什么是统一功能?

例如:六国统一,秦始皇规定,我的国家货币要统一,只能使用我规定的那一种货币,那为什么要这样做呢?方便管理,各国之间的货币之间也不方便流通。

统一功能:像六国统一货币那样,规定某些程序,统一执行某些操作,也方便进行管理,提高效率。

前言2:统一功能包括哪些呢?展开说说?

  • 使用拦截器实现某些操作,主要拦截用户在页面发来的请求,例如使用拦截器实现用户登录权限的统一校验。
  • 某一块程序产生运行时的异常后,统一对这些异常进行处理。
  • 某些数据要返回给前端时,对数据的格式进行统一处理。

一、拦截器(interceptor)

1、介绍

例:一个学校呢,可能进入车,也可能进入人,安排出一个保安,放到门口,保安要对这些进行拦截校验,现在领导要求保安,拦截人,对人进行校验,不管车。

拦截器就相当于是一个保安,拦截用户请求,按照规定,要对某些方法(人)拦截,先去执行预先设定好的代码(进行校验)。

2、如何使用拦截器

咱们先了解一下大概步骤,整体看一下~~:

  • 第一步:自定义出一个拦截器(相当于安排出一个保安,告诉他的职责是什么,(拦截,校验))
  • 第二步:再将拦截器注册到项目中(将保安安排到某个地方,去发挥作用,再告诉具体拦截谁)

大概了解完之后,那咱们看具体是如何使用的吧(以登录验证为例)~:

  • 第一步:先自定义出一个拦截器吧~,名字:LoginInterceptor,具有拦截,校验的功能,可以实现(implements)HandlerInterceptor(代理拦截器)并重写出此接口内的所有方法,下面是对这三个方法的解释:

preHandle(相当于保安将人拦截后,在对人进行校验):在目标方法执行前执行,校验通过,返回true,失败就返回false~

postHanddle:在目标方法执行后执行~

afterCompletion:这个方法现在不用学了,因为这个方法是在视图渲染后执行的,而现在后端已经不涉及视图了~

  • 第二步:再将拦截器注册配置到项目中:创建出WebConfig(网络配置)类,再去实现WebMvcConfiguer接口~,接着将对象注入到这个类中,在类中重写接口中的addInterceptor方法,调用registry的addInterceptor方法,这个方法是添加注入到类中的拦截器,再规定这个拦截器可以具体拦截哪些路径,具体不拦截哪些路径。(相当于告诉保安要具体拦截哪些车牌号的车,哪些车牌号不用拦截)具体操作如下图所示~

此时注意看18-21行代码。只用几行代码,就可以对所有想要验证的方法统一处理~

相信在此时,大家更加直接看出拦截器的强大了吧,按照18-21行的做法,大大提高了开发的效率,简化了代码~

---------------------------------------------------------------------------------------------------------------------------------

但是在此时,有一个问题,由于咱们的项目现在没有前后端分离,所以咱们刚才配置的拦截器不仅会拦截后端的请求,还会拦截前端的请求,甚至是前端的图片也会拦截,但是咱们刚才设置的是拦截所有请求,只允许它不拦截后端的登录请求,并没有对前端的登录请求放行,比如在浏览器输入http://127.0.0.1:8080/login.html,会进行拦截,那可咋办呢?

(下面的方法借助于他人博客,链接为:Spring统一功能-CSDN博客)

通过excludePathPatterns()加入需要放行的前端路径

方法一:把前端需要放行的文件都放到一个文件夹,例如book中,然后/book/**就可以

方法二:不放到文件夹中,一个文件一个文件的放行。(但是不能排除其他文件中会不会有html文件呀,这样就仿佛小偷混进了好人的包里面,逃出去了)。。。

(但是上面两种方法不能排除其他文件中会不会有html文件呀,这样就仿佛小偷混进了好人的包里面,逃出去了)。。。下面请看第三种方法~

方法三:不放到文件夹中,精准放行,不会让任何一个漏网之鱼逃出去。

放行方法的另一种方式:(将那些路径写到集合当中,代码比较优雅~)

-----------------------------------------------------------------------------------------------------------------------------

这是一些拦截路径的格式,大家可以看一看。

3、拦截器的在程序内部的执行流程是啥呢?

相信大家对上述所讲大概已经明白了拦截器的基本操作,但是可能有人还会有新的疑惑,那它在内部是咋执行的呢?现在告诉大家~

没有拦截器之前,用户的任何一个请求都是如下图所示~

将拦截器注册配置到项目中之后,请求流程都是如下图所示~

4、拦截器在代码底层是如何被成功执行的?(源码分析)

好,现在对于拦截器已经基本上介绍完毕了,下面是要具体看看它的底层到底是如何实现的~

(了解即可,因为源码不容易看懂)

现在也是按照上面讲的逻辑,咱们先讲出大概的框架,让各位看官心里有个大概了解,然后咱们再讲具体的~ 说到这里,我联想到,看源码,也是这样一个逻辑~,因为源码一般看不懂,因为不仅多而且逻辑复杂,所以在看源码的过程,我们要有以下两个原则:

一:不死扣源码的每一行,找到想要看的源码那一部分,大概浏览一下,找到核心的代码,连蒙带猜的去看,遇到不懂的方法,按住CTRL,点击左键,去看具体它是如何实现的。

二:若经过第一步后,还是看不懂,就不要挣扎了,在不同的业务下,多遇到几次,多看几次,多研究几次,就可以了。

好,咱们言归正传

大概流程:核心类DispatcherServlet,它属于一个调度器,(相当于一个公司前台一样),为spring服务,听从spring差遣,当用户发送请求后,Spring通过它来告诉我们的程序该去调用什么,来完成这个请求,在执行请求之前,会去执行拦截器的相关代码,然后看拦截器检验是否成功,再去决定要不要继续向下执行。那为什么DispatcherServlet是核心类呢?请看下图所示:

spring产生之后,DispatcherServlet接着被产生,然后就去执行拦截器相关的代码了,所以DispatcherServlet是一个核心类。(当程序启动后,结束之前,初始化只会初始一次)。

ok,咱们大概的流程看完了,看每一步具体是怎么执行的,是怎么就执行到拦截器的代码了~

首先,既然DispatcherServlet类是一个核心类,那咱们从DispatcherServlet类入手,咱们去研究DispatcherServlet类,看看它到底为spring做了什么事,他其实就是一个servlet,servlet的生命周期是:

init()-初始化,service()-处理请求,derstory()-服务终止。

先去初始化过程:

咱们要先找到DispatcherServlet类,所以先按住   CTRL+n 快捷键,在输入框输入DispatcherServlet找到这个类,点击进入这个类:

进入它的父类(CTRL + 鼠标左键):

再进入FrameworkServlet的父类:

再找到HttpServletBean中的init:

再进入init方法中的initServletBean()方法:

进去之后,发现没有具体实现逻辑,点击箭头处

此刻又回到了DispatcherServlet的父类FrameworkServlet中:

观看大概逻辑后,发现try里面的才是核心逻辑,不知道绿色的里面是啥东西,咱们点进去一探究竟

 点进去之后,发现此方法的返回类型是WebApplicationContext,方法里面有个wac变量,咱们看看~

 可以看到上面的if语句,咱们猜一猜,先是获取一些东西,再给wac,给了之后呢,传给onRefresh方法,这个方法猜着是更新的意思,那具体啥意思呢,咱们点进去看看~

点进去之后,发现是空的,咱们点击箭头处看看~

进去之后看到,wac传给了context,这个似曾相识呀!这个不就是spring的上下文吗?也就是spring的运行环境,也是一个容器,这个容器里面可以存放对象,那现在用context干什么呢?好像是在里面放东西呀 ,放的就是Spring的九大组件,也就是在初始化这个容器, 那是谁在初始化,是spring,它是根据什么初始化呢?根据程序中的各种注解和代码和配置等等各种方面完成的这个context~  

service()-处理请求的过程:

开始处理请求了,咱们看看具体怎么处理请求的~ 进入doService方法:

然后咱们不一行一行看了,由于DispatcherServlet是一个调度器,所以咱们直接看doService方法里面的doDispatch方法。先大概介绍一下这个方法,是个调度方法,管着请求发出之后,谁干什么事的,在这里面呢,咱们一会重要讨论的是两个器,一个处理器,一个调度器,讨论完之后,会继续向下看代码,也就是关于过滤器相关的代码,对!没错,终于执行到过滤器了,会讲解在这个方法里,怎么执行的过滤器相关的代码~ 废话不多说,开整!

点进去之后,直接找核心的代码,mappedHander与HandlerAdapter。

这两个对于咱们来说,还有一点陌生,因为还没学呢~简单介绍一下吧~

mappedHander:它是一个处理器,作用是啥呢?比方说我们打一个1235电话后,会提示我们根据我们的需求,按不同的键,接线员就会给我分配不同的部门处理,它就好比是一个接线员,当一个请求发进来之后,Spring会通过调度器让处理器去处理请求,它会根据不同路径去调用不同的controller方法,完成响应。

HandlerAdapter:看上面的图片,根据一个处理器,得到了一个适配器ha,它就好比是一个中间人,当接线员了解到打电话的人的需求后,接线员会亲自把需求给相关的部门吗,不会的,他会把需求转接给一个中间人,再由这个中间人去对接部门,所以是适配器去调用不同的controller方法,完成响应。

刚看,确实很复杂,多看看就好啦~ 咱们接着往下看~

大家看applyPreHandle方法,是不是又是似曾相识呢?这不就是拦截器相关的方法吗?真的是这样吗?咱们点进去看看就知道了~

好家伙,真的是这样的~ 终于看到拦截器相关的代码了!在这个方法里面得到咱们注册配置的拦截器,再去执行它的preHandle方法。

若preHandle返回true,代表对目标方法的检验成功,检验成功之后,就去调用适配器了,去调用各种controller方法,完成对用户的响应,那这个过程是怎实现的呢?咱们继续往下看~

最后上图中这个applyPreHandle方法最后在154行处,会返回true。

接着true返回到下图中的1067行代码处之后,if语句判断为false,继续向下执行,执行下图的1072行

检验成功之后,就去调用ha适配器了,去调用各种controller方法 ,完成响应。

若preHandle返回false:,代表对目标方法的检验失败,程序不再向下执行,那具体咋执行的呢?咱们接着看~

在下图中的第150行代码处返回false,doDispatch方法执行完成

 doDispatch方法执行完成后,再执行finall里面的方法后,doService的方法也执行完成了。

 derstory()-服务终止: 这个暂时不作讲解了,继续下面的二,三的讲解了,要不然讲不完了,下面的比较重要~

其实这么一看这三个过程,我认为初始化阶段就好像是在商店准备开门的准备阶段,service阶段就好像是准备好了,等待服务的过程~

综上所述,拦截器终于完结了,不知道大家掌握的怎么样呢?~

二、统一异常处理

1、大概介绍

咱们先大概讲一下,这个异常~  当程序在运行时,产生了异常,

但是对于我们后端来说:不想要将具体的错误,返回给前端~

并且对于前端来说:也不想要将具体错误,给用户,只给用户展现一个简单页面即可。

这种现象与一个公司出现问题时,所做的差不多,因为公司会对外界说,公司内部错误,不变告知。

所以我们也将异常的结果进行统一处理,统一返回一个结果。

好的,现在大概讲完了这个统一异常处理,现在咱们将统一异常处理是怎么实现的~

2、具体操作

咱们是创建出一个异常处理类,在类中写出对异常进行捕获的代码,如下图所示,写出了三个异常处理器,对程序产生的异常进行捕获。

那现在问题来了!异常是怎么被这几个处理器捕获的呢?

当异常产生之后,会自动进行捕获,这三个处理器会进行比较,看谁距离异常近,就由谁进行捕获,这与处理器代码的先后没有任何关系~

看谁距离异常近,这句话是啥意思呢?看咱们的三个异常处理器的参数,是三个不同的异常类型,

当异常出现之后,会看谁的类型与出现的异常的类型最相近,就由谁来捕获~

三、统一数据返回处理

1、大概介绍

咱们还是先大概介绍一下吧~

统一数据返回处理就是将程序中所有接口返回的数据进行统一处理,包装一下,统一返回一种类型,这样对前端来说,每次返回都是一种类型,也方便他们接收了,对于后端来说呢,进行统一处理,而不用一个接口一个接口的处理,大大提高了效率~

2、具体讲解

在代码层面具体如何进行统一处理的呢?实现ResponBodyAdvice接口,添加@ControllerAdvice注解,重写两个方法,第一个方法返回true,第二个方法返回数据~

3、出现的问题

在数据进行包装之前,类型已经是要求的统一类型了,又包装了一层~

返回String类型的数据时,报错,显示类型不匹配~

4、解决办法

在包装之前,先判断一下body的类型:

如果是result类型的,就不用再包装了,直接return  body,

如果是String类型的,对包装之后的数据进行处理。

5、为什么会报错

只简单说一下~

是因为在包装完之后,还会进行别的操作,只不过咱们看不见~

当包装完的String类型数据,变成我们统一的类型后,又把这个数据,传给了一个方法,用String类型的参数接收,由于这俩类型没啥关系,不能直接转换,所以就报了类型转换错误~

当然了,只有String类型的数据如此特殊,其余类型的数据不会报错~

四、补充知识(适配器模式)

1、大概介绍

也是大概介绍一下,先有个大概了解~

比方说。中国和美国的插座,咱们如果去了美国,咱们国内的电器不能直接使用美国的插座,所以就需要一个转换插座,把转换插座插到美国插座上,然后咱们国内电器使用这个转换插座,不直接使用美国的插座~

对于咱们的Java程序来说,美国插座相当于一个类,电器相当于另一个类,转换插座就相当于一个适配器,现在有一个业务,需要两个类结合使用,完成某一项任务,但是这两个类不兼容,无法结合,所以适配器隆重登场,适配器可以兼容这两个类,这样,这两个类通过适配器结合在一起了,只不过是间接结合而已,在适配器中去完成这一项任务~

2、代码讲解

大概讲解完了,咱们通过代码去实战演练一下~

五、在源码层面进行分析,统一异常处理和统一数据格式处理是咋执行的

1、大概讲解

咱还是先大概讲解一下吧:统一数据返回和统一异常都是基于@ControllerAdvice这个注解实现的,通过研究@ControllerAdvice这个注解相关的源码可以知道他们的执行流程~

从DispatcherServlet类开始分析,他在初始化阶段,咱重点关注这三个方法:

initHandlerMappings(context);初始化处理器的

initHandlerAdapters(context);初始化适配器的

initHandlerExceptionResolvers(context);初始化异常处理器的

2、插播几条知识

(先插播一条信息吧,讲解一下前两种方法,还有处理器和适配器之间的关系,这对后面的讲解至关重要)

initHandlerMappings(context);初始化处理器的,点进去看看这个方法:

594行-535行是这个方法的核心,这是从spring的容器中获取bean的,获取什么类型的bean的呢?获取实现了HandlerMapping接口的bean,也就是获取很多个处理器对象,不同的处理器会处理不同的内容,比如RequestMappingHandler,它的存在,正是@RequestMapping注解生效的主要原因,当请求发出后,它会获取到url,并做一个映射,什么映射呢?url对应哪个controller的映射,但是处理器无法直接做出这些内容,所以要借助相应的适配器来做,在适配器里面,完成处理器想要做出的内容。

initHandlerAdapters(context);初始化适配器的,点进去看看~

这个方法里面,又会获取到实现了HandlerMapping接口的对象,也就是各种适配器,去帮助不同的处理器完成相应的内容~

好,讲解完毕,咱们开始正题~

3、具体讲解

initHandlerAdapters(context);在这个方法里面,会获取到所有使用@ControllerAdvice的对象,再进行下一步处理,这就是统一数据返回格式能够生效的主要原因。

spring在启动的时候,会进行一系列初始化的工作,其中包括异常模块的处理,就是在initHandlerAdapters(context);里面处理的,具体如何处理的呢?若异常产生后,在异常处理类中有多个处理器,首先会进行匹配,若匹配到多个处理器,会进行排序,根据什么规则排序呢?根据抛出的异常相对于声明出的异常参数的深度,最后选择一个深度最低的处理器,对异常进行处理。

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

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

相关文章

MySQL关键字—using和on

文章目录 1. MySQL关键字—using和on1.1 using关键字的概念 2. using和on的区别2.1 USING 子句2.2 ON 子句 3. 示例对比3.1 建表:3.2 准备数据3.3 结果 1. MySQL关键字—using和on 1.1 using关键字的概念 连接查询时如果是同名字段作为连接条件,using可…

ctfhub Bypass disable_function(完结)0

LD_PRELOAD url 蚁剑连接 选择插件 点击开始 查看到此文件名编辑连接拼接到url后面重新连接 点击开启终端 在终端执行命令 ls / /readfile ShellShock url CTFHub 环境实例 | 提示信息 蚁剑连接 写入shell.php <?phpeval($_REQUEST[ant]);putenv("PHP_test() { :…

四款AI写作免费工具,让文案工作更轻松

作为一名文案编辑&#xff0c;我算是跟文字打了几年的交道了。最近&#xff0c;AI写作这股风潮真是吹得热火朝天&#xff0c;我也忍不住尝了尝鲜&#xff0c;试了试几款神器。说实话&#xff0c;这体验还挺有意思的&#xff0c;感觉就像是在文字的世界里开了一场高科技的派对。…

Redis:概念、部署、配置、优化

目录 关系型数据库与非关系型数据库 关系型数据库 非关系型数据库 非关系型数据库存在的原因 Redis 概念 优点 Redis部署流程 初步设置 安装 初始化 初始化时指定的参数说明 Redis配置文件 修改监听地址 Redis远程连接 远程连接 测试服务端状态 redis-benchm…

智慧景区系统:科技赋能旅游新体验

随着信息技术的飞速发展&#xff0c;旅游业正经历着前所未有的变革&#xff0c;智慧景区系统作为这一变革的先锋&#xff0c;正以其独特的魅力重塑着游客的旅行方式。智慧景区系统&#xff0c;顾名思义&#xff0c;是运用物联网、大数据、云计算、人工智能等现代信息技术&#…

Git客户端 TortoiseGit下载

1.概述 使用TortoiseGit比直接使用git客户端和命令来实现代码管理更为方便&#xff0c;本文贴出了软件的下载地址和基本配置信息 2.TortoiseGit安装与配置 TortoiseGit是TortoiseSVN的Git版本&#xff0c;是一个在Windows系统下使用的Git版本控制客户端。它提供了图形用户界…

MIT线性代数P5

置换矩阵 置换矩阵是行重新排列的单位矩阵。 置换矩阵用P表示&#xff0c; 性质&#xff1a; n阶置换矩阵共有n!个

37.x86游戏实战-XXX遍历怪物数组

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 工具下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1rEEJnt85npn7N38Ai0_F2Q?pwd6tw3 提…

0812|TCP和UDP跨主机通信

思维导图 TCP实现跨主机通信 服务器端 #include<myhead.h> #define SER_PORT 6666 //端口号 #define SER_IP "192.168.0.108" //服务器IP int main(int argc, const char *argv[]) {//创建套接字文件int sfd socket(AF_INET,SOCK_STREAM,0);if(sfd -1){pe…

进阶!haproxy高级功能与配置

文章目录 前言基于cookie的会话保持IP透传四层IP透传未开启状态开启透传状态 七层IP透传 自定义错误界面重定向HAProxy 四层负载之数据库HAProxy https 前言 本文主要介绍HAProxy高级配置及使用案例 文章相关连接如下&#xff1a; 如果想深入了解haproxy算法的相关知识&…

基于Python+Django+Vue+Mysql前后端分离的图书管理系统

利用空闲休息时间开始自己写了一套图书管理系统。现将源码开源&#xff0c;项目遇到问题 PythonDjangoVue图书管理系统开发全流程 大家好&#xff0c;我是程序员科科&#xff0c;这是我开源的基于PythonDjangoVue的图书管理系统 希望可以帮助想学前后端分离的同学 项目中遇…

积极创新模式,推动智慧场馆建设

智慧场馆是指基于信息技术应用的场馆建设模式&#xff0c;利用物联网、云计算、大数据分析等技术手段&#xff0c;实现场馆资源的管理优化、运营效率的提升以及用户体验的改善。智慧场馆在我国得到了广泛的政策支持和推动&#xff0c;政府出台了一系列鼓励智慧场馆建设的政策措…

Java SIP Client

采用JAIN SIP API实现一个SIP客户端实现向SIP服务器注册。SIP服务器可以为FreeSWITCH也可以为满足GB28181的SIP平台。话不多说直接看注册流程图&#xff1a; 代码实现&#xff1a; 创建maven工程添加依赖 <dependencies><dependency><groupId>javax.sip</…

Apple Maps现在可在Firefox和Mac版Edge浏览器中使用

Apple Maps最初只能在 Windows 版 Safari、Chrome 浏览器和 Edge 浏览器上运行&#xff0c;现在已在其他浏览器上运行&#xff0c;包括 Mac 版 Firefox 和 Edge。经过十多年的等待&#xff0c;Apple Maps于今年 7 月推出了新版地图应用的测试版&#xff0c;但只能在有限的浏览器…

哈希表 - 三数之和

15. 三数之和 方法一&#xff1a;排序双指针 /*** param {number[]} nums* return {number[][]}*/ var threeSum function(nums) {const res [], len nums.length;// 将数组排序nums.sort((a, b) > a - b)for (let i 0; i < len; i) {let l i 1, r len - 1, iNum…

什么是令牌桶算法?工作原理是什么?使用它有哪些优点和注意事项?

大家好&#xff0c;我是鸭鸭&#xff01; 此答案节选自鸭鸭最近弄的面试刷题神器面试鸭 &#xff0c;更多大厂常问面试题&#xff0c;可以点击下面的小程序进行阅读哈&#xff01; 目前这个面试刷题小程序刚出&#xff0c;有网页和小程序双端可以使用&#xff01; 回归面试题…

网络初学者必备:100个基础知识全掌握

网络安全学习路线 如果你对网络安全入门感兴趣&#xff0c;那么你需要的话可以点击这里网络安全重磅福利&#xff1a;入门&进阶全套282G学习资源包免费分享&#xff01; 或者扫描下方csdn官方合作二维码获取哦&#xff01; 1 什么是链接? 链接是指两个设备之间的连接。…

OpenCV 基本使用

OpenCV 基本使用 参考教程&#xff1a; GitHub - gaoxiang12/slambook2: edition 2 of the slambook 1. 安装 OpenCV 1.1 下载 OpenCV 参考教程&#xff1a; 无法定位软件包libjasper-dev的解决办法-CSDN博客 视觉slam14讲ch5 opencv安装 ubuntu20.04_libvtk5-dev-CSDN博…

机器学习——聚类算法K-Means

目录 一、初识聚类 1. 认识聚类算法 2. 聚类的流程 3. 簇内误差平方和 Inertia越小模型越好吗&#xff1f; 二、KMeans介绍 1. 重要参数n_clusters 2. 模型评估指标 &#xff08;1&#xff09;真实标签己知的时候 &#xff08;2&#xff09;真实标签未知的时候 三、s…

Tomcat 最大连接数实现原理

spring boot 内置tomcat设置连接数 max-connections: 5 server:port: 9898servlet:context-path: /testtomcat:connection-timeout: 5000max-connections: 5accept-count: 5 ##初始化连接数量connectionLimitLatch protected LimitLatch initializeConnectionLatch() {if (ma…