2

Spring 6/Spring Boot 3新特性:优雅的业务异常处理

 1 year ago
source link: https://www.51cto.com/article/721281.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Spring 6/Spring Boot 3新特性:优雅的业务异常处理

作者:爱科学的卫斯理 2022-10-26 07:14:25
当你使用Spring Boot(Spring MVC)进行RESTful API开发的时候,你会发现HTTP的状态码很多时候不能足够有效的传递错误的信息。

当你使用Spring Boot(Spring MVC)进行RESTful API开发的时候,你会发现HTTP的状态码很多时候不能足够有效的传递错误的信息。

HTTP里有一个RFC 7807规范:https://www.rfc-editor.org/rfc/rfc7807。这个规范里定义了HTTP API的“问题细节”(Problem Details)内容。

该规范定义了一个“问题细节”(Problem Details),用它来携带HTTP错误返回信息,避免自定义新的错误返回格式。我们通常情况下是自己定义错误返回格式的。

Spring 6.0为我们提供了一个org.springframework.http.ProblemDetail 来实现该规范。

RFC 7807是一个很简单的规范。它定义了一个JSON格式,并关联了一个媒体类型(media type),这个JSON格式包含了五个可选成员来描述问题细节:

type:一个URI引用,用来识别问题的类型。这个URI的路径内容应该用来显示人类可读的信息来描述类型;

title:人类可读的问题类型描述;相同类型的问题,应该总是相同的描述;

status:HTTP状态码,将它包含在问题细节里是一种方便的方式;

detail:人类可读的问题实例描述,解释为什么当前的问题发生在这个特定的场景下;

instance:一个URI引用,用来识别问题实例。这个URI的内容应该用来描述问题实例,但不是必须的。

我们首先建立一个演示项目:

f56aa07828a47bb0538692d6509e9ee176e901.png

1、通常的业务异常处理方法

定义一个业务异常类。异常含义为:当Person找不到的时候抛出的业务异常。

public class PersonNotFoundException  extends RuntimeException {
    @Getter
    private final HttpStatus status;

    public PersonNotFoundException(String message, HttpStatus status){
        super(message);
        this.status = status;
    }
}

注册这个业务异常到全局异常处理。

通过在@RestControllerAdvice 中定义全局的切面处理。

通过@ExceptionHandler 来处理指定异常的处理方式。

这里返回的格式就是我们自定义的ErrorMsg格式。我们通过自定义这个ErroMsg完成和接口使用者协议,完成对业务异常的处理。

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(PersonNotFoundException.class)
    public ResponseEntity<ErrorMsg> personNotFoundHandler(PersonNotFoundException e) {
        ErrorMsg msg = new ErrorMsg("0000", e.getMessage());
        return new ResponseEntity<>(msg, e.getStatus());
    }
}

需自定义的错误返回

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ErrorMsg {
    private String code;
    private String msg;
}

测试控制器

@RestController
public class PersonController {

    @GetMapping("/getPerson")
    public String getPerson(){
        throw new PersonNotFoundException("查找的人不存在", HttpStatus.NOT_FOUND);
    }
}

启动程序,访问:http://localhost:8080/getPerson

a8a8e9c66eec4d4e6be089cc17034651489378.png

2、基于“问题细节”的业务异常处理

基于我们常规的异常处理,其实已经能满足我们的业务需求,使用RFC 7807规范,我们可以免去自定义的异常错误格式(ErrorMsg ),使用Spring 6.0给我们提供的ProblemDetail ,这样我们以后再无需自己自定义异常返回格式,且在不同的项目之间有了标准,从而客户端在使用的时候有了可预测性。

Spring 6.0的做法也很简单,我们只需要将我们自定返回的ErrorMsg 修改成ProblemDetail 即可。我们看一下示例代码:

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(PersonNotFoundException.class)
    public ProblemDetail personNotFoundHandler(PersonNotFoundException e) {
      ProblemDetail problemDetail = ProblemDetail.forStatus(HttpStatus.NOT_FOUND); 
      problemDetail.setType(URI.create("https://www.toutiao.com/c/user/token/MS4wLjABAAAAJxW0bvHKNNwIpcsocIDAjNHHNXg2yaj1upViHO2JVNw/"));
      problemDetail.setTitle("Person Not Found");
      problemDetail.setDetail(String.format("错误信息:‘%s’", e.getMessage()));
      return problemDetail;
    }
}

值得说的是ProblemDetail 还支持设置一个Map的properties:

private Map<String, Object> properties;

这样也为我们的定制扩展提供了更大的空间。

启动,访问:http://localhost:8080/getPerson,其实的错误返回符合RFC 7807规范。

4269db6489bbb73b3155965e78c561c673ada0.png

注意查看返回的头信息,我们看到了,返回数据的媒体类型为:application/problem+json:

93b272c804e1da8b2a6194a51efc5aaf61ee42.png

感谢支持我的书:《从企业级开发到云原生微服务:Spring Boot实战》

参考资料:https://docs.spring.io/spring-framework/docs/6.0.0-RC2/javadoc-api/org/springframework/http/ProblemDetail.html

文章出自:​​爱科学的卫斯理​​,如有转载本文请联系爱科学的卫斯理今日头条号。


Recommend

  • 144
    • blog.didispace.com 6 years ago
    • Cache

    Spring Boot 2.0 新特性和发展方向

    Spring Boot 2.0 新特性和发展方向

  • 50

    在程序中,错误可能产生于程序员没有预料的各种情况,或者是超出了程序员可控范围的环境因素,如用户的坏数据、试图打开一个根本不存在的文件等...

  • 54

    之前一篇文章介绍了基本的统一异常处理思路: Spring MVC/Boot 统一异常处理最佳实践 . 上篇文章也有许多人提出了一些问题: 如何区分 Ajax 请求和普...

  • 44

    之前一篇文章介绍了基本的统一异常处理思路: Spring MVC/Boot 统一异常处理最佳实践. 上篇文章也有许多人提出了一些问题: 如何区分 Ajax 请求和普通页面请求, 以分...

  • 19
    • 微信 mp.weixin.qq.com 4 years ago
    • Cache

    Spring MVC 异常处理机制

    在Spring MVC中,当一个请求发生异常(Controller抛出一个异常时), DispatcherServlet 采用委托的方式交给一个处理链来处理或者解析这个抛出的异常,这是在request和Servlet Container之间的一道屏障,所以我们可以在这里做一些处理工作,如转换异常,转换成友...

  • 26

    本文将从如何处理业务流程和信息分发中的定时和延时问题出发,横向比较了业界常见的几种方案,如直接多线程编码、Spring定时调度框、大型分布式调度框架、消息中间件定时消息,因为消息中间件接口友好,调用方便,性能稳定,特别推荐了使...

  • 9

    GraalVM是一种高性能的虚拟机,它可以显著的提高程序的性能和运行效率,非常适合微服务。最近比较火的 Java 框架 Quarkus默认支持 GraalVM 下图为 Quarkus 和传统框架(SpringBoot) 等对比图,更快的启动数...

  • 9

    如何优雅的处理协程的异常? | 秉心说的技术博客 如何优雅的处理协程的异常? ...

  • 3
    • www.jdon.com 2 years ago
    • Cache

    Spring Boot 3的新特性 - jrebel

    Spring Boot 3的新特性 Spring Boot 3是期待已久的Spring Boot 2版本的后续版本,它目前是Spring Boot 3.0.0-M1的M1版本,Spring Boot 3.0.0-M2计划于3月24日交付。其中 M 表示里程碑版本,RC 表示候选发布版本,SNAPSHOT 表示构建。在向...

  • 4

    Spring Boot3.0 官方暂时还不支持,等等再看吧。 MyBatis-Plus 是 MyBatis 的第三方使用插件。 前两天在公众号中发了《Sprin...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK