当前位置: 首页 > news >正文

SpringBoot异常处理?用这两个就够啦!

​ 在日常项目中,我们难免会遇到系统错误的情况。如果对系统异常的情况不做处理,Springboot本身会默认将错误异常作为接口的请求返回。

@GetMapping("/testNorError")
public void testNorError() {try {throw new MyException(6000, "我的错误");}catch (Exception e){throw new MyException(5000, "我的包装异常", e);}
}

在这里插入图片描述

​ 从上图可以看到,Springboot没有对异常进行处理的情况下,将错误的堆栈直接当做响应数据返回了。这样对用户既不友好,又可能因为泄漏系统堆栈信息引发潜在的安全风险。因此,搭建一个完善的异常处理机制,对于维护系统健壮性是十分必要的。

通用异常处理

​ 要快速的搭建异常处理机制,那么需要考虑如何对异常进行捕获并加以处理?最便捷的方法便是用**@ExceptionHandler**注解实现。

    @ExceptionHandler(MyException.class)protected ResponseEntity<Object> handleException(Exception ex) {LOGGER.error("Failed to execute,handleException:{}", ex.getMessage(), ex);return new ResponseEntity<>(new ResultDTO().fail(ResultCodeEnum.ERROR_SERVER), HttpStatus.OK);}

​ 通过在Controller内添加上述的异常处理代码,Springboot就可以将相关的错误信息转义成系统的统一错误处理,进而避免堆栈外露。(这里的ResultDTO是系统内自定义的JSON结构,可以根据自己的业务自行修改。)
在这里插入图片描述

​ 然而,@ExceptionHandler本身存在一个弊端,就是他作用的范围必须是Controller,也就意味着有多少个Controller,你的异常处理代码便要重复写多遍,这无疑是低效率的。为了减少重复的代码冗余,@ControllerAdvance就进入了我们的视野。

@ControllerAdvice
@Slf4j
public class ExtGlobalExceptionHandler {@ExceptionHandler(Exception.class)protected ResponseEntity<Object> handleException(Exception ex) {LOGGER.error("Failed to execute,handleException:{}", ex.getMessage(), ex);return new ResponseEntity<>(new ResultDTO().fail(ResultCodeEnum.ERROR_SERVER), HttpStatus.OK);}
}

​ 简单来说,@ControllerAdvance是一个全局处理的注解,其中的代码会对所有的Controller生效,通常会搭配@ExceptionHandler处理异常,由此以来就可以实现只编写一次异常处理方法就可以处理全局异常的情况。

​ 至于@ControllerAdvance和@ExceptionHandler是如何实现这个神奇的功能的,限于篇幅原因,后续会考虑单独出一篇文章详细介绍。(其实根据名字,不难推断ControllerAdvance就是一种针对于Controller对象的动态代理罢了。)

个性化异常处理

​ 用了@ControllerAdvance和ExceptionHandler,几乎可以解决80%的项目面临的报错处理问题。然而,思考一下。如果一个项目中出现了多组人同时维护、迭代一个系统的时候(降本增效嘛,懂的都懂),每组人要关注的报错自然会不一样。如A组人只关注报错A,B组人员只关注报错B,那么这种通用的异常解决方案是无法区分开的。

​ 针对于这种情况,就不得不请出另外一位大佬了,他就是:AOP,针对于动态代理有很多的实现方式和框架,这里我们直接默认采用SpringBoot的自带AOP框架:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId><version>2.1.11.RELEASE</version>
</dependency>

​ 不管选择的AOP实现框架是什么,要采用AOP编码都少不了以下两个步骤:

1、定义切点和执行时机(哪些地方要做增强)

2、定义通知(要怎么增强)

定义切点和执行时机

​ 对于Springboot自带的AOP框架,其执行时机共有以下五个:

增强时机增强类型异同点
@After后置增强目标方法执行之后调用增强方法
@Before前置增强目标方法执行之前先调用增强方法
@AfterReturning返回增强目标方法执行return之后返回结果之前调用增强方法,如果出异常则不执行
@AfterThrowing异常增强目标方法执行产生异常调用增强方法,需注意的是,处理后异常依旧会往上抛出,不会被catch。
@Around环绕增强环绕增强包含前面四种增强,通过一定的try-catch处理,环绕类型可以替代上述的任意一种增强。

了解了SpringBoot的动态代理的执行时机之后,我们还需要知道其定义切点的方式。框架定义切点的方式主要有两个:

  • 切点表达式

  • 注解

注释

​ 我们首先介绍注释的正确打开方式。要通过注解来实现自己的AOP,那么首先需要定义一个新的注解。这里我简单定义了一个注解:

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation {String SERVER_NAME() default "";String action() default "";
}

​ 在定义了注解以后,将注解定义为方法的入参,并通过@annotation()标注出注解的变量名称,由此就可以实现注解AOP的功能。

//处理注解的地方
@Around(value = "@annotation(name)")
public <T> T test(ProceedingJoinPoint point, MyAnnotation name) throws Throwable {String serverName = name.SERVER_NAME();//处理异常return handlerRpcException(point, serverName);
}//具体代码执行处
@MyAnnotation(SERVER_NAME = "下游系统", action = "操作处理")
public <T> T testFunction() {return (T) new ResultDTO<>().success(Boolean.TRUE);
}

切点表达式

​ Springboot的AOP中,还提供了一种十分强大的实现动态代理切点标注的方式,即切点表达式,其基本模式如下所示:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)

​ 注意到modifiers-pattern?、declaring-type-pattern?、throws-pattern?等携带问号的参数都是非必填的。紧接着我们来逐一介绍上述参数的含义:

  • modifiers-pattern?:修饰符匹配,主要表示的是切点是public/private/protected/default的哪一种。
  • ret-type-pattern:顾名思义,指的是返回值的类型,常见如:void/Boolean/String等
  • declaring-type-pattern?:这个指的是被增强的方法、属性的类路径,如com.example.demo.service.aop.MyAspect等
  • name-pattern(param-pattern):这个是相对关键的参数,指的是被增强的方法名称以及其对应的参数类型。
  • throws-pattern:throw-pattern见词知意,可以知道它是指的方法所抛出的异常类型。

除了了解了上述的表达式的基本匹配含义以外,还有几个特殊的符号通配指的提一下:

*****:匹配任何数量字符
:匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数(0个或者多个参数)
+:匹配指定类型及其子类型;仅能作为后缀放在类型模式后边

也许上面的代码和介绍让你一脸懵逼,没关系,可以简单看下下面两个表达式的含义,你就大致明白他们的含义了:

// 1、代表【返回值任意】且前缀为【com.example.demo.rpc】的【任意类下】【任意名称】的【所有参数】方法
execution(* com.example.demo.rpc.*.*(..))// 2、代表【返回值为Boolean】且位于【com.example.demo.rpc及其子包下】的【任意名称】的【以String为最后一个入参数】的方法
execution(Boolean com.example.demo.rpc..*(.., String))

借助于切面表达式,我们可以很自由灵活地定义出我们的切点,从而通过AOP实现我们对于异常的处理

@Pointcut("execution(Boolean com.example.demo.rpc..*(.., String)) || execution(另外一个表达式)")private void PointCutOfAnno() {
}@Around(value = "PointCutOfAnno()")
public <T> T testForAOP(ProceedingJoinPoint point) throws Throwable {//处理对应的异常return handlerRpcException(point, serverName);
}

总结

​ 本文介绍了两种Springboot下针对于异常处理的编写方法:

一、借助于@ControllerAdvance和@ExceptionHandler实现的通用异常处理方法

二、借助于AOP实现的个性化异常处理机制。

两者其实本质上的实现思路都是一样的,通过对执行代码做动态代理,从而将错误包装起来,达到异常不外漏的效果。在实际业务场景中,方法一几乎可以涵盖80%的异常处理场景。方案二则主要针对一个系统中需要做个性化处理的情况,可以根据具体的业务需要进行选择。

参考文献

@Pointcut 的 12 种用法,你知道几种?

相关文章:

SpringBoot异常处理?用这两个就够啦!

​ 在日常项目中&#xff0c;我们难免会遇到系统错误的情况。如果对系统异常的情况不做处理&#xff0c;Springboot本身会默认将错误异常作为接口的请求返回。 GetMapping("/testNorError") public void testNorError() {try {throw new MyException(6000, "我…...

mysql-查询重复数据的条数-count

查询重复数据的条数 select name , count(*) from table group by name&#xff1b; 查询结果&#xff1a;查询表table中name相同重复的个数 补充&#xff1a;count的用法 查询一个表中总共多少行&#xff08;多少条数据&#xff09; select count (*) from table 小结 …...

【Java枚举类】使用enum关键词定义枚举类

使用说明 1.使用 enum 定义的枚举类默认继承了 java.lang.Enum类&#xff0c;因此不能再继承其他类 2.枚举类的构造器只能使用 private 权限修饰符 3.枚举类的所有实例必须在枚举类中显式列出(, 分隔 ; 结尾)。列出的 实例系统会自动添加 public static final 修饰 4.必须在…...

第十四届蓝桥杯三月真题刷题训练——第 8 天

目录 第 1 题&#xff1a;分数 题目描述 运行限制 代码&#xff1a; 第 2 题&#xff1a;回文日期 题目描述 输入描述 输出描述 输入输出样例 运行限制 代码&#xff1a; 第 3 题&#xff1a;迷宫 代码&#xff1a; 第 1 题&#xff1a;分数 题目描述 本题为填空题…...

鼎阳SDS2074X Plus免费“升级”(破解)备忘录

鼎阳SDS2074X Plus从基础参数来看&#xff0c;在一众国产示波器里并不出彩。但作为一款可以免费“升级”到【1】4通道2GSa/s的采样率&#xff0c;500MHz分析带宽&#xff0c;200Mpts存储深度的数字示波器&#xff08;可惜原配的是200MHz的探头&#xff0c;500MHz的探头还是贵&a…...

【C++】C++标准模板库STL (一) string类的使用详解

前言 在前一章种我们介绍了C中的模板的使用&#xff0c;这是一种泛型编程&#xff0c;模板的使用能让我们减少大量的相似代码&#xff0c;减少我们的代码量与工作量&#xff0c;写出更加高效简洁的代码&#xff0c;模板如此好用&#xff0c;但还是要我们先出写一个泛型类或函数…...

如何用SpringBoot+Thymeleaf+Echart生成好看的柱状图,折线图,饼状图

一、前言 上篇文章我们用POI技术读取Excel并生成了相应的图表。但是实际的效果比较一般&#xff0c;因为本身WPS生成图表就比较简单&#xff0c;如果用程序操作远比人工耗时费力&#xff0c;效果远不如一些付费模板。如下图所示&#xff1a; 然后我就想到前端不是有一个简单易…...

LeetCode819. 最常见的单词(python)

题目 给定一个段落 (paragraph) 和一个禁用单词列表 (banned)。返回出现次数最多&#xff0c;同时不在禁用列表中的单词。 题目保证至少有一个词不在禁用列表中&#xff0c;而且答案唯一。 禁用列表中的单词用小写字母表示&#xff0c;不含标点符号。段落中的单词不区分大小写。…...

【深入理解C指针】经典笔试题——指针和数组

&#x1f539;内容专栏&#xff1a;【C语言】进阶部分 &#x1f539;本文概括&#xff1a;一些指针和数组笔试题的解析 。 &#x1f539;本文作者&#xff1a;花香碟自来_ &#x1f539;发布时间&#xff1a;2023.3.12 目录 一、指针和数组练习题 1. 一维数组 2. 字符数组 …...

雷达散射截面

雷达散射截面(Radar Cross Section, RCS)是表征目标散射强弱的物理量。 σ = 4 π R 2 ∣ E s ∣ 2 ∣ E i ∣ 2 \sigma = 4\pi R^2 \frac{|E_s |^2}{|E_i|^2}...

希腊棺材之谜——复盘

文章目录梗概推导伪解答虽然花费6-8小时来看小说&#xff0c;是一件很奢侈的事情。但是再荒诞的事情终归有它背后的逻辑链条。这正如Ellery所坚持的那样&#xff0c;逻辑为王。希腊棺材之谜是Ellery Queen首次展露头角&#xff0c; 因此作者特地给他安排了3次伪解答和1次真解答…...

CentOS的下载和安装

文章目录前言一、CentOS的下载二、如何下载1.选择下载版本2.选择isos3.点击isos后&#xff0c;进入如下页面&#xff0c;接着点击X86_644.一般选择下面框住的进行下载三、安装软件选择设置接着进行分区设置设置网络和主机名前言 在学习Linux时&#xff0c;记录下CentOS的安装 …...

new bing的chatGPT如何解析英文论文pdf

昨天我的new bing申请下来了&#xff0c;有了聊天的界面&#xff1a; 但是解析pdf的英文文献&#xff0c;还是不行&#xff0c;没有对话窗口。就问了一下chatGPT&#xff0c;方案如下&#xff1a; 要使用New Bing解析PDF文献&#xff0c;你需要以下几个步骤&#xff1a; 1&a…...

学会这12个Python装饰器,让你的代码更上一层楼

学会这12个Python装饰器&#xff0c;让你的代码更上一层楼 Python 装饰器是个强大的工具&#xff0c;可帮你生成整洁、可重用和可维护的代码。某种意义上说&#xff0c;会不会用装饰器是区分新手和老鸟的重要标志。如果你不熟悉装饰器&#xff0c;你可以将它们视为将函数作为输…...

企业使用ERP的好处

ERP系统是企业管理信息系统的简称&#xff0c;它是以信息技术为手段&#xff0c;以物流、资金流、信息流为主线&#xff0c;以企业的核心业务流程为对象&#xff0c;建立的一套适用于企业管理的、高效的企业管理信息系统。它是通过科学方法和计算机信息技术&#xff0c;将企业运…...

【QT】如何获取屏幕(桌面)的大小或分辨率

目录1. QDesktopWidget 获取系统屏幕大小2. QScreen 获取系统屏幕大小3. geometry() 与 availableGeometry() 的区别1. QDesktopWidget 获取系统屏幕大小 QDesktopWidget 提供了详细的位置信息&#xff0c;其能够自动返回窗口在用户窗口的位置和应用程序窗口的位置 QDesktopW…...

ETL工具的选择

正确选择 ETL 工具&#xff0c;可以从 ETL 对平台的支持、对数据源的支持、数据转换功能、管理 和调度功能、集成和开放性、对元数据管理等功能出发&#xff0c;具体如下。 支持平台 随着各种应用系统数据量的飞速增长和对业务可靠性等要求的不断提高&#xff0c;人们对数据抽…...

SpringBoot仿天猫商城java web购物网站的设计与实现

1&#xff0c;项目介绍 基于 SpringBoot 的仿天猫商城拥有两种角色&#xff0c;分别为管理员和用户。 迷你天猫商城是一个基于SSM框架的综合性B2C电商平台&#xff0c;需求设计主要参考天猫商城的购物流程。 后端页面兼容IE10及以上现代浏览器&#xff0c;Chrome,Edge,Firebox…...

C#基础教程22 文件的输入与输出

C# 文件的输入与输出 一个 文件 是一个存储在磁盘中带有指定名称和目录路径的数据集合。当打开文件进行读写时,它变成一个 流。 从根本上说,流是通过通信路径传递的字节序列。有两个主要的流:输入流 和 输出流。输入流用于从文件读取数据(读操作),输出流用于向文件写入数…...

Ubuntu18.04 python 开发usb通信

一、安装环境 1.安装pip sudo python3 get-pip.py 或 sudo -i apt update apt install python3-pip 确定pip是否安装成功&#xff1a; xxx-desktop:~$ pip3 --versionpip 9.0.1 from /usr/lib/python3/dist-packages (python 3.6)2.安装pyusb pip3 install pyusb --use…...

<6>-MySQL表的增删查改

目录 一&#xff0c;create&#xff08;创建表&#xff09; 二&#xff0c;retrieve&#xff08;查询表&#xff09; 1&#xff0c;select列 2&#xff0c;where条件 三&#xff0c;update&#xff08;更新表&#xff09; 四&#xff0c;delete&#xff08;删除表&#xf…...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:

根据万维钢精英日课6的内容&#xff0c;使用AI&#xff08;2025&#xff09;可以参考以下方法&#xff1a; 四个洞见 模型已经比人聪明&#xff1a;以ChatGPT o3为代表的AI非常强大&#xff0c;能运用高级理论解释道理、引用最新学术论文&#xff0c;生成对顶尖科学家都有用的…...

return this;返回的是谁

一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请&#xff0c;不同级别的经理有不同的审批权限&#xff1a; // 抽象处理者&#xff1a;审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

数据结构:递归的种类(Types of Recursion)

目录 尾递归&#xff08;Tail Recursion&#xff09; 什么是 Loop&#xff08;循环&#xff09;&#xff1f; 复杂度分析 头递归&#xff08;Head Recursion&#xff09; 树形递归&#xff08;Tree Recursion&#xff09; 线性递归&#xff08;Linear Recursion&#xff09;…...

32单片机——基本定时器

STM32F103有众多的定时器&#xff0c;其中包括2个基本定时器&#xff08;TIM6和TIM7&#xff09;、4个通用定时器&#xff08;TIM2~TIM5&#xff09;、2个高级控制定时器&#xff08;TIM1和TIM8&#xff09;&#xff0c;这些定时器彼此完全独立&#xff0c;不共享任何资源 1、定…...

PH热榜 | 2025-06-08

1. Thiings 标语&#xff1a;一套超过1900个免费AI生成的3D图标集合 介绍&#xff1a;Thiings是一个不断扩展的免费AI生成3D图标库&#xff0c;目前已有超过1900个图标。你可以按照主题浏览&#xff0c;生成自己的图标&#xff0c;或者下载整个图标集。所有图标都可以在个人或…...

webpack面试题

面试题&#xff1a;webpack介绍和简单使用 一、webpack&#xff08;模块化打包工具&#xff09;1. webpack是把项目当作一个整体&#xff0c;通过给定的一个主文件&#xff0c;webpack将从这个主文件开始找到你项目当中的所有依赖文件&#xff0c;使用loaders来处理它们&#x…...

云原生安全实战:API网关Envoy的鉴权与限流详解

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关 作为微服务架构的统一入口&#xff0c;负责路由转发、安全控制、流量管理等核心功能。 2. Envoy 由Lyft开源的高性能云原生…...