SpringBoot中优雅的处理异常-SpringBoot优雅的实现异常处理-《Java笔记》

admin 2025-10-19 04:58:57 编程 来源:ZONE.CI 全球网 0 阅读模式

Java SpringBoot

前言

在平时的 API 开发过程中,总会遇到一些错误异常没有捕捉到的情况。那有的小伙伴可能会想,这还不简单么,在 API 最外层加一个 try...catch 不就完事了。这种方法简单粗暴。在每一个 API 入口,都去做 try...catch 吗?这样不是代码看起来非常丑陋。所以使用 AOP 来实现是最佳的选择。Spring Boot 通过注解来实现全局异常处理的。

@ControllerAdvice@ExceptionHandler

  • @ControllerAdvice 相当于 controller 的切面,主要用于 @ExceptionHandler, @InitBinder@ModelAttribute,使注解标注的方法对每一个 controller 都起作用。默认对所有 controller 都起作用,当然也可以通过 @ControllerAdvice 注解中的一些属性选定符合条件的 controller 。
  • @ExceptionHandler 用于异常处理的注解,可以通过 value 指定处理哪种类型的异常还可以与 @ResponseStatus 搭配使用,处理特定的 http 错误。标记的方法入参与返回值都有很大的灵活性,具体可以看注释也可以在后边的深度探究。

    案例分析

    通过全局异常处理的方式了解 Spring Boot 的全局异常处理。

    案例一

    一般的异常处理,所有的API都需要有相同的异常结构。SpringBoot优雅的实现异常处理 - 图1在这种情况下,实现是非常简单的,只需要创建 GeneralExceptionHandler 类,用 @ControllerAdvice 注解来注解它,并创建所需的 @ExceptionHandler ,它将处理所有由应用程序抛出的异常,如果它能找到匹配的 @ExceptionHandler,它将相应地进行转换。
    1. @ControllerAdvice
    2. public class GeneralExceptionHandler {
    3. @ExceptionHandler(Exception.class)
    4. protected ResponseEntity<Error> handleException(Exception ex) {
    5. MyError myError = MyError.builder()
    6. .text(ex.getMessage())
    7. .code(ex.getErrorCode()).build();
    8. return new ResponseEntity(myError,
    9. HttpStatus.valueOf(ex.getErrorCode()));
    10. }
    11. }

    案例二

    有一个API,它需要有一个或多个异常以其他格式处理,与其他应用程序的 API 不同。2021-07-31-19-35-50-840170.png可以采取两种方式来实现这种情况。可以在 OtherController 内部添加 @ExceptionHandler 来处理 OtherException ,或者为 OtherController 创建新的@ControllerAdvice,以备在其他 API 中处理 OtherException。在 OtherController 中添加 @ExceptionHandler 来处理 OtherException 的代码示例。
    1. @RestController
    2. @RequestMapping("/other")
    3. public class OtherController {
    4. @ExceptionHandler(OtherException.class)
    5. protected ResponseEntity<Error> handleException(OtherException ex) {
    6. MyOtherError myOtherError = MyOtherError.builder()
    7. .message(ex.getMessage())
    8. .origin("Other API")
    9. .code(ex.getErrorCode()).build();
    10. return new ResponseEntity(myOtherError,
    11. HttpStatus.valueOf(ex.getErrorCode()));
    12. }
    13. }
    只针对 OtherController 控制器的 @ControllerAdvice 的代码示例
    1. @ControllerAdvice(assignableTypes = OtherController.class)
    2. public class OtherExceptionHandler {
    3. @ExceptionHandler(OtherException.class)
    4. protected ResponseEntity<Error> handleException(OtherException ex) {
    5. MyOtherError myOtherError = MyOtherError.builder()
    6. .message(ex.getMessage())
    7. .origin("Other API")
    8. .code(ex.getErrorCode()).build();
    9. return new ResponseEntity(myOtherError,
    10. HttpStatus.valueOf(ex.getErrorCode()));
    11. }
    12. }

    案例三

    与案例二类似,有一个 API 需要以不同于应用程序中其他 API 的方式对异常进行格式化,但这次所有的异常都需要进行不同的转换。SpringBoot优雅的实现异常处理 - 图3为了实现这个案例,将不得不使用两个 @ControllerAdvice,并加上 @Order 注解的注意事项。因为现在需要告诉 Spring,在处理同一个异常时,哪个 @ControllerAdvice 的优先级更高。如果没有指定 @Order,在启动时,其中一个处理程序将自动注册为更高的顺序,异常处理将变得不可预测。例如,如果使用 mvn springboot:run 任务启动一个应用程序,OtherExceptionHandler 是主要的,但是当以jar形式启动时,GeneralExceptionHandler 是主要的。
    1. @ControllerAdvice
    2. public class GeneralExceptionHandler {
    3. @ExceptionHandler(Exception.class)
    4. protected ResponseEntity<Error> handleException(Exception ex) {
    5. MyError myError = MyError.builder()
    6. .text(ex.getMessage())
    7. .code(ex.getErrorCode()).build();
    8. return new ResponseEntity(myError,
    9. HttpStatus.valueOf(ex.getErrorCode()));
    10. }
    11. }
    12. @ControllerAdvice(assignableTypes = OtherController.class)
    13. @Order(Ordered.HIGHEST_PRECEDENCE)
    14. public class OtherExceptionHandler {
    15. @ExceptionHandler(Exception.class)
    16. protected ResponseEntity<Error> handleException(Exception ex) {
    17. MyError myError = MyError.builder()
    18. .message(ex.getMessage())
    19. .origin("Other API")
    20. .code(ex.getErrorCode()).build();
    21. return new ResponseEntity(myError,
    22. HttpStatus.valueOf(ex.getErrorCode()));
    23. }
    24. }

    总结

    经过上述的几个案例,应该已经能够轻松应对 Spring Boot 中大部分的全局异常处理的情况。为什么不使用 @RestControllerAdvice 呢?如果是用的 @RestControllerAdvice 注解,它会将数据自动转换成JSON格式,不再需要 ResponseEntity 的处理来。这种与 ControllerRestController 类似,本质是一样的,所以在使用全局异常处理之后可以进行灵活的选择处理。
以太坊cppgolang区别 编程

以太坊cppgolang区别

以太坊是一种去中心化的开源平台,它采用智能合约技术,旨在构建和运行不受干扰的分布式应用程序。作为目前最受欢迎的区块链平台之一,以太坊提供了多种编程语言的支持,其
progolang 编程

progolang

Go语言(Golang)是由Google开发的一门静态类型编程语言。作为一名专业的Golang开发者,我深知这门语言的优势和特点。在本文中,我将介绍Golang
golangn个发送者 编程

golangn个发送者

Golang是一种开源的编程语言,由Google团队开发,旨在提高程序的并发性和简化软件开发过程。在Go语言中,有时需要向多个接收者发送信息。本文将介绍如何在G
golang技能图谱 编程

golang技能图谱

从互联网行业的快速发展到人工智能技术的日益成熟,各种编程语言也应运而生。而在这众多的编程语言中,Golang(即Go)作为一门强大且高效的开发语言备受关注。Go
评论:0   参与:  14