springboot2.x通用异常捕获

news2024/11/18 18:32:33

文章目录

    • 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 ~ 10100
	USER_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.coloradmin.cn/o/1150303.html

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

相关文章

解决由于找不到mfc140u.dll无法继续执行此代码问题的4个方法

mfc140u.dll是Microsoft Foundation Class&#xff08;微软基础类库&#xff09;中的一个动态链接库文件&#xff0c;它包含了许多用于实现Windows应用程序的基本功能。当我们在编写或运行基于MFC的程序时&#xff0c;如果系统中缺少这个文件&#xff0c;就会出现“找不到mfc14…

电脑端微信多开方式

方法一&#xff1a;电脑微信分身法 大家只需要先按住键盘上的enter键不放&#xff0c;然后用鼠标点击电脑上的微信即可&#xff0c;这里的微信分身个数不限&#xff0c;大家根据自己的实际需要进行点击即可&#xff0c;点击了几次就可以开出几个微信。 注意&#xff1a;前提是…

vscode debug skills

1) VSCode 调试 C/C 代码时&#xff0c;如何显示动态分配的指针数组。 创建一个动态分配的一维数组: int n 10; int *array (int *)malloc(n*sizeof(int)); memset(array, 1, n*sizeof(int)); 如果直接 Debug 时查看 array 指针&#xff0c;并不能看到数组所有的值。 查看…

uniapp 提供了一种运行于视图层的专属js,微信叫做wxs

小程序里有几个谜一样的存在&#xff0c;微信的WXS、支付宝的SJS、百度的Filter。 很多开发者都不明白为什么要造这种语言脚本的轮子出来&#xff0c;甚至很多开发者根本不知道它们的存在。 其实几大小程序平台创造它们&#xff0c;都是为了解决性能问题&#xff0c;但不得不…

Spring Boot中配置默认的HikariCP数据源

在了解HiKari之前&#xff0c;我们需要先了解关于数据访问的相关概念&#xff1a; 什么是JDBC JDBC&#xff08;Java Database Connectivity&#xff09;是Java编程语言用于与数据库进行交互的标准API。它提供了一组类和接口&#xff0c;用于执行数据库操作&#xff0c;如连接…

six是6,seven是7,“at sixes and sevens”可不是6、7点钟的意思!柯桥商务英语学校

暴露年纪的时候到了。 你有没有听过一首风靡全球的经典英文歌曲 ——Don’t Cry For Me Argentina 其中一段歌词是这样的&#xff1a; It wont be easy. Youll think it strange 我细诉心底话&#xff0c;大家都会惊讶 When I try to explain how I feel. That I still ne…

reese84

网址:https://beta.makeabooking.flyscoot.com/ 这个基本上会在航空网站上出现&#xff0c;国内的我也没见过&#xff0c;然后这个是我很早很早之前的老友分享的&#xff0c;然后昨天花时间去看了一下&#xff0c;之前经常听其他大佬说&#xff0c;但是我也出来没遇见过。 感觉…

14技术太卷我学APEX-RESTful服务全自动Autorest

Oracle REST 数据服务 (ORDS) 的 AutoREST 功能&#xff0c;该功能允许您将表和视图等自动公开为 RESTful Web 服务。这个太好可不用自己费劲巴拉的定义RESTful数据服务了。 1 先准备测试数据表 登录APEX现在开发平台 [https://apex.oracle.com/pls/apex/r/apex/workspace-si…

无线渗透|Wi-Fi渗透思路

对于WPA2 WPA3的一些渗透思路 0x00 进行渗透时需知晓的基础知识 1.WPA2:是WPA的升级版&#xff0c;是针对保护无线网络安全而设计的无线网络保护系统&#xff0c;引入了PSK&#xff08;预共享密钥模式&#xff09;秘钥&#xff0c;加强了WPA的不足之处&#xff0c;但是因为使…

day45

今日内容 标签的分类 1.单标签 imr br hr <img /> 2.双标签 a h p div <a> </a> 3.按照标签属性分类 &#xff08;1&#xff09;块儿标签 &#xff08;自己独占一行&#xff09; h1-h6 p div &#xff08;2&#xff09;行内(内联)标签 &a…

探求flutter全栈开发

显示一种网络图片 import package:flutter/material.dart; main(){runApp(MaterialApp(theme: ThemeData.dark(),home:Home(),));}class Home extends StatelessWidget{overrideWidget build(BuildContext context) {// TODO: implement buildreturn Scaffold(appBar:AppBar(t…

H5随机短视频滑动版带打赏源码V1.3

全新H5滑动屏幕观看&#xff0c;可封装APP软件或嵌入式观看&#xff0c;网站引流必备源码&#xff01; 数据来源抖音和快手官方短视频链接&#xff0c;无任何违规内容&#xff01; 可自行添加广告等等&#xff01; 手机端完美支持滑动屏幕观看&#xff08;向上或向右&#x…

隔离模块CC10-2405SF-E,嵌入式(MCU) STM32F207IGT7、SPC5742PK1AMLQ9R规格参数

一、CC10-2405SF-E 1.3至10W DC-DC转换器 CC系列DC-DC转换器具有高密度&#xff0c;输出电压为3.3V、5V、12V和15VDC&#xff0c;额定输出功率为3W至30W。CC模块采用通孔或SMT封装&#xff0c;带或不带屏蔽金属外壳。这些器件适用于-40C至85C的扩展温度范围应用&#xff0c;具…

一文浅析Instagram网红经济为什么远远超出其他社媒平台

根据数据显示&#xff0c;网红营销市场规模在短短五年时间内从2016年的17亿美元增长至2022年的164亿美元&#xff0c;累计增速超过了712%。未来&#xff0c;有专家预计该市场预计将进一步增长&#xff0c;将在2023年突破210亿美元。这种惊人的增长趋势源于社交媒体的快速发展以…

Django实战项目-学习任务系统-定时任务管理

接着上期代码框架&#xff0c;开发第4个功能&#xff0c;定时任务管理&#xff0c;再增加一个学习定时任务表&#xff0c;主要用来设置周期重复性的学习任务&#xff0c;定时周期&#xff0c;定时时间&#xff0c;任务标题和内容&#xff0c;预计完成天数&#xff0c;奖励积分和…

PythonWEB

文章目录 前端简介1. 什么是网页2. 网页的组成3. 网页的优势4. 前端三剑客5. 编写步骤6. HTTP协议 HTML51. HTML介绍2. 元素3. 使用4. 基本结构解析5. 常用标签文本标签容器标签列表标签表格标签表单标签 对于文件数据的提交需要满足以下两个条件&#xff1a;6. 标签分类 前端简…

基于SpringBoot的体育馆管理系统

目录 前言 一、技术栈 二、系统功能介绍 管理员功能介绍 商品列表 场地信息管理 场地类型管理 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff…

精益制造的工具与方法有什么区别?ECRS工时分析软件的功能和价值

精益制造是一套价值创造系统&#xff0c;它强调在生产过程中减少浪费、提高效率和质量&#xff0c;从而实现持续改进和优化。在精益制造的理念下&#xff0c;企业需要运用一系列的工具和方法来提升生产管理水平。这些工具和方法不仅包括传统的精益工具&#xff0c;如5S、持续改…

Java自学者怎么写简历?

Java自学者怎么写简历&#xff1f; 首先&#xff0c;有技术实力的人绝对不会问这个问题。虽然你是自学的&#xff0c;但是一定要有项目&#xff01;没有项目都是空谈。最近很多小伙伴找我&#xff0c;说想要一些Java资料&#xff0c;然后我根据自己从业十年经验&#xff0c;熬夜…

使用 Sealos 一键部署 Kubernetes 集群

Sealos 是一款以 Kubernetes 为内核的云操作系统发行版&#xff0c;使用户能够像使用个人电脑一样简单地使用云。 与此同时&#xff0c;Sealos 还提供一套强大的工具&#xff0c;可以便利地管理整个 Kubernetes 集群的生命周期。 Sealos 不仅可以一键安装一个单节点的 Kubern…