异常统一处理:BusinessException(自定义业务异常)

一、引言

本篇内容是“异常统一处理”系列文章的重要组成部分,主要聚焦于对 BusinessException 的原理解析与异常处理机制,并给出测试案例。

  • 关于 全局异常统一处理 的原理和完整实现逻辑,请参考文章:
    《SpringBoot 全局异常统一处理(AOP):@RestControllerAdvice + @ExceptionHandler + @ResponseStatus》
  • 本文仅详细解析 BusinessException 的异常处理;其他类型异常的原理和处理方法,请参阅本文所在专栏内的其他文章。

二、业务异常原理

在Java企业级应用开发中,BusinessException 是一种常见的自定义异常类型,它通常继承自 java.lang.RuntimeException 类。这种异常专门用于表示业务逻辑层( BLL )出现的错误或不符合预期的情况,这些情况并不属于系统内部错误,但会导致当前业务流程无法正常完成。

由各种业务规则导致的异常情况,与系统级别的异常(如 IOException、NullPointerException等)不同,它们是业务逻辑上的错误,例如用户输入非法(如登录时的用户名密码错误)、订单状态非法操作、库存不足无法完成购买等情况。

设计 BusinessException 的主要目的是为了统一处理业务相关的错误,并方便异常传播时携带特定的业务上下文信息,如错误码、错误消息等。通过抛出 BusinessException,开发者可以清晰地区分并优雅地处理那些由应用程序业务规则违反导致的问题,而不是因编程错误或系统故障引起的异常。

在实际使用中,当业务执行过程中出现错误时(如用户输入非法、资源不足、权限不够等情况),可抛出此异常,并附带相应的错误码和详细错误信息,这样上层服务或者全局异常处理器就能根据异常类型和错误码来采取相应的恢复措施,比如记录日志、向客户端返回友好的提示信息以及进行事务回滚等操作。

三、业务异常代码

BusinessException

package com.example.core.model;import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;/*** 业务异常*/
@Getter
@Schema(name = "业务异常", description = "业务异常")
public class BusinessException extends RuntimeException {@Schema(description = "用户提示", example = "操作成功!")private final String userMessage;/*** 错误码<br>* 调用成功时,为 null。<br>* 示例:10001*/@Schema(description = "错误码")private final String errorCode;/*** 错误信息<br>* 调用成功时,为 null。<br>* 示例:"验证码无效"*/@Schema(description = "错误信息")private final String errorMessage;public BusinessException(ErrorEnum errorEnum) {super(String.format("错误码:[%s],错误信息:[%s],用户提示:[%s]", errorEnum.name(), errorEnum.getMessage(), errorEnum.getMessage()));this.userMessage = errorEnum.getMessage();this.errorCode = errorEnum.name();this.errorMessage = errorEnum.getMessage();}public BusinessException(String userMessage, String errorCode, String errorMessage) {super(String.format("错误码:[%s],错误信息:[%s],用户提示:[%s]", errorCode, errorMessage, userMessage));this.userMessage = userMessage;this.errorCode = errorCode;this.errorMessage = errorMessage;}}

ErrorEnum

下文为错误枚举的代码,本代码仅为示例,具体的错误枚举类型,应该按照公司的开发标准制定。

package com.example.core.model;import lombok.AllArgsConstructor;
import lombok.Getter;/*** 错误枚举*/
@Getter
@AllArgsConstructor
public enum ErrorEnum {A0001("用户端错误 "), // 一级宏观错误码// ------------------------------------------------------------------------------- //A0100("用户注册错误"), // 二级宏观错误码A0101("用户未同意隐私协议"),A0102("注册国家或地区受限"),A0110("用户名校验失败"),A0111("用户名已存在"),A0112("用户名包含敏感词"),A0113("用户名包含特殊字符"),// ------------------------------------------------------------------------------- //A0200("用户登录异常"), // 二级宏观错误码A0201("用户账户不存在"),A0202("用户账户被冻结"),A0203("用户账户已作废"),A0210("用户密码错误"),A0211("用户输入密码错误次数超限"),// ------------------------------------------------------------------------------- //A0400("用户请求参数错误"), // 二级宏观错误码A0420("请求参数值超出允许的范围"),A0421("参数格式不匹配"),A0422("地址不在服务范"),A0423("时间不在服务范围"),A0424("金额超出限制"),A0425("数量超出限制"),A0426("请求批量处理总个数超出限制"),A0427("请求 JSON 解析失败");private final String message;}

四、异常处理代码

在Spring Boot应用中,我们可以通过使用@ExceptionHandler注解来捕获并处理BusinessException异常。

4.1 异常处理示意图

在这里插入图片描述

4.2 异常处理核心代码

package com.example.core.advice;import com.example.core.model.BusinessException;
import com.example.core.model.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.HandlerMethod;/*** 全局异常处理器*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {/*** 业务异常处理*/@ExceptionHandler@ResponseStatus(HttpStatus.BAD_REQUEST)public Result<Void> handle(BusinessException e, HandlerMethod handlerMethod) {// BusinessException(自定义业务异常)的处理逻辑,比如:记录日志等逻辑。return Result.fail(e.getUserMessage(), e.getErrorCode(), e.getErrorMessage());}}

上述代码中,当出现BusinessException异常时,系统将返回一个状态码为400(Bad Request)的结果,并附带具体的错误信息。

五、测试案例

5.1 测试代码

    @GetMapping("business_exception")@Operation(summary = "业务异常", description = "测试 “业务异常”:直接将业务异常抛出,由 “异常统一处理” 模块来进行处理,将错误信息返回给前端。")public void throwBusinessException() {throw new BusinessException(ErrorEnum.A0210);}

5.2 未处理异常时的报错

请求响应

在这里插入图片描述

控制台的错误日志

在这里插入图片描述

5.3 已处理异常时的响应

在这里插入图片描述

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

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

相关文章

云性能测试方法:优化应用性能的关键步骤

随着云计算的普及和应用程序的不断发展&#xff0c;对于云平台上应用程序性能的测试变得愈发重要。云性能测试方法是评估应用程序在云环境中的性能表现并识别改进机会的关键步骤之一。在本文中&#xff0c;我们将探讨云性能测试的方法和步骤&#xff0c;以帮助开发人员和测试人…

挑战杯 基于人工智能的图像分类算法研究与实现 - 深度学习卷积神经网络图像分类

文章目录 0 简介1 常用的分类网络介绍1.1 CNN1.2 VGG1.3 GoogleNet 2 图像分类部分代码实现2.1 环境依赖2.2 需要导入的包2.3 参数设置(路径&#xff0c;图像尺寸&#xff0c;数据集分割比例)2.4 从preprocessedFolder读取图片并返回numpy格式(便于在神经网络中训练)2.5 数据预…

使用Templ进行Go模板化

使用Templ在Go项目中高效生成动态内容的指南 动态内容生成是Web开发的一个基本方面。无论您是在构建网站、Web应用程序还是API&#xff0c;根据数据和模板生成动态内容的能力都至关重要。在Go编程世界中&#xff0c;一个名为“Templ”的强大工具简化了这一过程。在这份全面的指…

Query Rewrite —— 基于大模型的query扩展改写,PRF(论文)

本文介绍了一篇典型的 PRF &#xff08;Pseudo-relevance feedback &#xff09;思路的论文&#xff0c;用于利用LLM来做query改写&#xff0c;提升召回率&#xff0c;召回效果。 论文地址&#xff1a;Large Language Models are Strong Zero-Shot Retriever 一、PRF的流程 如…

DPDK应该如何入门学习?

01 写在前面 我的读者当中应该有一部分人是做 DPDK 相关的&#xff0c;我自己虽然现在已经不做 DPDK 了&#xff0c;但对这块仍然有兴趣&#xff0c;今天这篇文章就来总结下 DPDK 的技术栈。注意&#xff1a;这篇文章是小白文&#xff0c;不适合大神哦。 文章从 DPDK 的产生背…

Qt应用软件【协议篇】MQTT官方源码编译安装

文章目录 QT官方代码选择对应的版本Qt Creator编译代码代码下载与编译安装mqtt命令行方式编译与安装代码示例QT官方代码 https://github.com/qt/qtmqtt/tree/5.15.2 选择对应的版本 我们可以在github上切换分支,切换到我们需要的版本上 Qt Creator编译代码 代码下载与编译…

【Godot4自学手册】第十五节碰撞层Layer和Mas的使用

上一节中我学习了敌人的攻击&#xff0c;这一节将学习一些碰撞的有关知识。开始今天的学习。 一、碰撞层基本使用知识 在Godot4中的Collsion属性中有Layer和Mask两个属性&#xff0c;用于定义碰撞过滤的重要参数&#xff0c;它们可以允许控制哪些物体可以与该节点进行碰撞检测…

亚信安慧AntDB数据库为实时流数据构筑坚实防线

在数字化浪潮中&#xff0c;企业对实时流数据处理的依赖日益增强。在此背景下&#xff0c;AntDB数据库应运而生&#xff0c;提供一种创新性解决方案&#xff0c;专注于解决实时流数据处理中的数据容灾和一致性问题。AntDB的设计理念是确保在处理高吞吐量的流数据时&#xff0c;…

SICTF Round#3 の WP

Misc 签到 SICTF{1f4ce05a-0fed-42dc-9510-6e76dff8ff53} Crypto [签到]Vigenere 附件内容&#xff1a; Gn taj xirly gf Fxgjuakd, oe igywnd mt tegbs mnrxxlrivywd sngearbsw wakksre. Bs kpimj gf tank, it bx gur bslenmngn th jfdetagur mt ceei yze Ugnled Lystel t…

使用JDBC操作数据库(IDEA编译器)

目录 JDBC的本质 ​ JDBC好处 JDBC操作MySQL数据库 1.创建工程导入驱动jar包 2.编写测试代码 ​相关问题 JDBC的本质 官方(sun公司) 定义的一套操作所有关系型数据库的规则&#xff0c;即接口各个数据库厂商去实现这套接口&#xff0c;提供数据库驱动jar包我们可以使用这…

国际阿里云,想要使用怎么解决支付问题

在国内我们很多时候都需要用到国际阿里云&#xff0c;在国际阿里云需要使用就需要支付&#xff0c;自己办理visa卡比较麻烦&#xff0c;那么我们可以使用虚拟卡&#xff0c;虚拟卡办理快速简单 真实测评使用Fomepay的5347支持国际阿里云的支付&#xff0c;秒下卡&#xff0c;不…

(HAL)STM32F407ZGT6——24-1 IIC实验

一、I2C简介 对比串口通信&#xff0c;从全双工转为半双工&#xff0c;有应答&#xff0c;一根线可以同时接多个模块&#xff0c;单片机可以选择与特定模块通信&#xff0c;并且不会相互干扰。 简而言之&#xff0c;I2C为同步、串行、半双工的通信总线协议。 1、为何SDA与SCL使…

使用Windbg动态调试目标程序去分析异常的两实战案例分享

目录 1、前言 2、案例1&#xff1a;程序退出时弹出报错提示框 2.1、问题说明 2.2、到系统应用程序日志中看系统有没有自动生成dump文件 2.3、将Windbg附加到目标程序上进行动态调试 3、案例2&#xff1a;程序在运行过程中弹出ASSERT断言提示框 3.1、问题说明 3.2、将Wi…

获取discord上自己创建的服务器的服务器ID、频道ID以及discord的登录token(用于第三方登录)

在服务器图标上右键点击-》复制服务器ID 在频道上右键点击-》复制频道ID F12->手机模式-》application-》local storage-》填写过滤条件【token】 我开发的chatgpt网站&#xff1a; https://chat.xutongbao.top

25-k8s集群中-RBAC用户角色资源权限

一、RBAC概述 1&#xff0c;k8s集群的交互逻辑&#xff08;简单了解&#xff09; 我们通过k8s各组件架构&#xff0c;指导各个组件之间是使用https进行数据加密及交互的&#xff0c;那么同理&#xff0c;我们作为“使用”k8s的各种资源&#xff0c;也是通过https进行数据加密的…

爬虫基本库的使用(requests库的详细解析)

注&#xff1a;本文一共4万多字&#xff0c;希望读者能耐心读完&#xff01;&#xff01;&#xff01; 前面,我们了解了urllib库的基本用法&#xff08;爬虫基本库的使用(urllib库的详细解析)-CSDN博客&#xff09;。其中&#xff0c;确实又不方便的地方。例如处理网页验证…

Android TV遥控器探索,Android 桌面应用程序

Android TV 的遥控功能是通过红外遥控器或蓝牙遥控器来实现的。下面分别介绍这两种遥控器的工作原理&#xff1a; 红外遥控器&#xff1a; 红外遥控器是最常见的 Android TV 遥控器类型之一。 红外遥控器通过发送红外信号来控制电视或机顶盒。每个按键都有一个特定的红外编码&…

【操作系统】12.文件系统是怎么管理的?

2.文件系统是怎么管理的&#xff1f; 2.1 文件系统的实现 2.1.1 文件系统层次结构 用户调用接口 文件目录系统 存取控制验证模块 逻辑文件系统与文件信息缓冲区 物理文件系统 辅助分配模块 设备管理程序模块 2.1.2 目录实现 线性列表 哈希表 2.1.3 文件实现 文件分配方式 连续…

基于ExtendSim的半导体制造工厂仿真

这是一个离散事件模型&#xff0c;使用ExtendeSim “高级资源管理&#xff08;ARM&#xff09;”功能来组织和分配资源。 此模型使用离散事件仿真和高级资源管理&#xff08;ARM&#xff09;功能。ARM是一个集成系统&#xff0c;用于组织资源、区分资源并在整个模型中分配资源。…

MySQL加锁策略详解

我们主要从三个方面来讨论这个问题&#xff1a; 啥时候加&#xff1f;如何加&#xff1f;什么时候该加什么时候不该加&#xff1f; 1、啥时候加 1.1 显式锁 MySQL 的加锁可以分为显式加锁和隐式加锁&#xff0c;显式加锁我们比较好识别的&#xff0c;因为他往往直接体现在 S…