原文: https://howtodoinjava.com/spring-restful/exception-handling-example/

在使用 Spring REST 模块创建的 REST API 中学习处理异常(请求验证,错误数据或其他请求处理错误)。 我们将研究一种使用@ControllerAdvice@ExceptionHandler的方法。

要使用@ControllerAdvice全局处理 REST 异常,我们需要遵循以下步骤。

1. 使用@ControllerAdvice@ExceptionHandler创建处理器

  • @ControllerAdvice注解是@Component注解的特化,其方法(以@ExceptionHandler注解)在全球范围内跨多个@Controller类共享。
  • 通过类路径扫描自动检测带有@ControllerAdvice的类。
  • 使用选择器annotations()basePackageClasses()basePackages()定义目标控制器的更窄子集。
  • 我们可以在选择器中应用 OR 运算符,即如果遇到给定异常中的任何一个,则将执行给定方法。

请注意,ResponseEntityExceptionHandler@ControllerAdvice类的便捷基类,这些类希望通过@ExceptionHandler方法跨所有@RequestMapping方法提供集中的异常处理

CustomExceptionHandler.java

  1. import java.util.ArrayList;
  2. import java.util.List;
  3. import org.springframework.http.HttpStatus;
  4. import org.springframework.http.ResponseEntity;
  5. import org.springframework.web.bind.annotation.ControllerAdvice;
  6. import org.springframework.web.bind.annotation.ExceptionHandler;
  7. import org.springframework.web.context.request.WebRequest;
  8. import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
  9. @ControllerAdvice
  10. public class CustomExceptionHandler extends ResponseEntityExceptionHandler
  11. {
  12. private String INCORRECT_REQUEST = "INCORRECT_REQUEST";
  13. private String BAD_REQUEST = "BAD_REQUEST";
  14. @ExceptionHandler(RecordNotFoundException.class)
  15. public final ResponseEntity<ErrorResponse> handleUserNotFoundException
  16. (RecordNotFoundException ex, WebRequest request)
  17. {
  18. List<String> details = new ArrayList<>();
  19. details.add(ex.getLocalizedMessage());
  20. ErrorResponse error = new ErrorResponse(INCORRECT_REQUEST, details);
  21. return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
  22. }
  23. @ExceptionHandler(MissingHeaderInfoException.class)
  24. public final ResponseEntity<ErrorResponse> handleInvalidTraceIdException
  25. (MissingHeaderInfoException ex, WebRequest request) {
  26. List<String> details = new ArrayList<>();
  27. details.add(ex.getLocalizedMessage());
  28. ErrorResponse error = new ErrorResponse(BAD_REQUEST, details);
  29. return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
  30. }
  31. }

2. 创建异常模型类

我们需要识别业务异常用例,并用异常类来表示它们。 这些类将扩展RuntimeException类。 也可以根据需要随意创建更多错误响应表示。

MissingHeaderInfoException.java

  1. import org.springframework.http.HttpStatus;
  2. import org.springframework.web.bind.annotation.ResponseStatus;
  3. @ResponseStatus(HttpStatus.BAD_REQUEST)
  4. public class MissingHeaderInfoException extends RuntimeException
  5. {
  6. private static final long serialVersionUID = 1L;
  7. public MissingHeaderInfoException(String message) {
  8. super(message);
  9. }
  10. }

RecordNotFoundException.java

  1. import org.springframework.http.HttpStatus;
  2. import org.springframework.web.bind.annotation.ResponseStatus;
  3. @ResponseStatus(HttpStatus.NOT_FOUND)
  4. public class RecordNotFoundException extends RuntimeException
  5. {
  6. private static final long serialVersionUID = 1L;
  7. public RecordNotFoundException(String message) {
  8. super(message);
  9. }
  10. }

ErrorResponse.java

  1. import java.util.List;
  2. public class ErrorResponse
  3. {
  4. public ErrorResponse(String message, List<String> details) {
  5. super();
  6. this.message = message;
  7. this.details = details;
  8. }
  9. private String message;
  10. private List<String> details;
  11. //getters and setters
  12. }

3. 配置视图解析器

如果尚未完成,我们需要配置视图解析器以将异常消息转换为 XML 或 JSON 形式。

在 Spring Boot 中,此配置是自动完成的。 没有 SpringBoot,我们需要像下面这样。

重要说明:确保已启用mvc: annotation-driven配置,或已使用@EnableWebMvc注解。

rest-servlet.xml

  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
  3. xmlns:mvc="http://www.springframework.org/schema/mvc"
  4. xmlns:jpa="http://www.springframework.org/schema/data/jpa"
  5. xmlns:tx="http://www.springframework.org/schema/tx"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans
  7. http://www.springframework.org/schema/beans/spring-beans.xsd
  8. http://www.springframework.org/schema/context
  9. http://www.springframework.org/schema/context/spring-context.xsd
  10. http://www.springframework.org/schema/data/jpa
  11. http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd
  12. http://www.springframework.org/schema/tx
  13. http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
  14. http://www.springframework.org/schema/mvc
  15. http://www.springframework.org/schema/mvc/spring-mvc.xsd">
  16. <mvc:annotation-driven />
  17. <context:component-scan base-package="com.howtodoinjava.demo" />
  18. <mvc:view-resolvers>
  19. <mvc:content-negotiation>
  20. <mvc:default-views>
  21. <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
  22. </mvc:default-views>
  23. </mvc:content-negotiation>
  24. </mvc:view-resolvers>
  25. <!-- JPA Config -->
  26. </beans>

4. REST 控制器更改

从 rest 控制器处理器方法中,我们需要抛出要转换并作为响应发送给 API 使用者的异常。 在这种情况下,如果id搜索了一个雇员并且该雇员在数据库中不存在,我们将发送RecordNotFoundException

EmployeeRESTController.java

  1. @GetMapping("/employees/{id}")
  2. Employee getEmployeeById(@PathVariable Long id)
  3. {
  4. return repository.findById(id)
  5. .orElseThrow(() -> new RecordNotFoundException("Employee id '" + id + "' does no exist"));
  6. }

5. Spring REST 异常处理演示

尝试按 ID(在数据库中不存在 ID)获取员工。

API Request

  1. HTTP GET : http://localhost:8080/SpringRestExample/api/rest/employee-management/employees/101

API Response

  1. {
  2. "message": "INCORRECT_REQUEST",
  3. "details": [
  4. "Employee id '101' does no exist"
  5. ],
  6. }

请把关于 Spring Rest API 中的异常处理的问题交给我。

学习愉快!

下载源码