SpringBoot之全局异常处理

默认情况下的异常现象

创建一个接口 (接口需要传递参数key)
@RestController
@RequestMapping("/exception")
public class ExceptionController {@GetMapping("/accept")public String acceptKey(@RequestParam("key") String key) {return key;}
}
访问链接(不传递参数key,使得抛出异常) http://localhost:8080/exception/accept
在浏览器中的现象

在 Postman 中的现象

小结

在浏览器中返回一个 html 页面,在 Postman 中返回一个 json 数据

解决方案

在默认静态资源路径下创建 error 子文件夹,并创建文件 400.html

默认静态资源路径如下:

  • classpath:/META-INF/resources/
  • classpath:/resources/
  • classpath:/static/
  • classpath:/public/

400.html 明细如下所示:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><h1>404</h1>
</body>
</html>

再次在浏览器下访问链接 : http://localhost:8080/exception/accept

PS:错误码需要和 html 名字一致,或者将 html 改成 4xx、5xx,这样以 4 开头的错误码就会跳转到 4xx.html,以 5 开头的错误码就会跳转到 5xx.html

再次在 Postman 中访问链接 : http://localhost:8080/exception/accept

好像并没有起作用,我们再尝试其他方法

创建 GlobalExceptionHandler,处理全局异常
创建实体类 ExceptionInfo
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ExceptionInfo {private String msg;
}
创建全局异常处理配置类 GlobalExceptionHandler
@ControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(value = Exception.class)@ResponseBodypublic ExceptionInfo resolverException(Exception exception) {ExceptionInfo exceptionInfo = new ExceptionInfo();exceptionInfo.setMsg(exception.getMessage());return exceptionInfo;}
}
访问链接 : http://localhost:8080/exception/accept

源码解析

ErrorMvcAutoConfiguration

ErrorMvcAutoConfiguration 会定义一个类型为 BasicErrorController 的  Bean。BasicErrorController 中定义了两个接口方法:errorHtmlerror ,其中 errorHtml 方法只对 request 的 accept 能兼容 text/html 的请求有效,error 方法则可以认为是一个兜底方法,它对 request 的 accept 没有要求

当我们的请求抛出异常,会转发到这个接口(/error),如果这个默认的 URI(/error) 和我们的项目有冲突,我们可以在配置文件中定义 server.error.path | error.path 来修改默认值。

StandardHostValve#custom (请求转发)

DispatcherServlet#processDispatchResult

我们需要关注两个方法 processHandlerExceptionrender

case1:访问一个不存在的接口或者不存在的文件

这种情况 exception 和 mv(ModelAndView)都为 null,所以既不会执行 processHandlerException 方法,也不会执行 render 方法,然后转发到 /error 接口。

在 Postman 中发请求,Accept 默认为 */*,在浏览器中发请求 Accept  如下所示:

根据一定的规则,在 Postman 中默认转发到 error 方法,在浏览器中默认转发到 errorHtml 方法

AbstractHandlerMethodMapping#lookupHandlerMethod (请求映射规则)

case1.1 转发到 error 方法

该方法会构建一个 map 对象,设置 timestampstatuserrorpath 等信息并响应

case1.2 转发到 errorHtml 方法

默认情况下 errorViewResolvers 只有一个,类型为 DefaultErrorViewResolver,它是在 ErrorMvcAutoConfiguration 内部类 DefaultErrorViewResolverConfiguration 中定义的,相关源码如下:

DefaultErrorViewResolver#resolveErrorView

当我们访问一个不存在的链接,viewName 为  404,errorViewName 为 error/404,如果 TemplateAvailabilityProviders 的 getProvider 方法返回一个非 null 对象,则返回一个 ModelAndView 对象

TemplateAvailabilityProviders#getProvider

如果 TemplateAvailabilityProvider 的 isTemplateAvailable 方法返回 true,则返回当前 TemplateAvailabilityProvider 对象,即最终会返回一个 ModelAndView 对象

根据 SpringBoot 的自动配置,容器中存在五个 TemplateAvailabilityProvider ,我们来看一下 ThymeleafTemplateAvailabilityProvider 的 isTemplateAvailable 方法。

即默认情况下,如果我们的环境中,存在指定的类(org.thymeleaf.spring5.SpringTemplateEngine),并且资源 classpath:/templates/error/404.html 存在,则返回一个 ModelAndView 对象

可以导入下方所示的依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId><version>2.6.13</version>
</dependency>

DefaultErrorViewResolver#resolveResource

如果 TemplateAvailabilityProviders 的 getProvider 方法返回 null,则继续调用 resolveResource 方法。该方法会遍历 staticLocations,判断这些默认静态文件路径下是否存在相关文件(是否存在error/404.html),如果存在则构建一个 HtmlResourceView 对象,staticLocations 明细列表如下:

  • classpath:/META-INF/resources/
  • classpath:/resources/
  • classpath:/static/
  • classpath:/public/

DefaultErrorViewResolver#resolveErrorView (2)

如果错误状态码是以 4 或 5 开头,则以 viewName 为  4xx,errorViewName 为 error/4xx,再执行一遍上述的流程

BasicErrorController#errorHtml(2)

即不管我们有没有在当前环境中找到指定文件,都会返回一个 ModelAndView 对象,如果存在以下资源,viewName 则不为 error:

  1. classpath:/templates/error/404.html  => view:error/404
  2. classpath:/META-INF/resources/404.html => view:HtmlResourceView
  3. classpath:/resources/404.html  => view:HtmlResourceView
  4. classpath:/static/404.html  => view:HtmlResourceView
  5. classpath:/public/404.html  => view:HtmlResourceView
  6. classpath:/templates/error/4xx.html => view:error/4xx
  7. classpath:/META-INF/resources/4xx.html => view:HtmlResourceView
  8. classpath:/resources/4xx.html => view:HtmlResourceView
  9. classpath:/static/4xx.html => view:HtmlResourceView
  10. classpath:/public/4xx.html => view:HtmlResourceView
  11. 其他 => view:error

DispatcherServlet#processDispatchResult(2)

第二次进入 DispatcherServlet 的 processDispatchResult 方法,此时 mv 不等于null,则进入render 方法

如果 viewName 为 error/404、error/4xx、error 则执行 resolveViewName 方法

一共有5个resolver,我们只需要关注 ContentNegotiatingViewResolver 的 resolveViewName 方法

ContentNegotiatingViewResolver 的内部属性 viewResolvers 有其他四个 resolvers,即 ContentNegotiatingViewResolver 相当于一个大管家,具体还是由其他四个 resolvers 处理,我们简要分析一下 beanNameViewResolver

ErrorMvcAutoConfiguration 的内部类 WhitelabelErrorViewConfiguration 会定义两个bean,其中一个 beanName 为 error,类型为 View,另一个 beanName 为 beanNameViewResolver,类型为 BeanNameViewResolver

即 BeanNameViewResolver 的 resolveViewName 方法会返回一个类型为 StaticView 的 View

View#render

StaticView#render

我们可以看到 StaticView 的 render 方法就是我们经常看到的页面

StaticView#render

HtmlResourceView#render

HtmlResourceView 的 render 方法就是将指定资源用流写出去

case2:访问一个存在的接口且抛出异常
DispatcherServlet#processHandlerException

一共有两个 HandlerExceptionResolver,其中一个类型为 DefaultErrorAttributes,DefaultErrorAttributes 的 resolveException 方法比较简单,主要是给 request 赋值,我们主要关注 HandlerExceptionResolverComposite 的 resolveException 方法

HandlerExceptionResolverComposite#resolveException

一共有三个 HandlerExceptionResolver,我们主要分析一下 ExceptionHandlerExceptionResolver的 resolveException 方法

ExceptionHandlerExceptionResolver#resolveException

最终会执行类上标记 @ControllerAdvice 注解,方法上标记 @ExceptionHandler 注解的符合条件的方法,就是我们在【解决方案】的 GlobalExceptionHandler#resolverException 方法

如何选择 ServletInvocableHandlerMethod

遍历 exceptionHandlerAdviceCache 对象,通过 ExceptionHandlerMethodResolver 的resolveMethod 方法,获取一个 method 对象,并将其封装成 ServletInvocableHandlerMethod 对象

isApplicableToBeanType

以下四种情况,@ControllerAdvice注解生效:

  1. 什么都没有配置
  2. Controller所在的类路径以配置的 basePackages 开头
  3. Controller类型是指定的类或是其子类
  4. Controller上含有指定注解

resolveMethod

遍历 mappedMethods 对象,如果存在多个 @ExceptionHandler 标注的方法,则选择一个优先级最高的

ExceptionHandlerExceptionResolver 的 exceptionHandlerAdviceCache 是如何赋值的

ExceptionHandlerExceptionResolver 继承 InitializingBean 接口,所以 bean 在实例化的过程中会执行其 afterPropertiesSet 方法

ExceptionHandlerExceptionResolver#afterPropertiesSet

如果 bean 上存在 @ControllerAdvice 注解,则构建一个 ControllerAdviceBean 对象

循环遍历查找出来的 adviceBeans,每存在一个 ControllerAdviceBean,则构建一个ExceptionHandlerMethodResolver 并将其 put 到 exceptionHandlerAdviceCache

ExceptionHandlerMethodResolver的实例化(给 mappedMethods 赋值)

如果方法存在 @ExceptionHandler 注解,则给 mappedMethods 赋值

PS : 如果 @ExceptionHandler 注解标注的方法也抛出异常,则使用 case1 做兜底

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

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

相关文章

C语言第5天作业 7月16日

目录 1.求1000以内所有的质数。 2.有1、2、3、4个数字&#xff0c;能组成多少个互不相同且无重复数字的三位数&#xff1f;都是多少&#xff1f; 3.猴子吃桃问题 4.判断最大值 1.求1000以内所有的质数。 质数&#xff1a;只能够1和它本身整除 #include <stdio.h> in…

Camera Raw:首选项

Camera Raw 首选项 Preferences提供了丰富的配置选项&#xff0c;通过合理设置&#xff0c;可以显著提升图像处理的效率和效果。根据个人需求调整这些选项&#xff0c;有助于创建理想的工作环境和输出质量。 ◆ ◆ ◆ 打开 Camera Raw 首选项 方法一&#xff1a;在 Adobe Bri…

Linux系统学习日记——vim操作手册

Vim编辑器是linux下的一个命令行编辑器&#xff0c;类似于我们windows下的记事本。 目录 打开文件 编辑 保存退出 打开文件 打开 hello.c不存在也可以打开&#xff0c;保存时vim会自动创建。 效果 Vim打开时&#xff0c;处于命令模式&#xff0c;即执行命令的模式&#x…

解决IDEA 中出现已有类、函数找不到的情况

缓存导致部分索引失效&#xff0c;需要刷新缓存并重启idea即可 1、File > Invalidate Cache / Restart... 2、Invalidate and Restart

聊聊常见的分布式ID解决方案

highlight: xcode theme: vuepress 为什么要使用分布式ID&#xff1f; 随着 Web 开发技术的不断发展&#xff0c;单体的系统逐步走向分布式系统。在分布式系统中&#xff0c;使用分布式 ID(Distributed IDs)主要是为了在没有单点故障的情况下生成唯一标识符。这些唯一标识符在很…

C++【OpenCV】图片亮度色度归一化

#include <opencv2/highgui.hpp> #include <opencv2/imgproc.hpp> #include <iostream>using namespace cv; using namespace std;int main() {Mat image imread("SrcMF.jpg");// 灰度、Gamma归一化亮度cv::Mat m_gray;cv::cvtColor(image, m_gra…

Linux-CentOS7忘记密码找回步骤

虚拟机版本 一、进入开机页面&#xff0c;先按上下&#xff08;↑↓&#xff09;键&#xff0c;以免系统自动启动。 二、按“e”键进入编辑页面,找到如下图位置&#xff0c;输入&#xff1a;init/bin/sh 按CTRLX 进入单用户模式。 三、 输入 mount -o remount,rw / 然后按 ent…

【ARMv8/v9 GIC- 700 系列 2 -- GIC-700 上电控制寄存器 GICR_PWRR】

请阅读【ARM GICv3/v4 实战学习 】 文章目录 GIC-700 上电GICR_PWRR 寄存器字段介绍GICR_PWRR 功能说明GICR_PWER 代码配置GICR_PWRR 使用场景GICR_PWRR 注意事项GIC-700 上电 GICR_PWRR(功耗寄存器)是ARM GICv4架构中用于控制GIC-700是否可以关闭电源的寄存器。它通过几个位…

Go语言并发编程-Goroutine调度

goroutine 概念 在Go中&#xff0c;每个并发执行的单元称为goroutine。通常称为Go协程。 go 关键字启动goroutine go中使用关键字 go 即可启动新的goroutine。 示例代码&#xff1a; 两个函数分别输出奇数和偶数。采用常规调用顺序执行&#xff0c;和采用go并发调用&…

如何用EXCEL自动解方程/方程组?利用 矩阵乘法X=A-*B,X=mmult(minverse(A), B)

目录 问题的由来 1 数据 → 模拟分析 → 单变量求解 1.1 找一个单元格填入公式 1.2 功能入口 1.3 选择单变量求解&#xff0c;分别填入内容 1.4 求解 1.5 这个感觉用处不大 2 重点介绍&#xff0c;用EXCEL进行矩阵运算解方程的操作 2.1 运用EXCEL进行矩阵运算&…

Mac 安装MySQL 配置环境变量 修改密码

文章目录 1 下载与安装2 配置环境变量3 数据库常用命令3.1 Mac使用设置管理mysql服务启停 4 数据库修改root密码4.1 知道当前密码4.2 忘记当前密码4.3 问题 参考 1 下载与安装 官网&#xff1a;https://www.mysql.com/ 找到开源下载方式 下载社区版 2 配置环境变量 对于Mac…

Ubuntu16.04环境下Baxter机器人开发环境搭建要点说明

Ubuntu16.04环境下Baxter机器人开发环境搭建要点说明 前面写过一篇文章&#xff0c;描述了在ubuntu20.04环境下baxter机器人开发环境的搭建&#xff0c;本人在后来的使用中&#xff0c;出于一些原因又在ubuntu16环境下搭建了开发环境&#xff0c;二者总体流程基本类似&#xf…

TikTok内嵌跨境商城全开源_搭建教程/前端uniapp+后端源码

多语言跨境电商外贸商城 TikTok内嵌商城&#xff0c;商家入驻一键铺货一键提货 全开源完美运营&#xff0c;接在tiktok里面的商城内嵌&#xff0c;也可单独分开出来当独立站运营 二十一种语言&#xff0c;可以做很多国家的市场&#xff0c;支持商家入驻&#xff0c;多店铺等等…

大数据之数据抽取架构演变过程

架构演变之Flink架构的演变过程 一、 起初搭建整个大数据平台是基于CDH这一套资源管理和整合的CM资源管理器搭建的 整个平台包括了&#xff1a; HDFS&#xff0c;YARN&#xff0c;HIVE&#xff0c;zoozie,FLINK,Spark,Zookeeper等组件搭建而成&#xff0c; 刚开始搭建的时候&am…

golang 基础 泛型编程

&#xff08;一&#xff09; 示例1 package _caseimport "fmt"// 定义用户类型的结构体 type user struct {ID int64Name stringAge uint8 }// 定义地址类型的结构体 type address struct {ID intProvince stringCity string }// 集合转列表函数&#…

第十届能源材料与电力工程国际学术会议(ICEMEE 2024)

第十届能源材料与电力工程国际学术会议&#xff08;ICEMEE 2024) 2024 10th International Conference on Energy Materials and Electrical Engineering 重要信息 ICEMEE 2024已通过SPIE - The International Society for Optical Engineering (ISSN: 0277-786X)单独出版…

Linux入门以及Linux文件编程学习

Linux学习必备 首先我们学习Linux必须安装一个虚拟机&#xff0c;我是跟着韦东山老师安装的&#xff0c;具体可以跟着视频操作&#xff0c;简单易懂&#xff1a;安装虚拟机 Linux入门最基本简单的指令 一、Vi的使用 Vi文件名 创建或者打开一个文件&#xff0c;进入默认命令行…

notes for datawhale summer camp NPL task3

了解 Transformer 模型&#xff0c;并基于 Transformer 模型实现在机器翻译任务上的应用&#xff01; Transformer 介绍 基于循环或卷积神经网络的序列到序列建模方法是现存机器翻译任务中的经典方法。然而&#xff0c;它们在建模文本长程依赖方面都存在一定的局限性。 为了…

[PM]产品运营

生命周期 运营阶段 主要工作 拉新 新用户的定义 冷启动 拉新方式 促活 用户活跃的原因 量化活跃度 运营社区化/内容化 留存 用户流失 培养用户习惯 用户挽回 变现 变现方式 付费模式 广告模式 数据变现 变现指标 传播 营销 认识营销 电商营销中心 拼团活动 1.需求整理 2.…

大数据之路 读书笔记 Day7 实时技术 简介及流式技术架构

回顾&#xff1a; Day6 离线数据开发之数据开发平台Day5 数据同步遇到的问题与解决方案 1. 简介 阿里巴巴在流式数据处理方面采用了多种技术和框架&#xff0c;这些技术的特点包括&#xff1a; 高可伸缩性&#xff1a; 阿里巴巴使用Apache Flink进行大规模数据处理&#xff0c…