65.9K
CodeProject 正在变化。 阅读更多。
Home

Spring Boot 2 – REST 异常

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2019年4月8日

CPOL

7分钟阅读

viewsIcon

8192

Spring Boot 2 – REST 异常

本教程可能让你想要更多。我不会给出明确的“如果这样,就那样做”的建议,而是向你展示在使用 Spring Boot 2 开发 Rest 端点时处理异常的三种不同技术。有经验的读者可能会问,为什么还要费心呢?因为 Spring Boot 默认会处理异常并呈现一个漂亮的 Rest 响应。然而,在某些情况下,你可能需要自定义异常处理,本教程将演示三种技术。与本网站上的其他教程一样,这里的“买者自负”原则依然适用……如果你使用不同版本的 Spring Boot,或者更糟的是,Spring 而非 Spring Boot 来遵循本教程,那么请做好进行进一步研究的准备,因为 Spring Boot 2 的主要目的是简化 Spring 开发。通过简化,许多实现细节变得隐藏起来了。

使用 Spring Boot Rest,我们可以通过三种方式处理异常:默认处理、控制器中的异常处理或全局异常处理。在本教程中,我们将探讨处理异常的所有这三种方法。

项目设置

开始之前,请创建你的 Spring Boot 应用程序。如果你是 Spring Boot 新手,那么在尝试本教程之前,你应该参考此处或网上的教程之一。本教程假设你能创建、编译和运行一个 Spring Boot Rest 应用程序。它还假设你知道如何调用 Rest 端点。

  • 在 Eclipse 中创建一个新的 Spring Boot Maven 项目。我使用 Spring Initializer 来创建项目。(Spring Initializr 视频书面教程
  • 将组的值指定为 com.tutorial.exceptions.spring.rest,将工件的值指定为 exceptions-tutorial

  • 为简单起见,请将 POM 替换为以下内容:
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation=
      "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
        <parent>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-parent</artifactId>
          <version>2.1.3.RELEASE</version>
          <relativePath /> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.tutorial.exceptions.spring.rest</groupId>
          <artifactId>exceptions-tutorial</artifactId>
          <version>0.0.1-SNAPSHOT</version>
          <name>exceptions-tutorial</name>
          <description>Tutorial project demonstrating exceptions in Spring Rest.
          </description>
          <properties>
            <java.version>1.8</java.version>
          </properties>
          <dependencies>
            <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-web</artifactId>
    	</dependency>
    	<dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-test</artifactId>
              <scope>test</scope>
            </dependency>
          </dependencies>
          <build>
            <plugins>
              <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
              </plugin>
            </plugins>
          </build>
    </project>
  • 创建一个名为 ExceptionTutorialApplication 的新类,该类扩展 SpringBootApplication 并在 main 方法中启动 Spring 应用程序。
    package com.tutorial.exceptions.spring.rest.exceptionstutorial;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class ExceptionsTutorialApplication {
    
      public static void main(String[] args) {
        SpringApplication.run(ExceptionsTutorialApplication.class, args);
      }
    }
  • 创建一个名为 HelloGoodbye 的新类。创建三个属性:greetinggoodbyetype
    package com.tutorial.exceptions.spring.rest.exceptionstutorial;
    
    public class HelloGoodbye {
      private String greeting;
      private String goodbye;
      private String type;
    	
      public String getType() {
        return type;
      }
      public void setType(String type) {
        this.type = type;
      }
      public String getGoodbye() {
        return goodbye;
      }
      public void setGoodbye(String goodbye) {
        this.goodbye = goodbye;
      }
      public String getGreeting() {
        return greeting;
      }
      public void setGreeting(String greeting) {
        this.greeting = greeting;
      }	
    }
  • 创建一个名为 GreetingService 的新 Spring 服务。
  • 暂时放下疑虑,实现一个名为 createGreeting 的方法,如下所示:
    package com.tutorial.exceptions.spring.rest.exceptionstutorial;
    
    import org.springframework.stereotype.Service;
    
    @Service
    public class GreetingService {
    
      public HelloGoodbye createGreeting(String type) {
        HelloGoodbye helloGoodbye = new HelloGoodbye();
        if(type.equals("hello")) {
          helloGoodbye.setGreeting("Hello there.");
        }
        else if(type.equals("goodbye")) {
          helloGoodbye.setGoodbye("Goodbye for now.");
        }
        helloGoodbye.setType(type);
        return helloGoodbye;
      }
    }
  • 创建一个新的 Spring Rest 控制器并自动注入 GreetingService
  • 创建一个名为 getGreeting 的新方法,该方法接受一个名为 type 的请求参数,并调用 GreetingServicecreateGreeting 方法。
    package com.tutorial.exceptions.spring.rest.exceptionstutorial;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @RequestMapping(value = "/greeting")
    public class GreetingController {
    
      @Autowired
      protected GreetingService service;
    
      @GetMapping("/greet")
      public HelloGoodbye getGreeting(@RequestParam("type") String type) {
        HelloGoodbye goodBye = service.createGreeting(type);
        return goodBye;
      }
    }
  • 编译并运行应用程序。
  • 使用 Curl、WebBrowser 或 Postman 等其他工具调用 Rest 端点,并将 type 的值指定为 hello
    https://:8080/greeting/greet?type=hello
  • 注意 JSON 响应。
    {
        "greeting": "Hello there.",
        "goodbye": null,
        "type": "hello"
    }
  • type 改为 goodbye,然后再次调用 Rest 端点。
    https://:8080/greeting/greet?type=goodbye
    {
        "greeting": null,
        "goodbye": "Goodbye for now.",
        "type": "goodbye"
    }
  • type 改为 wrong,然后注意响应。
    https://:8080/greeting/greet?type=wrong
    {
        "greeting": null,
        "goodbye": null,
        "type": "wrong"
    }

    当为 Rest 端点传递错误的 type 值时,响应并不十分有用。此外,由于 greetinggoodbye 都是 null,响应很可能会导致客户端应用程序抛出 NullPointerException。相反,当向端点传递错误值时,我们应该抛出异常。

    顺带一提,是的,HelloGoodbye 的设计很糟糕。返回 null 是糟糕的编程实践。更好的选择是这样做。但是,创建设计良好的 POJO 不是本教程的意图。因此,请继续使用上面设计糟糕的 HelloGoodbye 实现。

    public class HelloGoodbye {
      private String message;
      private String type;
    	
      public String getType() {
        return type;
      }
      public void setType(String type) {
        this.type = type;
      }
      public String getMessage() {
        return message;
      }
      public void setMessage(String msg) {
        this.message = msg;
      }
    }

默认异常处理

Spring Boot 默认提供异常处理。这使得服务终端和客户端能够更容易地在没有复杂编码的情况下通信失败。

  • 修改 createGreeting 方法,如果 type 的值不是 hellogoodbye,则抛出 Exception
    package com.tutorial.exceptions.spring.rest.exceptionstutorial;
    
    import org.springframework.stereotype.Service;
    
    @Service
    public class GreetingService {
    
      public HelloGoodbye createGreeting(String type) throws Exception {
        HelloGoodbye helloGoodbye = new HelloGoodbye();
        if (type.equals("hello")) {
          helloGoodbye.setGreeting("Hello there.");
        } else if (type.equals("goodbye")) {
          helloGoodbye.setGoodbye("Goodbye for now.");
        } else {
          throw new Exception("Valid types are hello or goodbye.");
        }
        helloGoodbye.setType(type);
        return helloGoodbye;
      }
    }
  • 修改 GreetingControllergetGreeting 方法以抛出 Exception
    package com.tutorial.exceptions.spring.rest.exceptionstutorial;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @RequestMapping(value = "/greeting")
    public class GreetingController {
    
      @Autowired
      protected GreetingService service;
    
      @GetMapping("/greet")
      public HelloGoodbye getGreeting(@RequestParam("type") String type) throws Exception {
        HelloGoodbye goodBye = service.createGreeting(type);
        return goodBye;
      }
    }
  • 编译、运行应用程序,然后访问 Rest 端点。注意响应以 JSON 格式返回错误。
    {
        "timestamp": "2019-04-06T18:07:34.344+0000",
        "status": 500,
        "error": "Internal Server Error",
        "message": "Valid types are hello or goodbye.",
        "path": "/greeting/greet"
    }

    当修改 createGreeting 方法时,我们需要捕获异常或抛出异常。这是因为 Exception 是一个受检异常(有关受检异常的更多信息)。但将该异常返回给客户端应用程序作为 JSON 没有特殊要求。这是因为 Spring Boot 为错误提供了一个默认的 JSON 错误消息。相关的类是 DefaultErrorAttributes,它实现了 ErrorAttributes 接口。当发生异常时,此类提供以下属性:timestampstatuserrorexceptionmessageerrorstracepath。你可以轻松地用自己的错误属性类覆盖默认值;但是,此处不演示此技术。有关编写 ErrorAttributes 接口自定义实现的信息,请参阅本教程(使用 ErrorAttributes 自定义错误 JSON 响应)。

    通常,业务逻辑异常需要业务逻辑异常而不是通用异常。让我们修改代码以抛出自定义异常。

  • 创建一个名为 GreetingTypeException 的类,该类扩展 Exception
  • 通过 @ResponseStatus 注解为其分配一个“Bad Request”(错误请求)状态。
    package com.tutorial.exceptions.spring.rest.exceptionstutorial;
    
    import org.springframework.web.bind.annotation.ResponseStatus;
    import org.springframework.http.HttpStatus;
    
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    public class GreetingTypeException extends Exception {
    
      private static final long serialVersionUID = -189365452227508599L;
    
      public GreetingTypeException(String message) {
        super(message);
      }
    
      public GreetingTypeException(Throwable cause) {
        super(cause);
      }
    
      public GreetingTypeException(String message, Throwable cause) 
      {
        super(message, cause);
      }
    }
  • 修改 createGreeting 以抛出 GreetingTypeException 而不是 Exception
    public HelloGoodbye createGreeting(String type) throws GreetingTypeException {
    
      HelloGoodbye helloGoodbye = new HelloGoodbye();
    
      if (type.equals("hello")) {
        helloGoodbye.setGreeting("Hello there.");
      } else if (type.equals("goodbye")) {
        helloGoodbye.setGoodbye("Goodbye for now.");
      } else {
      throw new GreetingTypeException("Valid types are hello or goodbye.");
      }
    
      helloGoodbye.setType(type);
      return helloGoodbye;
    }
  • 编译、运行应用程序,然后访问 Rest 端点。为 type 参数分配一个不正确的值。
    https://:8080/greeting/greet?type=cc
    {
        "timestamp": "2019-03-29T01:54:40.114+0000",
        "status": 400,
        "error": "Bad Request",
        "message": "Valid types are hello or goodbye.",
        "path": "/greeting/greet"
    }
  • 创建一个名为 NameNotFoundException 的异常。让该异常扩展 RuntimeException 而不是 Exception
  • 为其分配“Not Found”(未找到)的响应状态。
    package com.tutorial.exceptions.spring.rest.exceptionstutorial;
    
    import org.springframework.web.bind.annotation.ResponseStatus;
    import org.springframework.http.HttpStatus;
    
    @ResponseStatus(value = HttpStatus.NOT_FOUND)
    public class NameNotFoundException extends RuntimeException {
      public NameNotFoundException(String message) {
        super("The id: " + message + " could not be found.");
      }
    }
  • 修改 GreetingServicecreateGreeting 方法以接受整数类型的 id
  • 创建一个名为 getPersonName 的新方法。暂时放下疑虑,并按如下方式实现它。显然,在真实项目中,你会从数据库、LDAP 服务器或其他数据存储中获取用户信息。
  • 修改 createGreeting 以使用 getPersonName 方法来个性化问候语。
    package com.tutorial.exceptions.spring.rest.exceptionstutorial;
    
    import org.springframework.stereotype.Service;
    
    @Service
    public class GreetingService {
      public HelloGoodbye createGreeting(String type, int id) 
                             throws GreetingTypeException {
        HelloGoodbye helloGoodbye = new HelloGoodbye();
        if (type.equals("hello")) {
          helloGoodbye.setGreeting("Hello there " + 
            this.getPersonName(id));
        } else if (type.equals("goodbye")) {				 
          helloGoodbye.setGoodbye("Goodbye for now " + 
            this.getPersonName(id));
        } else {
          throw new GreetingTypeException("Valid types are hello or goodbye.");
        }
        helloGoodbye.setType(type);
        return helloGoodbye;
      }
    	
      public String getPersonName(int id) {
        if(id==1) {
          return "Tom";
        } else if(id==2) {
          return "Sue";
        } else {
          throw new NameNotFoundException(Integer.toString(id));
        }
      }	
    }
  • 修改 GreetingController 以接受 id 作为请求参数,并修改其对 GreetingServicecreateGreeting 方法的调用,以将 id 也传递给服务。
    package com.tutorial.exceptions.spring.rest.exceptionstutorial;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @RequestMapping(value = "/greeting")
    public class GreetingController {
    
      @Autowired
      protected GreetingService service;
    	
      @GetMapping("/greet")
      public HelloGoodbye getGreeting(@RequestParam("type") String type, 
                   @RequestParam("id") int id) {
        HelloGoodbye goodBye = service.createGreeting(type, id);
          return goodBye;
        }
    }
  • 编译、运行应用程序,然后访问端点。
    https://:8080/greeting/greet?type=hello&id=2
    {
        "greeting": "Hello there Sue",
        "goodbye": null,
        "type": "hello"
    }
  • id 查询参数的值更改为六,然后注意异常。
    https://:8080/greeting/greet?type=hello&id=6
    {
        "timestamp": "2019-03-31T20:30:18.727+0000",
        "status": 404,
        "error": "Not Found",
        "message": "The id: 6 could not be found.",
        "path": "/greeting/greet"
    }

顺带一提,请注意,我们让 NameNotFoundException 扩展了 RuntimeException 而不是 Exception。通过这样做,我们使 NameNotFoundException 成为一个非受检异常(有关非受检异常的更多信息),并且不需要处理该异常。

控制器错误处理器

尽管 Spring Boot 的默认异常处理非常健壮,但有时应用程序可能需要更自定义的错误处理。一种技术是在 Rest 控制器中声明一个异常处理方法。这是使用 Spring 的 @ExceptionHandler 注解来实现的(javadoc)。

  • 创建一个名为 GreetingError 的新简单类。请注意,它是一个 POJO,不扩展 Exception
    package com.tutorial.exceptions.spring.rest.exceptionstutorial;
    
    import java.util.Date;
    
    public class GreetingError {
      private Date timestamp;
      private String message;
        
      public Date getTimestamp() {
        return timestamp;
      }
      public void setTimestamp(Date timestamp) {
        this.timestamp = timestamp;
      }
      public String getMessage() {
        return message;
      }
      public void setMessage(String message) {
        this.message = message;
      }
    }
  • 修改 GreetingController 以拥有一个名为 nameNotFoundException 的方法,该方法被 @ExceptionHandler 注解。
  • 实现 nameNotFoundException 以返回一个 ResponseEntity<>
    package com.tutorial.exceptions.spring.rest.exceptionstutorial;
    
    import java.util.Date;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.context.request.WebRequest;
    
    @RestController
    @RequestMapping(value = "/greeting")
    public class GreetingController {
    
      @Autowired
      protected GreetingService service;
    	
      @GetMapping("/greet")
      public HelloGoodbye getGreeting(@RequestParam("type") String type, 
           @RequestParam("id") int id) throws Exception {
        HelloGoodbye goodBye = service.createGreeting(type, id);
        return goodBye;
      }
    	
      @ExceptionHandler(NameNotFoundException.class)
      public ResponseEntity<?> nameNotFoundException
                (NameNotFoundException ex, WebRequest request) {
        GreetingError errorDetails = new GreetingError();
        errorDetails.setTimestamp(new Date());
        errorDetails.setMessage
           ("This is an overriding of the standard exception: " + ex.getMessage());
        return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
      }
    }
  • 编译、运行应用程序,然后访问端点。
    https://:8080/greeting/greet?type=hello&id=33
    {
        "timestamp": "2019-04-01T02:14:51.744+0000",
        "message": "This is an overriding of the standard exception: 
                    The id: 33 could not be found."
    }

    NameNotFoundException 的默认错误处理在控制器中被覆盖。但是,你并不局限于在控制器中实现一个错误处理器,你可以定义多个错误处理器,如下面的代码所示。

  • 修改 GreetingControllergetGreeting 方法以抛出算术异常。
  • ArithmeticException 创建一个新的异常处理器。
    package com.tutorial.exceptions.spring.rest.exceptionstutorial;
    
    import java.util.Date;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.context.request.WebRequest;
    
    @RestController
    @RequestMapping(value = "/greeting")
    public class GreetingController {
      @Autowired
      protected GreetingService service;
    	
      @GetMapping("/greet")
      public HelloGoodbye getGreeting(@RequestParam("type") String type, 
                   @RequestParam("id") int id) throws Exception {
        int i = 0;
        int k = 22/i;
        HelloGoodbye goodBye = service.createGreeting(type, id);
        return goodBye;
      }
    	
      @ExceptionHandler(NameNotFoundException.class)
      public ResponseEntity<?> nameNotFoundException
                 (NameNotFoundException ex, WebRequest request) {
        GreetingError errorDetails = new GreetingError();
        errorDetails.setTimestamp(new Date());
        errorDetails.setMessage("This is an overriding of the standard exception: 
                                " + ex.getMessage()); 
        return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
      }
    	 
      @ExceptionHandler(ArithmeticException.class)
      public ResponseEntity<?> arithmeticException
               (ArithmeticException ex, WebRequest request) {
        GreetingError errorDetails = new GreetingError();
        errorDetails.setTimestamp(new Date());
        errorDetails.setMessage("This is an overriding of the standard exception: 
                   " + ex.getMessage()); 
        return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
      }
    }
  • 编译、运行应用程序,然后访问 Rest 端点。
    {
        "timestamp": "2019-04-01T02:40:53.527+0000",
        "message": "This is an overriding of the standard exception: / by zero"
    }
  • 在继续之前,不要忘记删除除零的代码。

    异常处理器是一个有用的注解,它允许在类中处理异常。我们在控制器中使用了它来处理异常。用于处理异常的方法返回了一个 ResponseEntity<T> 类(javadoc)。此类是 HttpEntityjavadoc)的子类。HttpEntity 包装实际的请求或响应——这里是响应——而 ResponseEntity 添加了 HttpStatus 代码。这允许你从 Rest 端点返回自定义响应。

全局错误处理器

@ControllerAdvice 是一个在 Spring Controllers 中处理异常的方法。它允许使用带有 @ExceptionHandler 注解的方法来处理应用程序中的所有异常。

package com.tutorial.exceptions.spring.rest.exceptionstutorial;

import java.util.Date;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;

@ControllerAdvice
public class GreetingExceptionHandler {
  @ExceptionHandler(NameNotFoundException.class)
  public ResponseEntity<?> nameNotFoundException
         (NameNotFoundException ex, WebRequest request) {
    GreetingError errorDetails = new GreetingError();
    errorDetails.setTimestamp(new Date());
    errorDetails.setMessage("This a global exception handler: " + ex.getMessage());
    return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
    }
}
  • 创建一个名为 GreetingExceptionHandler 的新类。
  • @ControllerAdvice 注解对其进行注释。
  • nameNotFoundException 方法从 GreetingController 类复制粘贴过来。更改消息文本,以确保它确实被调用了。
  • GreetingController 类中移除 NameNotFoundException 异常处理器。
    package com.tutorial.exceptions.spring.rest.exceptionstutorial;
    
    import java.util.Date;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.context.request.WebRequest;
    
    @RestController
    @RequestMapping(value = "/greeting")
    public class GreetingController {
    	
      @Autowired
      protected GreetingService service;
    	
      @GetMapping("/greet")
      public HelloGoodbye getGreeting(@RequestParam("type") String type, 
                     @RequestParam("id") int id) throws Exception {
        HelloGoodbye goodBye = service.createGreeting(type, id);
        return goodBye;
      }
    	 
      @ExceptionHandler(ArithmeticException.class)
      public ResponseEntity<?> arithmeticException
          (ArithmeticException ex, WebRequest request) {
        GreetingError errorDetails = new GreetingError();
        errorDetails.setTimestamp(new Date());
        errorDetails.setMessage("This is an overriding of the standard exception: 
                                " + ex.getMessage());
        return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
      }	 
    }
  • 编译、运行应用程序,然后访问 Rest 端点。你收到了全局处理器中创建的错误。
    https://:8080/greeting/greet?type=hello&id=33
    {
    “timestamp”: “2019-04-06T21:21:17.258+0000”,
    “message”: “This a global exception handler: The id: 33 could not be found.”
    }

    @ControllerAdvice 注解(Javadoc)允许跨控制器共享异常处理器。如果你希望在多个控制器之间创建统一的异常处理,它会很有用。你可以将 @ControllerAdvice 异常处理限制为仅适用于某些控制器,有关更多信息,请参阅 Javadoc。

结论

Spring 异常处理既简单又困难。简单是因为有具体的方法来实现异常处理。而且,即使你没有提供任何异常处理,Spring 也会默认为你提供。困难是因为有许多不同的方法可以实现异常处理。Spring 提供了如此多的自定义选项,如此多的不同技术,有时很容易迷失在细节中。

在本教程中,我们探讨了在使用 Spring Boot 2.1 Rest 时使用的三种不同技术。你应该参考其他教程,然后再决定哪一种技术是你应该使用的。为了完全披露,我个人认为 @ControllerAdvice 技术是最健壮的,因为它允许创建统一的异常处理框架。

GitHub 项目

https://github.com/jamesabrannan/spring-rest-exception-tutorial

 

© . All rights reserved.