IOTXING

记录技术学习之路

0%

spring boot 自定义全局异常处理

spring boot 全局错误异常处理

1. 背景

在开发一个前后端分离的项目时,难免会遇到各种各样的业务逻辑错误,例如某个接口,其中可能有十种情况会影响业务的清空,如果是一个对用户比较友好的项目的话,对于这10种情况都会做对应的错误处理,能够让用户清楚业务不成功的具体原因。向阿里云,腾讯云等提供的sdk,都会定义自己的错误异常文件,进而将异常信息抛出来,让用户清楚自己错误的原因。

一般我们使用抛出异常或者通过修改自定义的返回体,来将错误信息给前端进行返回。在抛出异常的时候,我们会希望能够根据该异常,返回一个统一数据结构,这样能够方便前端进行处理。所以我们需要想办法通过controller层对异常进行处理,然后按照预定的格式内容返回给前端json字符串。

因为有时候我们在完成一个接口的时候,有些情况下并不是直接发生了错误,可能是在经过了几个service的时候,出现了错误,这个时候因为每一层service都会定义个一个返回值类型,所以很难去将我们的错误类型给抛出来,如果通过写上一堆if else来判断函数执行有没有正常执行的话,代码可读性以及可扩展性太差了。

这个时候如果将异常抛出,然后最上层统一进行处理,就能够避免这种问题

类似这种,会规定错误码以及对应的错误信息,方便用户排查。

2.数据结构

在进行返回数据的时候,考虑到兼容性以及用户友好,设计了一下的数据结构

public class Result<T> implements Serializable {

    private String errCode = "0";

    private T data;

    private String errorMsg;

    private Boolean status;

}

其中errCode采用String类型,默认为0,即0为业务处理成功。

如果业务正常处理成功,则将status置为true,并且将数据放在data中进行返回。

3. 错误常量定义

因为考虑到会有较多的错误类型,为了统一进行管理,我使用了一个枚举类来盛放所有的错误类型,这样对同一种类型的异常,我就能够通过使用一个异常类,然后通过传入不同的枚举类型来进行处理。个人觉得这样能够对效率有所提升

public enum ErrorConstant {

    RESOURCE_ACCOUNT_EXIST("10001", "资源账户已经存在"),
    RESOURCE_ACCOUNT_PRODUCT_EXIST("10011", "资源产品已经关联");

    private String value;

    private String desc;


    ErrorConstant(String value, String desc) {
        this.value = value;
        this.desc = desc;
    }

    public String getValue() {
        return value;
    }

    public String getDesc() {
        return desc;
    }
}

4. 编写自定义异常类

这里我们需要写一个我们自己的异常类,之后出现预料中错误时,可以直接抛出该异常类

public class BaseException extends Exception {

    private ErrorConstant errorConstant;

    //在新建BaseException对象的时候,传入一个错误枚举,这样方便在处理异常的时候使用

    public BaseException(ErrorConstant errorConstant) {
        this.errorConstant = errorConstant;
    }
}

所有的自定义异常类都要继承Exception或者已经继承Exception的子类。

5. 编写异常处理类

这里我们主要会用到三个注解

@ControllerAdvice:该注解作用于整个spring工程,定义了一个会对全局的异常都进行捕获

@ResponseBody:定义返回JSON给前端

@ExceptionHandler :捕获指定的Exception,然后进行处理

@ControllerAdvice
@ResponseBody
@Slf4j
public class ResponseExceptionHandler {


    @ExceptionHandler(BaseException.class)
    Result handleCustomException(BaseException e) {
        return new Result(e.getErrorConstant());
    }
}

这里我只对BaseException这一种类型的异常进行处理,也就是说所有抛出的BaseException,都会在这里进行处理,然后返回给前端。

6. 异常抛出

这里我在处理资源账户的时候,针对存在的账户,抛出一个异常,错误信息为资源账户已存在。

public Boolean createResourceAccount(ResourceAccountRequest resourceAccountRequest) throws Exception {
    if (resourceAccountRepository.findByResourceId(resourceAccountRequest.getResourceId())
        != null) {
      throw new BaseException(ErrorConstant.RESOURCE_ACCOUNT_EXIST);
    }
}

我只需要每一层都把异常抛出去,然后由最上层的ExceptionHandler来进行处理就好了。

通过将异常由最上层统一处理,就能够避免在业务处理过程中,各种情况的判断,能够大幅度的提高开发效率以及代码可读性。