SpringBoot全局异常处理

前言:在我们开发项目过程中,经常会主动的抛出异常提示,又或者程序出现了未知的异常而抛出的堆栈异常,此时,我们调用方会收到下面的信息(以swagger为例):

{
  "timestamp": "2020-05-18T14:21:05.180+0000",
  "status": 500,
  "error": "Internal Server Error",
  "message": "参数错误",
  "path": "/err2"
}

这种方式很不优雅,那么有没有一种优雅点的方式,来统一处理程序抛出的异常,并友好的返回给调用方呢?

下面将介绍,如何在项目中封装异常处理,使之统一而优雅。
以RESTful项目为例:

一、在RESTful架构中,一般使用JSON来和调用方交互,我们先来定义一个返回数据的包装类,当我们正常返回数据或者遇到异常返回提示信息,都使用统一的格式返回给调用方
@Setter
@Getter
public class RespResult<T> {
	private String code;
    private String msg;
    private T data;

    public RespResult(String code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public static <T> RespResult<T> ok() {
        return ok(null);
    }

    public static <T> RespResult<T> ok(T data) {
        return new RespResult<>("000", "success", data);
    }

    public static <T> RespResult<T> error() {
        return error("500", "unknown error", null);
    }

    public static <T> RespResult<T> error(String msg) {
        return error("500", msg, null);
    }

    public static <T> RespResult<T> error(String code, String msg, T data) {
        return new RespResult<>(code, msg, data);
    }
}
二、自定义一个异常信息枚举、一个异常类,并封装相应的异常包装类,可以更优雅的创建异常
/***************自定义异常信息枚举*********************/
@Getter
public enum ErrorCodeEnum {

    //自定义异常枚举
    ILLEGAL_PARAM("001", "参数错误");

    private String code;
    private String msg;

    ErrorCodeEnum(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }
}
/***************自定义异常类*********************/
@Getter
public class MyException extends RuntimeException {

    private String code;

    protected MyException(String code, String msg) {
        super(msg);
        this.code = code;
    }

    protected MyException(ErrorCodeEnum errorCodeEnum) {
        super(errorCodeEnum.getMsg());
        this.code = errorCodeEnum.getCode();
    }
}
/***************包装一个异常创建类*********************/
public class MyExceptionFactory {

    private MyExceptionFactory() {
    }

    public static MyException create(String code, String msg) {
        return new MyException(code, msg);
    }

    public static MyException create(ErrorCodeEnum errorCodeEnum) {
        return new MyException(errorCodeEnum.getCode(), errorCodeEnum.getMsg());
    }

    public static MyException create(ErrorCodeEnum errorCodeEnum, String msg) {
        return new MyException(errorCodeEnum.getCode(), msg);
    }
}
三、统一处理异常

想要统一处理异常,我们需要用到@RestControllerAdvice这个注解,这个注解有三个作用:

  • 全局异常处理
  • 全局数据绑定
  • 全局数据预处理

我们这里用到的是第一种功能。

@RestControllerAdvice
public class MyExceptionHandler {

    @ExceptionHandler(MyException.class)
    public <T> RespResult<T> handleMyException(MyException e) {
        return RespResult.error(e.getCode(), e.getMessage());
    }

    @ExceptionHandler(IllegalArgumentException.class)
    public <T> RespResult<T> handleMyException(IllegalArgumentException e) {
        return RespResult.error(ErrorCodeEnum.ILLEGAL_PARAM.getCode(), e.getMessage());
    }

    @ExceptionHandler(ArithmeticException.class)
    public <T> RespResult<T> handleMyException(ArithmeticException e) {
        return RespResult.error(ErrorCodeEnum.ILLEGAL_PARAM.getCode(), "运算错误");
    }
}

使用了@RestControllerAdvice注解之后,这个类就会去处理程序抛出的异常,但前提是需要配合@ExceptionHandler这个注解使用,这个注解需要传入一个异常类.class来捕获具体的异常,如@ExceptionHandler(MyException.class)就会拦截到MyException类型的异常,然后再将异常信息获取到,并封装到RespResult的返回里。

四、测试
@RestController
@RequestMapping
public class TestController {

    @GetMapping("/ok")
    public RespResult<String> ok() {
        return RespResult.ok("hello world!");
    }

    @GetMapping("/err1")
    public RespResult<List<String>> err1() {
        List<String> list = new ArrayList<>();
        list.add("name不能为空");
        list.add("code不能为空");
        return RespResult.error(ErrorCodeEnum.ILLEGAL_PARAM.getCode(), ErrorCodeEnum.ILLEGAL_PARAM.getMsg(), list);
    }

    @GetMapping("/err2")
    public RespResult<Void> err2() {
        throw MyExceptionFactory.create(ErrorCodeEnum.ILLEGAL_PARAM);
    }
}

1.请求"/ok"

{
  "code": "000",
  "msg": "success",
  "data": "hello world!"
}

2.请求"/err1"

{
  "code": "001",
  "msg": "参数错误",
  "data": [
    "name不能为空",
    "code不能为空"
  ]
}

3.请求"/err2"

{
  "code": "001",
  "msg": "参数错误",
  "data": null
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值