【AgileTC】_捕获异常并返回相应自定义状态码

【AgileTC】_捕获异常并返回相应自定义状态码

  • 创建一个全局异常捕捉器,捕捉SpringMVC容器中出现的一些特定异常,然后向前端返回更加详细的异常信息,也就是说Filter等非SpringMVC容器中出现的异常并不会被捕获;如果一个异常被该捕捉器捕获了,后端返回的http状态码并不是5类,而是2类;

  • 1.创建一个异常捕捉器类,用@ControllerAdvice注解和@ExceptionHandler进行配置:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    @ControllerAdvice
    @ResponseBody
    public class ExpHandler {

    private final static Logger LOGGER = LoggerFactory.getLogger(ExpHandler.class);

    @ExceptionHandler(IllegalArgumentException.class)
    public Response<?> handlerException(IllegalArgumentException e) {
    e.printStackTrace();
    LOGGER.error(StatusCode.INTERNAL_ERROR.getCode(), e.getMessage());
    return Response.build(StatusCode.INTERNAL_ERROR, e.getMessage());
    }

    @ExceptionHandler(MissingServletRequestParameterException.class)
    public Response<?> handlerException(MissingServletRequestParameterException e) {
    e.printStackTrace();
    LOGGER.error(StatusCode.INTERNAL_ERROR.getCode(), e.getMessage());
    return Response.build(StatusCode.INTERNAL_ERROR, e.getMessage());
    }

    @ExceptionHandler(JsonMappingException.class)
    public Response<?> handlerException(JsonMappingException e) {
    e.printStackTrace();
    LOGGER.error(StatusCode.JSON_FORMAT_ERROR.getCode(), e.getMessage());
    return Response.build(StatusCode.JSON_FORMAT_ERROR);
    }

    @ExceptionHandler(JsonParseException.class)
    public Response<?> handlerException(JsonParseException e) {
    e.printStackTrace();
    LOGGER.error(StatusCode.DATA_FORMAT_ERROR.getCode(), e.getMessage());
    return Response.build(StatusCode.DATA_FORMAT_ERROR);
    }

    /**
    * 自定义异常
    */
    @ExceptionHandler(CaseServerException.class)
    public Response<?> handlerException(CaseServerException e) {
    e.printStackTrace();
    LOGGER.error(StatusCode.INTERNAL_ERROR.getCode(), e.getMessage());
    return Response.build(StatusCode.INTERNAL_ERROR, e.getMessage());
    }

    /**
    * 这里的全局异常是捕捉controller下没有try catch Exception的Method的
    */
    @ExceptionHandler(Exception.class)
    public Response<?> handlerException(Exception e) {
    e.printStackTrace();
    LOGGER.error(StatusCode.SERVER_BUSY_ERROR.getCode(), e.getMessage());
    return Response.build(StatusCode.SERVER_BUSY_ERROR);
    }
    }
  • 2.创建一个继承RuntimeException的自定义异常类,其实就是给运行时异常加上一个Status状态码属性,使得捕捉器在捕获到该异常时,可以返回更加详细的信息:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    public class CaseServerException extends RuntimeException {

    private Status status;

    public CaseServerException(Status status) {
    this.status = status;
    }

    public CaseServerException(String message, Status status) {
    super(message);
    this.status = status;
    }

    public CaseServerException(String message, Throwable cause, Status status) {
    super(message, cause);
    this.status = status;
    }

    public CaseServerException(Throwable cause, Status status) {
    super(cause);
    this.status = status;
    }

    public CaseServerException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Status status) {
    super(message, cause, enableSuppression, writableStackTrace);
    this.status = status;
    }

    public Status getStatus() {
    return status;
    }

    public void setStatus(Status status) {
    this.status = status;
    }

    }
  • 3.指定相关场景下抛出对应异常信息,一般这些抛出异常的代码都是在service层中编写,因为一般也就是service层中才会出现各种逻辑错误,往上抛就正好抛到SpringMVC容器的controller层中:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    //如果角色是基本角色且角色名称被修改了,则报错提示基础角色不能被修改
    if (role.getType() > 0 && !request.getRoleName().equals(role.getRoleName())) {
    throw new CaseServerException("系统角色名称不得被修改",StatusCode.INTERNAL_ERROR);
    }else {
    role.setRoleName(request.getRoleName());
    }

    //如果修改了基础角色的权限则报错
    if (role.getType() != 0) {
    for (Long inputPermId : inputPermIds) {
    if (!dbPermIds.contains(inputPermId)) {
    throw new CaseServerException("系统角色权限不得被修改",StatusCode.INTERNAL_ERROR);
    }
    }
    for (Long dbPermId : dbPermIds) {
    if (!inputPermIds.contains(dbPermId)) {
    throw new CaseServerException("系统角色权限不得被修改",StatusCode.INTERNAL_ERROR);
    }
    }
    }
  • 4.访问相关接口时如果出现对应逻辑错误,服务器就会抛出相关异常,并返回对应响应状态码,前端应将该响应信息渲染在浏览器界面上:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    //第一种情况返回的响应体
    {
    "code": 10400,
    "msg": "系统角色名称不得被修改",
    "data": null
    }

    //第二种情况返回的响应体
    {
    "code": 10400,
    "msg": "系统角色权限不得被修改",
    "data": null
    }