统一异常拦截

Spring Boot @RestControllerAdvice 统一异常处理

 

在做前后端分离的项目时,后端通常都会拆分成多个独立的微服务,这时候就会涉及每个服务返回给前端的数据格式问题了。下面就来实现一个比较常用的数据格式,统一所有服务的返回值格式。
一般返回的数据格式会包括4个部分,第一部分: 请求处理是否成功,第二部分:服务处理结果编码,第三部分:编码对应的文本信息,第四部分:返回值。如下所示:

{
    "result": true,
    "code": 1000,
    "message": "SUCCESS",
    "data": {
        "lantian": 17,
        "qingfen": 16,
        "baiyun": 18
    }
}

对于异常处理情况,我们也需要统一成上面的格式。如果我们在controller中通过try catch来处理异常的话,会出现一个问题就是每个函数里都加一个Try catch,代码会变的很乱。下面我们就通过spring boot的注解来省略掉controller中的try-catch 帮助我们来封装异常信息并返回给前端,这样用户也不会得到一些奇奇怪怪的错误提示。

{
    "result": false,
    "code": 3000,
    "message": "THIS IS AN UNKNOW EXCEPTION",
    "data": null
}

1:定义返回值结构信息(get, set函数省略)

public class CallResultMsg<T> {
    private boolean result;
    private int code;
    private String message;
    private T data;
}

2:定义返回值和对应code的信息(get, set函数省略)

public enum CodeAndMsg {
    SUCCESS(1000, "SUCCESS"),
    METHODFAIL(2000, "ENCOUNTER AN ERROR WHEN EXECUTE METHOD"),
    UNKNOWEXCEPTION(3000, "THIS IS AN UNKNOW EXCEPTION");

    private int code;
    private String msg;

    CodeAndMsg(int code, String msg){
        this.code = code;
        this.msg = msg;
    }
}

3:自定义异常

对于一些特别的异常,我们可以自定义Exception和Error Code,这里自定义一个异常(需要继承RuntimeException)

public class UserDefinedException extends RuntimeException {
    private CodeAndMsg exception;

    public UserDefinedException(CodeAndMsg exception){
        this.exception = exception;
    }

    public CodeAndMsg getException() {
        return exception;
    }

    public void setException(CodeAndMsg exception) {
        this.exception = exception;
    }
}

4:RestControllerAdvice来捕获全局异常,

@RestControllerAdvice都是对Controller进行增强的,可以全局捕获spring mvc抛的异常。
@ExceptionHandler(value = Exception.class)
ExceptionHandler的作用是用来捕获指定的异常。

@RestControllerAdvice(annotations = RestController.class)
public class UniformReponseHandler<T> {

    @ResponseStatus(HttpStatus.OK)
    public CallResultMsg sendSuccessResponse(){
        return new CallResultMsg(true, CodeAndMsg.SUCCESS, null);
    }

    @ResponseStatus(HttpStatus.OK)
    public CallResultMsg sendSuccessResponse(T data) {
        return new CallResultMsg(true, CodeAndMsg.SUCCESS, data);
    }

    @ExceptionHandler(UserDefinedException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public CallResultMsg sendErrorResponse_UserDefined(Exception exception){
        return new CallResultMsg(false, ((UserDefinedException)exception).getException(), null);
    }

    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public CallResultMsg sendErrorResponse_System(Exception exception){
        if (exception instanceof UserDefinedException) {
            return this.sendErrorResponse_UserDefined(exception);
        }

        return new CallResultMsg(false, CodeAndMsg.UNKNOWEXCEPTION, null);
    }
}

通过上面的一波操作,我们的controller中就不需要再去写大量的try-catch了,RestControllerAdvice会自动帮助catch,并匹配相应的ExceptionHandler,然后重新封装异常信息,返回值,统一格式返回给前端。
\color{ red }{ 当然也可以单独写成一个jar包,供其他微服务的使用。 }

5:ControllerAdvice 和 RestControllerAdvice的区别

@ControllerAdvice 和 @RestControllerAdvice都是对Controller进行增强的,可以全局捕获spring mvc抛的异常。
RestControllerAdvice = ControllerAdvice + ResponseBody
6:测试统一异常捕获功能

@GetMapping("/doTestObject")
public CallResultMsg testObjectReturn(){
    Map<String, Integer> map = new HashMap();
    map.put("qingfen", 16);
    map.put("lantian", 17);
    map.put("baiyun", 18);
    return new UniformReponseHandler<Map>().sendSuccessResponse(map);
}


@GetMapping("/doTestException/{x}")
public int testExceptionResturn(@PathVariable int x){
    if (0 < x && x < 10){
        throw new UserDefinedException(CodeAndMsg.METHODFAIL);
    } else {
        return  1/0;
    }
}

返回结果:

{
    "result": true,
    "code": 1000,
    "message": "SUCCESS",
    "data": {
        "lantian": 17,
        "qingfen": 16,
        "baiyun": 18
    }
}
{
    "result": false,
    "code": 2000,
    "message": "ENCOUNTER AN ERROR WHEN EXECUTE METHOD ",
    "data": null
}
posted @ 2022-04-06 13:46  姚春辉  阅读(160)  评论(0编辑  收藏  举报