Springboot优雅处理异常| 8月更文挑战

194 阅读2分钟

这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战

平时的API开发过程,我们总会在API的最外层加一个try...catch来捕获异常错误。这种方法简单粗暴,但是在每个API入口都去做这样的处理的话,代码不够优雅。所以我们要实现一个AOP来进行全局的异常处理。

@ControllerAdvice 和 @ExceptionHandler

@ControllerAdvice 相当于 controller 的切面,主要用于 @ExceptionHandler,  @InitBinder 和 @ModelAttribute,使注解标注的方法对每一个 controller 都起作用。默认对所有 controller 都起作用,当然也可以通过 @ControllerAdvice 注解中的一些属性选定符合条件的 controller

@ExceptionHandler 用于异常处理的注解,可以通过 value 指定处理哪种类型的异常还可以与 @ResponseStatus 搭配使用,处理特定的 http 错误。标记的方法入参与返回值都有很大的灵活性

一、所有的API都需要相同的异常处理。

@ControllerAdvice
public class GeneralExceptionHandler {
    @ExceptionHandler(Exception.class)
    protected ResponseEntity<Error> handleException(Exception ex) {
       MyError myError = MyError.builder()
                         .text(ex.getMessage())
                         .code(ex.getErrorCode()).build();
       return new ResponseEntity(myError,HttpStatus.valueOf(ex.getErrorCode()));
    }
}

二、有一个API,它需要一个或多个异常其他形式进行格式处理,与其他应用程序API不同。我们可以在 OtherController 内部添加 @ExceptionHandler 来处理 OtherException ,或者为 OtherController 创建新的@ControllerAdvice,以备我们也想在其他 API 中处理 OtherException

@ControllerAdvice(assignableTypes = OtherController.class)
public class OtherExceptionHandler {
    @ExceptionHandler(OtherException.class)
    protected ResponseEntity<Error> handleException(OtherException ex) {
      MyOtherError myOtherError = MyOtherError.builder()
                         .message(ex.getMessage())
                         .origin("Other API")
                         .code(ex.getErrorCode()).build();
      return new ResponseEntity(myOtherError,HttpStatus.valueOf(ex.getErrorCode()));
    }
}

三、我们有一个 API 需要以不同于应用程序中其他 API 的方式对异常进行格式化,但这次所有的异常都需要进行不同的转换。加上 @Order 注解的注意事项。因为现在我们需要告诉 Spring,在处理同一个异常时,哪个 @ControllerAdvice 的优先级更高。

@ControllerAdvice
public class GeneralExceptionHandler {
    @ExceptionHandler(Exception.class)
    protected ResponseEntity<Error> handleException(Exception ex) {
       MyError myError = MyError.builder()
                         .text(ex.getMessage())
                         .code(ex.getErrorCode()).build();
       return new ResponseEntity(myError, HttpStatus.valueOf(ex.getErrorCode()));
    }
}
@ControllerAdvice(assignableTypes = OtherController.class)
@Order(Ordered.HIGHEST_PRECEDENCE)
public class OtherExceptionHandler {
    @ExceptionHandler(Exception.class)
    protected ResponseEntity<Error> handleException(Exception ex) {
       MyError myError = MyError.builder()
                         .message(ex.getMessage())
                         .origin("Other API")
                         .code(ex.getErrorCode()).build();
       return new ResponseEntity(myError,HttpStatus.valueOf(ex.getErrorCode()));
    }
}

如果是用的 @RestControllerAdvice 注解,它会将数据自动转换成JSON格式,不再需要 ResponseEntity 的处理来。这种与 Controller 和 RestController 类似,本质是一样的,所以我们在使用全局异常处理之后可以进行灵活的选择处理