三.统一异常Exception拦截处理

文章目录

  • 前言
  • 一、先定义一个业务异常类
  • 二、定义全局异常处理器
  • 二、测试
      • 小插曲
      • 抛出异常:
      • 抛出自定义异常:
  • 总结


前言

上一章对统一返回值进行封装,但是都是基于正常情况下的返回,系统难免会出现异常的情况,我们不可能在每一个地方都try...catch,但是异常有分为很多种类,我们需要对异常进行统一的拦截,希望友好的返回给客户端信息,而不是报一堆错误代码…


Spring中提供了一个@RestControllerAdvice它是 @ControllerAdvice@ResponseBody 的结合体,意味着使用该注解的类可以为所有的@RequestMapping 处理方法提供通用的异常处理和数据绑定等增强功能,并且方法的返回值将被直接写入 HTTP 响应体中,这里用来做全局异常处理正合适不过。

我们需要配合@ExceptionHandler@ResponseStatus一起结合着使用

  • @ExceptionHandler该注解用于标注在异常处理方法,该方法需要@RestControllerAdvice写到类中,其作用是当控制器抛出异常时候,Spring会根据异常的类型调用相应的异常处理方法,我们可以利用该注解实现各种不同类型的异常处理逻辑

  • @ResponseStatus该注解也是注解到异常处理方法上的,主要是为了设置返回的http状态码。如果我们希望在后端异常的时候,客户端的http状态码也跟随变化,则需要用到此注解


一、先定义一个业务异常类

com.light.common中创建一个exception包,并在exception中创建一个ServiceException代码如下:

import com.light.common.result.IResultCode;import java.io.Serial;/*** 自定义业务异常类*/
public class ServiceException extends RuntimeException {@Serialprivate static final long serialVersionUID = -2184933109131865121L;private IResultCode resultCode;public ServiceException(IResultCode resultCode) {super(resultCode.getMessage());this.resultCode = resultCode;}public ServiceException(String message) {super(message);}public ServiceException(Throwable cause) {super(cause);}public ServiceException(String message, Throwable cause) {super(message, cause);}public IResultCode getErrorCode() {return resultCode;}
}

二、定义全局异常处理器

exception中创建一个GlobalExceptionHandler代码如下:

import cn.hutool.core.convert.Convert;
import cn.hutool.http.HTMLFilter;
import com.light.common.result.BaseResult;
import com.light.common.result.ResultCode;
import io.micrometer.common.util.StringUtils;
import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;/*** 全局异常处理器*/
@RestControllerAdvice
public class GlobalExceptionHandler {private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);/*** 自定义业务异常*/@ExceptionHandler(ServiceException.class)@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)@ResponseBodypublic Object handleServiceException(ServiceException e, HttpServletRequest request) {log.error("自定义业务异常,'{}'", e.getMessage(), e);if (e.getErrorCode() != null) {return BaseResult.error(e.getErrorCode());}return BaseResult.error(e.getMessage());}/*** 自定义验证异常*/@ExceptionHandler(BindException.class)@ResponseStatus(HttpStatus.BAD_REQUEST)@ResponseBodypublic BaseResult<?> handleBindException(BindException e) {log.error(e.getMessage(), e);BindingResult bindingResult = e.getBindingResult();String message = null;if (bindingResult.hasErrors()) {FieldError fieldError = bindingResult.getFieldError();if (fieldError != null) {message = fieldError.getField() + fieldError.getDefaultMessage();}}return BaseResult.error(message);}/*** 请求参数类型不匹配*/@ExceptionHandler(MethodArgumentTypeMismatchException.class)@ResponseStatus(HttpStatus.BAD_REQUEST)@ResponseBodypublic BaseResult<?> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e,HttpServletRequest request) {String requestURI = request.getRequestURI();String value = Convert.toStr(e.getValue());if (StringUtils.isNotEmpty(value)) {value = new HTMLFilter().filter(value);}log.error("请求参数类型不匹配'{}',发生系统异常.", requestURI, e);return BaseResult.error(String.format("请求参数类型不匹配,参数[%s]要求类型为:'%s',输入值为:'%s'", e.getName(), e.getRequiredType().getName(), value));}/*** 请求路径中缺少必需的路径变量*/@ExceptionHandler(MissingPathVariableException.class)@ResponseStatus(HttpStatus.BAD_REQUEST)@ResponseBodypublic BaseResult<?> handleMissingPathVariableException(MissingPathVariableException e, HttpServletRequest request) {String requestURI = request.getRequestURI();log.error("请求路径中缺少必需的路径变量'{}',发生系统异常.", requestURI, e);return BaseResult.error(String.format("请求路径中缺少必需的路径变量[%s]", e.getVariableName()));}/*** 参数验证异常*/@ExceptionHandler(MethodArgumentNotValidException.class)@ResponseStatus(HttpStatus.BAD_REQUEST)@ResponseBodypublic BaseResult<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) {String requestURI = request.getRequestURI();BindingResult bindingResult = e.getBindingResult();String message = null;if (bindingResult.hasErrors()) {FieldError fieldError = bindingResult.getFieldError();if (fieldError != null) {message = fieldError.getField() + fieldError.getDefaultMessage();}}log.error("请求地址'{}',参数验证失败", requestURI);return BaseResult.error(ResultCode.VALIDATE_FAILED, message);}/*** 请求方式异常*/@ExceptionHandler(HttpRequestMethodNotSupportedException.class)@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)@ResponseBodypublic BaseResult<?> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,HttpServletRequest request) {String requestURI = request.getRequestURI();log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod());return BaseResult.error(ResultCode.METHOD_FAILED, "请求方式不支持:{}" + e.getMethod());}/*** 拦截未知的运行时异常*/@ExceptionHandler(RuntimeException.class)@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)@ResponseBodypublic BaseResult exceptionHandler(RuntimeException e, HttpServletRequest request) {String requestURI = request.getRequestURI();log.error("请求地址'{}',发生未知异常.", requestURI, e);return BaseResult.error("未知异常:"+e.getMessage());}/*** 拦截系统异常*/@ExceptionHandler(Exception.class)@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)@ResponseBodypublic BaseResult handleException(Exception e, HttpServletRequest request) {String requestURI = request.getRequestURI();log.error("请求地址'{}',发生系统异常.", requestURI, e);return BaseResult.error("系统异常:"+e.getMessage());}
}

二、测试

通过上述代码处理后,我们在写业务逻辑的时候,只需要关心自己的主要业务,无需花费大量精力去写try...catch

小插曲

直接测试会发现无效,返回的信息并不是我们定义的消息类结构,原因是默认情况下,Spring Boot会扫描启动类所在包及其子包,而我们这里的ControllerGlobalExceptionHandler分别在不同的子模块中,所以没有被关联上,我们只需要在启动类上添加手动扫描包路径即可

@SpringBootApplication
@ComponentScan(basePackages = {"com.light.api", "com.light.common"})
public class LightApiApplication {public static void main(String[] args) {SpringApplication.run(LightApiApplication.class, args);}
}

抛出异常:

  • 我们在控制器中人为制造一个异常比如,除数为0
    @GetMapping("/getMsg")public BaseResult<?> getTest() {int s=1/0;
//        throw new ServiceException("自定义异常");return BaseResult.success("成功");}

测试请求,返回结果如下
在这里插入图片描述

抛出自定义异常:

如果需要对自己的业务代码进行自定义抛出异常可采用此方式

    @GetMapping("/getMsg")public BaseResult<?> getTest() {throw new ServiceException("自定义异常");}

测试请求,返回结果如下
在这里插入图片描述

总结

至此,我们对整个系统进行的全局异常的统一处理,写代码的时候不再花费大量精力考虑try...catch的事情了,这也是后端需要做到的统一返回标准

下一章写统一日志处理

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

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

相关文章

Xcode 16 编译弹窗问题、编译通过无法,编译通过打包等问题汇总

问题1&#xff1a;打包的过程中不断提示 &#xff1a;codesign 想要访问你的钥匙串中的密钥“develop 或者distribution 证书” 解决&#xff1a;打开钥匙串&#xff0c;点击证书---显示简介---信任----改为始终信任 &#xff08;记住 &#xff1a;不能只修改钥匙的显示简介的…

汽车IVI中控开发入门及进阶(44):杰发科智能座舱芯片

概述: 杰发科技自成立以来,一直专注于汽车电子芯片及相关系统的研发与设计。 产品布局: 合作伙伴: 杰发科技不断提升产品设计能力和产品工艺,确保产品达 到更高的质量标准。目前杰发科技已通过ISO9001质 量管理体系与CMMIL3认证。 杰发科技长期合作的供应商(芯片代工厂、…

Linux系统安装部署xtrabackup

简介 xtrabackup一款强大的在线热备份工具备份过程中不锁库表&#xff0c;适合生产环境由专业组织Percona提供&#xff08;改进MySQL分支&#xff09; 下载xtrabackup xtrabackup官网地址&#xff1a;https://www.percona.com/ 进去官网后&#xff0c;下滑到底部导航栏&…

有没有检测吸烟的软件 ai视频检测分析厂区抽烟报警#Python

在现代厂区管理中&#xff0c;安全与规范是重中之重&#xff0c;而吸烟行为的管控则是其中关键一环。传统的禁烟管理方式往往依赖人工巡逻&#xff0c;效率低且存在监管死角&#xff0c;难以满足当下复杂多变的厂区环境需求。此时&#xff0c;AI视频检测技术应运而生&#xff0…

idea设置控制台日志输出自动换行

文章目录 1. 原因2. 方法一&#xff1a;3. 方法二&#xff1a; 1. 原因 你是否碰到ideal控制台输入日志是一行的效果&#xff0c;那是因为带了soft wrap。 2. 方法一&#xff1a; 最新版的IDEA设置控制台自动换行位置如下&#xff1a; Setting->Editor->General->C…

某科技局国产服务器PVE虚拟化技术文档

环境介绍 硬件配置 服务器品牌&#xff1a;黄河 型号&#xff1a;Huanghe 2280 V2 Cpu型号&#xff1a;kunpeng-920 磁盘信息 :480SSD * 2 ,4T*4 网卡&#xff1a;板载四口千兆 如下表 四台服务器同等型号配置&#xff0c;均做单节点虚拟化&#xff0c;数据保护采用底层r…

华为实训课笔记 2024 1223-1224

华为实训 12/2312/24 12/23 [Huawei]stp enable --开启STP display stp brief --查询STP MSTID Port Role STP State Protection 实例ID 端口 端口角色 端口状态 是否开启保护[Huawei]display stp vlan xxxx --查询制定vlan的生成树计算结…

个人笔记:ORM数据库框架EFCore使用示例,运行通过,附源码

个人笔记&#xff1a;ORM数据库框架EFCore使用示例&#xff0c;运行通过&#xff0c;附源码 0.新建项目1. 设置环境1.1. 添加 NuGet 包1.2. 创建模型类 2. 创建上下文类3. 创建数据库和表3.1. 启用迁移3.2. 更新数据库 4. 插入数据5. 查询数据6. 更新数据7. 删除数据8. 完整示例…

vue 集成 webrtc-streamer 播放视频流 - 解决阿里云内外网访问视频流问题

资料&#xff1a; 史上最详细的webrtc-streamer访问摄像机视频流教程-CSDN博客 webrtc目录 前端集成 html文件夹里的webrtcstreamer.js&#xff0c;集成到前端&#xff0c;可以访问webrtc&#xff0c;转换rtsp为webrtc视频流&#xff0c;在前端video中播放 <videoref&quo…

Unity3D仿星露谷物语开发5之角色单例模式

1、目的 使用单例模式创建角色对象&#xff0c;保证整个游戏中只有一个角色&#xff0c;并且让游戏对象具有全局可访问性。 2、流程 &#xff08;1&#xff09;创建SingletonMonobehaviour脚本 Assets下创建Scripts目录用于存放所有的脚本&#xff0c;再创建Misk子目录&…

DevNow x Notion

前言 Notion 应该是目前用户量比较大的一个在线笔记软件&#xff0c;它的文档系统也非常完善&#xff0c;支持多种文档格式&#xff0c;如 Markdown、富文本、表格、公式等。 早期我也用过一段时间&#xff0c;后来有点不习惯&#xff0c;就换到了 Obsidian &#xff0c;但是…

hCaptcha 图像识别 API 对接说明

hCaptcha 图像识别 API 对接说明 本文将介绍一种 hCaptcha 图像识别 API 对接说明&#xff0c;它可以通过用户输入识别的内容和 hCaptcha验证码图像&#xff0c;最后返回需要点击的小图像的坐标&#xff0c;完成验证。 接下来介绍下 hCaptcha 图像识别 API 的对接说明。 申请…

Move AI技术浅析(二):输入与预处理

一、视频输入模块 1.1 视频输入步骤详解 视频输入模块的主要任务是接收视频数据&#xff0c;并将其转换为后续处理所需的格式。具体步骤&#xff1a; 1.1.1 视频读取 步骤&#xff1a;从文件系统、网络流或摄像头读取视频数据。技术&#xff1a;使用 OpenCV 的 cv2.VideoCa…

Jenkins 任意文件读取(CVE-2024-23897)修复及复现

Jenkins任意文件读取漏洞CVE-2024-23897修复及复现 漏洞详情影响范围漏洞复现修复建议 Jenkins是一个开源软件项目&#xff0c;是基于Java开发的一种持续集成工具&#xff0c;用于监控持续重复的工作&#xff0c;旨在提供一个开放易用的软件平台&#xff0c;使软件项目可以进行…

远程控制macOS一直卡在100%,能连接上了却只显示了壁纸?

前言 前段时间有个朋友过来咨询关于Windows使用第三方远程软件&#xff08;向日葵、Todesk等&#xff09;远程连接控制macOS系统&#xff0c;但出现了一些奇奇怪怪的问题。 比如在连接的时候&#xff0c;一直卡在100%连接&#xff0c;对方的电脑却已经显示已经被控制的状态。…

Datawhale AI 冬令营学习笔记-零编程基础制作井字棋小游戏

井字棋小游戏是通过豆包MarsCode实现的&#xff0c;没有改动任何的代码&#xff0c;全部是通过对话让AI进行优化和改进。 开始进入正题&#xff1a;进入豆包MarsCode在线IDE&#xff0c;直接点击上方蓝字&#xff0c;或复制链接打开: 豆包 MarsCode - 编程助手。 IDE界面&…

利用Circuit JS1再学学电子方面的知识(硬件)

1 电阻器 1.1 电阻并联 每个电阻电压相同&#xff0c;总电流等于各支路电流之和。 并联电阻值 R 1/(1/R11/R2);R约等于90.9 电阻并联后的阻值比最小的一个电阻值都小。 1.2 电阻串联 电阻串联的阻值为各电阻阻值相加。 RR1R2&#xff0c;串联涉及电阻分压。 一般在开关处…

webrtc获取IceCandidate流程

在WebRTC(Web Real-Time Communication)中,ICECandidate是一个关键概念,它用于描述在建立点对点(P2P)连接时可以考虑的潜在通信端点。以下是关于WebRTC中ICECandidate的详细解释: 一、ICECandidate的定义 ICECandidate对象通常包含以下关键属性: foundation:用于唯一…

注意力机制详解

一、引言 注意力机制&#xff08;Attention Mechanism&#xff09;源于对人类视觉的研究&#xff0c;是一种在深度学习模型中模拟人类注意力的机制。它允许模型在处理信息时能够聚焦于当前任务最相关的部分&#xff0c;从而提高模型的性能和泛化能力。本文将从注意力机制的起源…

重温设计模式--单例模式

文章目录 单例模式&#xff08;Singleton Pattern&#xff09;概述单例模式的实现方式及代码示例1. 饿汉式单例&#xff08;在程序启动时就创建实例&#xff09;2. 懒汉式单例&#xff08;在第一次使用时才创建实例&#xff09; 单例模式的注意事项应用场景 C代码懒汉模式-经典…