springboot2.x使用@RestControllerAdvice实现通用异常捕获

文章目录

    • demo地址
    • 实现效果
    • 引入
    • 基础类准备
      • 1.通用枚举与错误状态枚举
      • 2.定义通用返回结果
      • 3.自定义业务异常
    • 统一异常捕获
    • 测试

demo地址

demo工程地址

实现效果

  • 当我们输入1时,正常的返回通用的响应结果
  • 当我们输入2时,抛出异常,被捕获然后返回通用的结果
  • 可以看到两者的数据结构都是完全一样的

java通用异常捕获效果展示

引入

很多时候,当一个javaweb项目在运行的过程中出现一些不可预值的错误时会抛出异常,例如下方我们在接口直接抛出一个运行时异常:

请添加图片描述
对应接口的响应就变成如下图所示:

请添加图片描述
这时的返回结果往往和我们与前端约定好的响应结果的数据结构出入很大,而且也不方便我们去排查错误,并且对用户体验也不好,这时就需要我们配置一个统一的异常捕获,对各种异常进行统一数据结构的返回,方便前端展示对应的错误,我们也可以在捕获到异常后进行对应的日志记录,方便后续排查。

基础类准备

1.通用枚举与错误状态枚举

我们首先需要和前端沟通好统一的返回结果的数据结构和一些常见的错误状态,这里我们使用一个错误状态枚举来展示业务内的一些报错,为了枚举更好的拓展性,这里我们先封装一个基础枚举类,如下:

  • 封装通用枚举的好处,可以参考我的这几个视频讲解:
  • 封装通用枚举1
  • 封装通用枚举2(封装选项生成)
  • 封装通用枚举3(按类型获取枚举选项接口)
/*** @Author: lzp* @description: 通用枚举* @Date: 2022/9/24*/
public interface BaseEnum<P> {/*** 获取标题*/String getTitle();/*** 获取值*/P getValue();/*** 通过value获取枚举对象* 2022-12-09日使用泛型优化此方法** @param enumClass 枚举的类对象* @param value     值* @return*/static <T extends BaseEnum> T valueOf(Class<T> enumClass, Object value) {if (value == null) {return null;}T[] enumConstants = enumClass.getEnumConstants();if (enumConstants == null) {return null;}for (T enumConstant : enumConstants) {if (value.equals(enumConstant.getValue())) {return enumConstant;}}return null;}}

接着,我们实现通用枚举接口,定义通用状态码枚举如下:

  • 这样可以把我们系统中可预知的异常全部定义在错误码枚举中
  • 我们可以给对应业务模块的错误码命名为指定范围内,例如用户相关的错误咱们控制在 10001 ~ 10100之间
import lombok.Getter;
import online.longzipeng.mywebdemo.enums.BaseEnum;/*** @Author: lzp* @Date:2023/10/30* @description: 通用错误状态码*/
@Getter
public enum ErrorCodeEnum implements BaseEnum<Integer> {// 通用错误状态码SUCCESS(0, "成功"),ERROR(-1, "失败"),// 用户相关异常  10001 ~ 10100USER_LOGIN_ERROR(1001,"账号或密码错误!"),;public final Integer value;public final String title;ErrorCodeEnum(Integer value, String title) {this.value = value;this.title = title;}}

2.定义通用返回结果

我们与前端约定好通用的返回结果的数据结构,例如都带有code,msg,data,分别表示该接口的响应状态码,错误消息,返回数据:

  • 为了通用防止任何数据类型,这里我们使用泛型来指定响应的data
  • 为了方便通用的返回,例如一般修改接口不需要返回数据,此时在咱们就可以指定调用静态方法 Result.success();
package online.longzipeng.mywebdemo.commen;import lombok.Data;
import online.longzipeng.mywebdemo.commen.exception.ErrorCodeEnum;import java.io.Serializable;/*** 通用响应** @author lzp*/
@Data
public class Result<T> implements Serializable {private static final long serialVersionUID = 1L;/*** 编码:0表示成功,其他值表示失败*/private int code = ErrorCodeEnum.SUCCESS.value;/*** 消息内容*/private String msg = ErrorCodeEnum.SUCCESS.title;/*** 响应数据*/private T data;public static <T> Result<T> error() {return generate(ErrorCodeEnum.ERROR.value, ErrorCodeEnum.ERROR.getTitle());}/*** 快速生成返回结果* @param code 状态码* @param msg 对应消息内容*/public static <T> Result<T> generate(int code, String msg) {Result<T> result = new Result();result.setCode(code);result.setMsg(msg);return result;}public static <T> Result<T> success() {return new Result<>();}public static <T> Result<T> success(T data) {Result<T> result = new Result<>();result.setData(data);return result;}}

3.自定义业务异常

因为运行时异常是一种特殊的异常,不需要我们显示的抛出和try catch处理,所以很适合用于做我们的自定义业务异常,然后我们希望业务出错了也统一返回Result的数据结构,所以咱们自定义的异常也需要包含 code和msg字段

package online.longzipeng.mywebdemo.commen.exception;import lombok.Data;/*** 通用异常处理*/
@Data
public class ServiceException extends RuntimeException {private static final long serialVersionUID = 1L;/*** 错误码*/private int code;/*** 错误信息*/private String msg;public ServiceException(int code) {this.code = code;}public ServiceException(int code, String msg) {this.code = code;}public ServiceException(String msg) {super(msg);this.code = ErrorCodeEnum.ERROR.value;this.msg = msg;}/*** 使用通用错误枚举快速创建异常*/public ServiceException(ErrorCodeEnum errorCodeEnum) {this.code = errorCodeEnum.getValue();this.msg =errorCodeEnum.getTitle();}
}

统一异常捕获

在springboot2.x中,咱们可以通过@ControllerAdvice注解与@ExceptionHandler注解来实现统一的异常捕获与处理,为了方便返回结果,这里我们使用@RestControllerAdvice注解返回JSON格式的响应,用于快速构建RESTful风格的程序。

如下:

  • 这里我们直接捕获到了自定义的业务异常,从中取出结果并返回Result对象
  • 捕获Exception异常,当发生不可预知的异常时,在此统一捕获,并打印错误日志
package online.longzipeng.mywebdemo.commen.exception;import online.longzipeng.mywebdemo.commen.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;/*** 通用异常处理器*/
@RestControllerAdvice
public class ServiceExceptionHandler {private Logger logger = LoggerFactory.getLogger(getClass());/*** 处理自定义异常*/@ExceptionHandler(ServiceException.class)public Result handleRenException(ServiceException e) {return Result.generate(e.getCode(),e.getMsg());}/*** 处理未知异常*/@ExceptionHandler(Exception.class)public Result handleException(Exception e) {logger.error(e.getMessage(), e);return Result.error();}
}

测试

我们创建一个用于测试的controller,并在其中手动抛出一个业务异常,如下:

package online.longzipeng.mywebdemo.controller;import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import online.longzipeng.mywebdemo.commen.Result;
import online.longzipeng.mywebdemo.commen.exception.ErrorCodeEnum;
import online.longzipeng.mywebdemo.commen.exception.ServiceException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;/*** @Author: lzp* @description:* @Date: 2023/10/30*/
@RestController
@RequestMapping("/test")
@Api(tags = "测试接口")
public class TestController {@GetMapping("/error")@ApiOperation("测试异常抛出")public Result<String> testError(@RequestParam @ApiParam("1 正常 2抛出错误") Integer type) {if (type == 2) {throw new ServiceException(ErrorCodeEnum.USER_LOGIN_ERROR);}return Result.success("你好呀~");}}

显示结果如下:

  • 当我们输入1时,正常的返回通用的响应结果
  • 当我们输入2时,返回对应的错误
  • 可以看到两者的数据结构都是完全一样的

java通用异常捕获效果展示

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

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

相关文章

Docker学习——①

文章目录 1、什么是虚拟化、容器化&#xff1f;2、为什么要虚拟化、容器化&#xff1f;3、虚拟化实现方式3.1 应用程序执行环境分层3.2 虚拟化常见类别3.3 常见虚拟化实现3.3.1 主机虚拟化(虚拟机)实现3.3.2 容器虚拟化实现3.3.3 空间隔离实战--基础知识3.3.4 PID 隔离3.3.5 Mo…

没有PDF密码,如何解密文件?

PDF文件有两种密码&#xff0c;一个打开密码、一个限制编辑密码&#xff0c;因为PDF文件设置了密码&#xff0c;那么打开、编辑PDF文件就会受到限制。想要解密&#xff0c;我们需要输入正确的密码&#xff0c;但是有时候我们可能会出现忘记密码的情况&#xff0c;或者网上下载P…

Linux-----nginx的简介,nginx搭载负载均衡以及nginx部署前后端分离项目

目录 nginx的简介 是什么 nginx的特点以及功能 Nginx负载均衡 下载 安装 负载均衡 nginx的简介 是什么 Nginx是一个高性能的开源Web服务器和反向代理服务器。它的设计目标是为了解决C10k问题&#xff0c;即在同一时间内支持上万个并发连接。 Nginx采用事件驱动的异…

听GPT 讲Rust源代码--library/std(12)

题图来自 Decoding Rust: Everything You Need to Know About the Programming Language[1] File: rust/library/std/src/os/watchos/mod.rs 该文件&#xff08;rust/library/std/src/os/watchos/mod.rs&#xff09;的作用是为Rust标准库提供支持WatchOS操作系统的特定功能。 W…

C语言实现俄罗斯方块游戏

文章目录 1 前言2 游戏截图3 源代码 1 前言 本文介绍的是我空闲时间用C语言写的一个俄罗斯方块游戏&#xff0c;整个程序只有一个文件&#xff0c;实现了基本的游戏功能&#xff0c;但还是有些缺陷&#xff0c;希望有心之士能够继续完善&#xff0c;感谢各位&#xff01; 2 游戏…

【大数据基础平台】星环TDH社区集群版本部署

&#x1f984; 个人主页——&#x1f390;开着拖拉机回家_大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341;&#x1fa81;&#x1f341;&#x1fa81;&#x1f341;&#x1fa81;&#x1f341; &#x1fa81;&#x1f341;&#x1fa81;&#x1f…

Spring-Spring 之底层架构核心概念解析

BeanDefinition BeanDefinition表示Bean定义&#xff0c;BeanDefinition中存在很多属性用来描述一个Bean的特点。比如&#xff1a; class&#xff0c;表示Bean类型scope&#xff0c;表示Bean作用域&#xff0c;单例或原型等lazyInit&#xff1a;表示Bean是否是懒加载initMeth…

【云备份|| 日志 day3】服务端配置信息模块

云备份day3 使用文件配置加载一些程序的运行关键信息可以让程序的运行更加灵活&#xff0c;且当需要修改部分内容时&#xff0c;不需要在代码上修改&#xff0c;只需要修改配置文件&#xff0c;然后重启服务器即可。 配置信息 热点判断时间文件下载URL前缀路径压缩包后缀名称…

模电学习路径

交流通路实质 列出电路方程1&#xff0c;方程1对时刻t做微分 所得方程1‘ 即为 交流通路 方程1对时刻t做微分&#xff1a;两个不同时刻的方程1相减&#xff0c;并 令两时刻差为 无穷小 微分 改成 差 模电学习路径&#xff1a; 理论 《电路原理》清华大学 于歆杰 朱桂萍 陆文…

学习 SpringMVC 必备的 4 大知识点

一、什么是 SpringMVC 前面我们了解了Spring、SpringBoot&#xff0c;那么 Spring MVC 又是什么呢&#xff1f;关于三者&#xff0c;我们可以这样理解&#xff1a;Spring MVC 是 Spring 框架的核心模块&#xff0c;而 Spring Boot 是 Spring 的脚手架。 Spring MVC 又称作 Sp…

【特殊矩阵的压缩存储】

文章目录 特殊矩阵的压缩存储特殊的矩阵 特殊矩阵的压缩存储 矩阵&#xff1a;一个由m x n个元素排成的m行n列的表。 矩阵的常规存储&#xff1a; 将矩阵描述为一个二维数组。 矩阵的常规存储的特点&#xff1a; 可以将元素进行随机存取&#xff1b; 矩阵运算非常简单&#xf…

linux查看文件夹使用情况以及查看文件大小

1、ls ls 命令是 Linux 中最常用的文件和目录列表命令之一。它可以显示文件的各种属性&#xff0c;包括文件大小。 ls -l <文件名>上述命令会显示文件的详细信息&#xff0c;其中包括文件的大小。文件大小以字节为单位显示&#xff0c;并且在输出中的第 5 列。4096 表示…

我做云原生的那几年

背景介绍 在2020年6月&#xff0c;我加入了一家拥有超过500人的企业。彼时&#xff0c;前端团队人数众多&#xff0c;有二三十名成员。在这样的大团队中&#xff0c;每个人都要寻找自己的独特之处和核心竞争力。否则&#xff0c;你可能会沉没于常规的增删改查工作中&#xff0…

【C++】C++11【下】lambda表达式|thread线程库

目录 1、lambda表达式 1.1 lambda表达式的引入 1.2 lambda表达式的语法 1.3 lambda表达式的原理 2、线程库 2.1thread类的介绍 2.2 线程函数参数 2.3 原子性操作库(atomic) 2.4 使用场景 应用场景1&#xff1a; 应用场景2: 应用场景3&#xff1a; 应用场景4&#xf…

在Qt中解决opencv的putText函数无法绘制中文的一种解决方法

文章目录 1.问题2.查阅资料3.解决办法 1.问题 在opencv中&#xff0c;假如直接使用putText绘制中文&#xff0c;会在图像上出现问号&#xff0c;如下图所示&#xff1a; 2.查阅资料 查了一些资料&#xff0c;说想要解决这个问题&#xff0c;需要用到freetype库或者用opencv…

Java--多线程--Thread类+Runnable接口

1.多进程与多线程 1.1多进程&#xff1a; 一个进程是一个包含自身地址的程序&#xff0c;每个独立执行的程序都称为进程&#xff0c;也就是正在执行的程序&#xff0c;系统可以分配给每个进程一段有限的使用CPU的时间&#xff08;CPU时间片&#xff09;&#xff0c;CPU在这个时…

Django实战项目-学习任务系统-查询列表分页显示

接着上期代码框架&#xff0c;6个主要功能基本实现&#xff0c;剩下的就是细节点的完善优化了。 接着优化查询列表分页显示功能&#xff0c;有很多菜单功能都有查询列表显示页面情况&#xff0c;如果数据量多&#xff0c;不分页显示的话&#xff0c;页面展示效果就不太好。 本…

pytorch 笔记:GRU

1 介绍 对于输入序列中的每个元素&#xff0c;每一层都计算以下函数&#xff1a; ht​ 是t时刻 的隐藏状态xt​ 是t时刻 的输入ht−1​ 是 t-1时刻 同层的隐藏状态或 0时刻 的初始隐藏状态rt​,zt​,nt​ 分别是重置门、更新门和新门。σ 是 sigmoid 函数∗ 是 Hadamard 乘积。…

OpenCV 笔记(4):图像的算术运算、逻辑运算

Part11. 图像的算术运算 图像的本质是一个矩阵&#xff0c;所以可以对它进行一些常见的算术运算&#xff0c;例如加、减、乘、除、平方根、对数、绝对值等等。除此之外&#xff0c;还可以对图像进行逻辑运算和几何变换。 我们先从简单的图像加、减、逻辑运算开始介绍。后续会有…

【Git企业开发】第四节.Git的分支管理策略和bug分支

文章目录 前言一、Git的分支管理策略 1.1 Fast forward 模式和--no-ff 模式 1.2 企业分支管理策略二、bug分支三、删除临时分支四、总结总结 前言 一、Git的分支管理策略 1.1 Fast forward 模式和--no-ff 模式 通常合并分支时&#xff0c;如果可能&#xff0c;Git 会…