0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Spring Boot怎么通过注解来实现全局异常处理的

科技绿洲 来源:Java技术指北 作者:Java技术指北 2023-10-13 10:58 次阅读

前言

在平时的 API 开发过程中,总会遇到一些错误异常没有捕捉到的情况。那有的小伙伴可能会想,这还不简单么,我在 API 最外层加一个 try...catch 不就完事了。

哈哈哈,没错。这种方法简单粗暴。小编曾经也是这么干的,但是你转过来想一想,你会在每一个 API 入口,都去做 try...catch 吗?这样不是代码非常丑陋的。小伙伴开始思考,突然灵光一现,说我们实现一个 AOP 来做这事不就完了。没错,使用 AOP 来实现是最佳的选择。

现在就给大家来介绍介绍 Spring Boot 怎么通过注解来实现全局异常处理的。

主角 @ControllerAdvice@ExceptionHandler

我们先来介绍一下今天的主角,分别是 @ControllerAdvice@ExceptionHandler

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

案例分析

今天我们就通过几种案例的方式,来给大家分析分析,怎么通过全局异常处理的方式玩转 Spring Boot 的全局异常处理。

案例一

一般的异常处理,所有的API都需要有相同的异常结构。

图片

exception1

在这种情况下,实现是非常简单的,我们只需要创建 GeneralExceptionHandler 类,用 @ControllerAdvice 注解来注解它,并创建所需的 @ExceptionHandler ,它将处理所有由应用程序抛出的异常,如果它能找到匹配的 @ExceptionHandler,它将相应地进行转换。

@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 不同。

图片

exception2

我们可以采取两种方式来实现这种情况。我们可以在 OtherController 内部添加 @ExceptionHandler 来处理 OtherException ,或者为 OtherController 创建新的@ControllerAdvice,以备我们也想在其他 API 中处理 OtherException

OtherController 中添加 @ExceptionHandler 来处理 OtherException 的代码示例。

@RestController
@RequestMapping("/other")
public class OtherController {
    @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()));
    }
}

只针对 OtherController 控制器@ControllerAdvice 的代码示例

@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 的方式对异常进行格式化,但这次所有的异常都需要进行不同的转换。

图片exception3

为了实现这个案例,我们将不得不使用两个 @ControllerAdvice,并加上 @Order 注解的注意事项。因为现在我们需要告诉 Spring,在处理同一个异常时,哪个 @ControllerAdvice 的优先级更高。如果我们没有指定 @Order,在启动时,其中一个处理程序将自动注册为更高的顺序,我们的异常处理将变得不可预测。例如,我最近看到一个案例,如果你使用 mvn springboot:run 任务启动一个应用程序,OtherExceptionHandler 是主要的,但是当以jar形式启动时,GeneralExceptionHandler 是主要的。

@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()));
    }
}

总结

经过上述的几个案例,指北君觉得大家应该已经能够轻松应对 Spring Boot 中大部分的全局异常处理的情况。

细心的同学也许会觉得为什么不使用 @RestControllerAdvice 呢?如果是用的 @RestControllerAdvice 注解,它会将数据自动转换成JSON格式,不再需要 ResponseEntity 的处理来。这种与 ControllerRestController 类似,本质是一样的,所以我们在使用全局异常处理之后可以进行灵活的选择处理。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • API
    API
    +关注

    关注

    2

    文章

    1384

    浏览量

    61007
  • 代码
    +关注

    关注

    30

    文章

    4557

    浏览量

    66866
  • SpringBoot
    +关注

    关注

    0

    文章

    172

    浏览量

    110
收藏 人收藏

    评论

    相关推荐

    Spring Boot如何实现异步任务

    Spring Boot 提供了多种方式来实现异步任务,这里介绍三种主要实现方式。 1、基于注解 @Async @Async
    的头像 发表于 09-30 10:32 494次阅读

    启动Spring Boot项目应用的三种方法

    首先大家了解什么是Spring BootSpring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用
    发表于 01-14 17:33

    使用Spring自定义注解实现

    执行器。其本质就是通过外部参数进行一次路由和Spring mvc做的事情类似。简单看了Spring mvc的实现原理之后,决定使用自定义注解
    发表于 09-28 11:55 0次下载

    Spring Boot框架错误处理

    》 《strong》翻译《/strong》:雁惊寒《/p》 《/blockquote》《p》《em》摘要:本文通过实例介绍了使用Spring Boot在设计API的时候如何正确地对异常
    发表于 09-28 15:31 0次下载

    Spring Boot 系列(八)@ControllerAdvice 拦截异常并统一处理

    Spring Boot 系列(八)@ControllerAdvice 拦截异常并统一处理spring 3.2中,新增了@Controll
    发表于 01-16 18:39 260次阅读

    教你如何用一个注解搞定Spring Boot接口防刷

    一,技术要点: Spring Boot的基本知识,Redis基本操作,首先是写一个注解类: import java.lang.annotation.Retention; import
    的头像 发表于 09-13 09:23 1572次阅读

    Spring Boot Web相关的基础知识

    Boot的第一个接口。接下来将会将会介绍使用Spring Boot开发Web应用的相关内容,其主要包括使用spring-boot-starter-web组件来
    的头像 发表于 03-17 15:03 465次阅读

    Spring Web MVC注解

    RequestMapping注解的主要用途是将Web请求与请求处理类中的方法进行映射。Spring MVC和Spring WebFlux都通过
    的头像 发表于 04-07 11:32 407次阅读
    <b class='flag-5'>Spring</b> Web MVC<b class='flag-5'>注解</b>

    容器配置及Spring Boot注解

    Autowired注解用于标记Spring将要解析和注入的依赖项。此注解可以作用在构造函数、字段和setter方法上。
    的头像 发表于 04-07 11:45 417次阅读
    容器配置及<b class='flag-5'>Spring</b> <b class='flag-5'>Boot</b><b class='flag-5'>注解</b>

    Spring Boot中整合两种定时任务的方法

    Spring + SpringMVC 环境中,一般来说,要实现定时任务,我们有两中方案,一种是使用 Spring 自带的定时任务处理器 @Scheduled
    的头像 发表于 04-07 14:55 1248次阅读
    <b class='flag-5'>Spring</b> <b class='flag-5'>Boot</b>中整合两种定时任务的方法

    Spring中@Component注解是怎么实现

    想必`@Component`注解大家一直在使用,只要类上加上它,就可以被Spring容器管理,那大家有想过它是怎么实现的吗?本篇文章就带领到家揭秘。
    的头像 发表于 04-07 15:23 1200次阅读
    <b class='flag-5'>Spring</b>中@Component<b class='flag-5'>注解</b>是怎么<b class='flag-5'>实现</b>的

    Spring Boot启动 Eureka流程

    类。Spring Boot 启动 eureka 的关键注解就在 @EnableEurekaServer 上面。 @Target ({ElementType.TYPE}) @Retention
    的头像 发表于 10-10 11:40 422次阅读
    <b class='flag-5'>Spring</b> <b class='flag-5'>Boot</b>启动 Eureka流程

    Spring Boot的启动原理

    可能很多初学者会比较困惑,Spring Boot 是如何做到将应用代码和所有的依赖打包成一个独立的 Jar 包,因为传统的 Java 项目打包成 Jar 包之后,需要通过 -classpath 属性
    的头像 发表于 10-13 11:44 377次阅读
    <b class='flag-5'>Spring</b> <b class='flag-5'>Boot</b>的启动原理

    Spring Boot 的设计目标

    ,这样我们就可以尽快的上手。 使用 Spring Boot 来不仅可以创建基于 war 方式部署的传统Java应用程序,也可以通过创建独立的不依赖任何容器(如 tomcat 等)
    的头像 发表于 10-13 14:56 315次阅读
    <b class='flag-5'>Spring</b> <b class='flag-5'>Boot</b> 的设计目标

    springboot核心注解

    Spring Boot 是基于 Spring 框架的开源框架,它可以帮助开发者快速构建、部署和运行独立的、生产级的 Spring 应用程序。Spri
    的头像 发表于 11-23 09:23 296次阅读