前言

近日心血来潮想做一个开源项目,目标是做一款可以适配多端、功能完备的模板工程,包含后台管理系统和前台系统,开发者基于此项目进行裁剪和扩展来完成自己的功能开发。本项目为前后端分离开发,后端基于Java21SpringBoot3开发,后端使用Spring SecurityJWTSpring Data JPA等技术栈,前端提供了vueangularreactuniapp微信小程序等多种脚手架工程。

项目地址:https://gitee.com/breezefaith/fast-alden

在前后端分离的项目开发过程中,我们通常会对数据返回格式进行统一的处理,这样可以方便前端人员取数据,后端发生异常时同样会使用此格式将异常信息返回给前端。本文将介绍在SpringBoot项目中如何实现统一异常处理。

实现步骤

定义统一响应对象类

/**
* 响应结果类
*
* @param <T> 任意类型
*/
@Data
public class ResponseResult<T> {
/**
* 响应状态码,200是正常,非200表示异常
*/
private int status;
/**
* 异常编号
*/
private String errorCode;
/**
* 异常信息
*/
private String message;
/**
* 响应数据
*/
private T data; public static <T> ResponseResult<T> success() {
return success(HttpServletResponse.SC_OK, null, null);
} public static <T> ResponseResult<T> success(T data) {
return success(HttpServletResponse.SC_OK, null, data);
} public static <T> ResponseResult<T> fail(String message) {
return fail(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, null, message, null);
} public static <T> ResponseResult<T> fail(String errorCode, String message) {
return fail(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, errorCode, message, null);
} public static <T> ResponseResult<T> success(int status, String message, T data) {
ResponseResult<T> r = new ResponseResult<>();
r.setStatus(status);
r.setMessage(message);
r.setData(data); return r;
} public static <T> ResponseResult<T> fail(int status, String errorCode, String message) {
return fail(status, errorCode, message, null);
} public static <T> ResponseResult<T> fail(int status, String errorCode, String message, T data) {
ResponseResult<T> r = new ResponseResult<>();
r.setStatus(status);
r.setErrorCode(errorCode);
r.setMessage(message);
r.setData(data);
return r;
} }

定义业务异常枚举接口和实现

通常一个系统中的自定义业务异常是可穷举的,可以考虑通过定义枚举的方式来列举所有的业务异常。

首先我们来定义一个异常信息枚举的基类接口。

public interface IBizExceptionEnum {
String getCode(); String getMessage();
}

再给出一个常用的异常信息的枚举类,如果有其他业务模块的异常信息,同样可以通过实现IBizExceptionEnum接口来进行定义。

@Getter
public enum BizExceptionEnum implements IBizExceptionEnum {
ENTITY_IS_NULL("Base_Entity_Exception_0001", "实体为空"),
ENTITY_ID_IS_NULL("Base_Entity_Exception_0002", "实体id字段为空"),
ENTITY_ID_IS_DUPLCATED("Base_Entity_Exception_0003", "实体id字段%s重复"); private final String code;
private final String message; BizExceptionEnum(String code, String message) {
this.code = code;
this.message = message;
}
}

定义业务异常基类

业务异常基类BizException继承自RuntimeException,代码中主动抛出的异常建议都包装为该类的实例。

/**
* 业务异常基类,支持参数化的异常信息
*/
@Getter
@Setter
public class BizException extends RuntimeException {
private String code;
private Object[] args; public BizException() {
super();
} public BizException(String message) {
super(message);
} public BizException(Throwable cause) {
super(cause);
} public BizException(String message, Throwable cause) {
super(message, cause);
} public BizException(Throwable cause, String code, String message, Object... args) {
super(message, cause);
this.code = code;
this.args = args;
} public BizException(String code, String message, Object... args) {
super(message);
this.code = code;
this.args = args;
} public BizException(IBizExceptionEnum exceptionEnum, Object... args) {
this(exceptionEnum.getCode(), exceptionEnum.getMessage(), args);
} public BizException(Throwable cause, IBizExceptionEnum exceptionEnum, Object... args) {
this(cause, exceptionEnum.getCode(), exceptionEnum.getMessage(), args);
} @Override
public String getMessage() {
if (code != null) {
if (args != null && args.length > 0) {
return String.format(super.getMessage(), args);
}
}
return super.getMessage();
}
}

定义全局异常处理切面

本步骤需要使用@RestControllerAdvice注解,它是一个组合注解,由@ControllerAdvice@ResponseBody组成,而@ControllerAdvice继承了@Component,因此@RestControllerAdvice本质上是个Component,用于定义@ExceptionHandler@InitBinder@ModelAttribute方法,适用于所有使用@RequestMapping方法。

还要用到@ExceptionHandler注解,可以认为它是一个异常拦截器,它采用“就近原则”,存在多个满足条件的异常处理器时会选择最接近的一个来使用。它本质上就是使用Spring AOP定义的一个切面,在系统抛出异常后执行。

具体实现代码如下:

/**
* 全局异常处理切面
*/
@RestControllerAdvice
public class GlobalExceptionHandlerAdvice {
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandlerAdvice.class); @ExceptionHandler({BizException.class})
public ResponseResult<Object> handleBizException(BizException e, HttpServletRequest request, HttpServletResponse response) {
log.error(e.getCode() + ": " + e.getMessage(), e);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return ResponseResult.fail(e.getCode(), e.getMessage());
} @ExceptionHandler({RuntimeException.class, Exception.class})
public ResponseResult<Object> handleRuntimeException(Exception e, HttpServletRequest request, HttpServletResponse response) {
log.error(e.getMessage(), e);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return ResponseResult.fail(e.getMessage());
}
}

上述代码会对系统中抛出的BizExceptionRuntimeExceptionException对象进行处理,把异常包装为ResponseResult对象后将异常编号和异常信息返回给前端。

测试和验证

下面我们就可以定义一个Controller类来进行简单的测试。

@RestController
@RequestMapping("/demo")
public class DemoController {
@GetMapping("/method1")
public ResponseResult<Integer> method1() {
throw new BizException(BizExceptionEnum.ENTITY_IS_NULL);
} @GetMapping("/method2")
public void method2() {
throw new BizException(BizExceptionEnum.ENTITY_ID_IS_NULL);
} @GetMapping(value = "/method3")
public String method3() {
throw new BizException(BizExceptionEnum.ENTITY_ID_IS_DUPLCATED, "1");
} @GetMapping(value = "/method4")
public String method4() {
// 抛出ArithmeticException异常
return String.valueOf(1 / 0);
}
}

总结

本文介绍了如何在SpringBoot项目中实现统一异常处理,如有错误,还望批评指正。

在后续实践中我也是及时更新自己的学习心得和经验总结,希望与诸位看官一起进步。

SpringBoot实现统一异常处理的更多相关文章

  1. Springboot项目统一异常处理

    Springboot项目统一异常处理 一.接口返回值封装 1. 定义Result对象,作为通用返回结果封装 2. 定义CodeMsg对象,作为通用状态码和消息封装 二.定义全局异常类 三.定义异常处理 ...

  2. SpringBoot之统一异常处理

    异常,不仅仅是程序运行状态的描述,还可以使得代码编写更加的规范   1.自定义异常:FieldValueInvalidException package com.geniuses.sewage_zer ...

  3. SpringBoot 统一异常处理

    统一异常处理: @ControllerAdvice public class GlobalExceptionHandler { private Logger logger = LoggerFactor ...

  4. 【异常处理】Springboot对Controller层方法进行统一异常处理

    Controller层方法,进行统一异常处理 提供两种不同的方案,如下: 方案1:使用 @@ControllerAdvice (或@RestControllerAdvice), @ExceptionH ...

  5. spring 或 springboot统一异常处理

    spring 或 springboot统一异常处理https://blog.csdn.net/xzmeasy/article/details/76150370 一,本文介绍spring MVC的自定义 ...

  6. 配置springboot在访问404时自定义返回结果以及统一异常处理

    在搭建项目框架的时候用的是springboot,想统一处理异常,但是发现404的错误总是捕捉不到,总是返回的是springBoot自带的错误结果信息. 如下是springBoot自带的错误结果信息: ...

  7. springboot返回统一接口与统一异常处理

    springboot返回统一接口与统一异常处理 编写人员:yls 编写时间:2019-9-19 0001-springboot返回统一接口与统一异常处理 简介 创建统一的返回格式 Result 封装统 ...

  8. SpringBoot小技巧:统一异常处理

    SpringBoot小技巧:统一异常处理 情景描述 对于接口的定义,我们通常会有一个固定的格式,比如: 但是调用方在请求我们的API时把接口地址写错了,就会得到一个404错误,且不同于我们定义的数据格 ...

  9. springboot中web应用的统一异常处理

    在web应用中,请求处理过程中发生异常是非常常见的情况.springboot为我们提供了一个默认的映射:/error,当处理中抛出异常之后,会转到该请求中处理,并且该请求有一个全局的错误页面用来展示异 ...

  10. SpringBoot统一异常处理后TX-LCN分布式事务无法捕获异常进行回滚

    通常我们使用SpringBoot都会进行统一异常处理,例如写一个BaseController,在BaseController里进行统一异常处理,然后其他的Controller都继承BaseContro ...

随机推荐

  1. Python pydot与graphviz库在Anaconda环境的配置

      本文介绍在Anaconda环境中,安装Python语言pydot与graphviz两个模块的方法.   最近进行随机森林(RF)的树的可视化操作,需要用到pydot与graphviz模块:因此记录 ...

  2. Java字节码与反射机制

    字节码(Byte Code)是Java语言跨平台特性的重要保障,也是反射机制的重要基础.通过反射机制,我们不仅能看到一个类的属性和方法,还能在一个类里调用另外一个类的方法,但前提是我们得有相关类的字节 ...

  3. excel常用函数整理(可检索)

    目录: 一.数字函数 1.1 sum 1.2 sumif 1.3 sumifs 1.4 sumproduct 1.5 abs二.统计函数 2.1 count 2.2 counta 2.3 counti ...

  4. java项目实战-mybatis-基本用法02接口绑定实现类-day23

    目录 1. 复习 什么是接口 什么是类? 2. mybatis接口绑定实现类 来实现查询 4. 参数的传递 5 插入数据 1. 复习 什么是接口 什么是类? public interface Spea ...

  5. Java应用架构演变史

    垂直应用架构 也叫单体架构.以 MVC 的垂直架构举例,MVC 架构通常分为 3 层,展示层.控制层.模型层.通常基于 MVC 架构开发的应用代码会打成一个 war 包,部署在 Tomcat 等 We ...

  6. mysql 复制表结构创建表及复制表结构与数据创建表

    本文为博主原创,未经允许不得转载: 在开发过程或项目维护发布过程中,经常需要复制建表及复制表数据建表等,整理了以下四种常用的 mysql 命令. 1.  create like 复制表结构(包含索引, ...

  7. 基于taro搭建小程序多项目框架

    前言 为什么需要这样一个框架,以及这个框架带来的好处是什么? 从字面意思上理解:该框架可以用来同时管理多个小程序,并且可以抽离公用组件或业务逻辑供各个小程序使用.当你工作中面临这种同时维护多个小程序的 ...

  8. springboot启动流程 (2) 组件扫描

    SpringBoot的组件扫描是基于Spring @ComponentScan注解实现的,该注解使用basePackages和basePackageClasses配置扫描的包,如果未配置这两个参数,S ...

  9. spring——DI_依赖注入

    Spring的注入方式 Dependency Injection 概念 依赖注入(Dependency Injection) 依赖:指Bean对象的创建依赖于容器,Bean对象的依赖资源 注入:指Be ...

  10. [转帖]一文深度讲解JVM 内存分析工具 MAT及实践(建议收藏)

    https://juejin.cn/post/6911624328472133646 1. 前言 熟练掌握 MAT 是 Java 高手的必备能力,但实践时大家往往需面对众多功能,眼花缭乱不知如何下手, ...