Spring 中的自定义 @ControllerAdvice 用于异常处理
Custom @ControllerAdvice in Spring for exception handling
我正在尝试将我的其余控制器的异常映射到具有正文的响应,并在一个中心位置进行。
我试过这个:
@Order(Ordered.HIGHEST_PRECEDENCE)
@ControllerAdvice
public class RestErrorResponseExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleExceptionInternal(
Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {
super.handleExceptionInternal(ex, body, headers, status, request);
return ResponseEntity.status(status).body(Error.from(status));
}
}
问题是从未触发处理程序。
如果我在其余控制器中使用 @ExceptionHandler
定义自定义方法,或扩展具有 @ExceptionHandler
的方法,则一切正常,但引入了一些糟糕的设计。
据我了解,Spring 将首先尝试在控制器中查找异常处理方法,然后检查已注册的处理程序。
我正在尝试通过 WebMvcTest 验证行为,但我得到的响应不是我期望的错误对象。
有什么我遗漏的吗?
ControllerAdvice 是必须由 Spring 注册的配置。你必须把你的class移到config包里或者你可以注解注册
就我而言,我使用这样的 controllerAdvice :
@ControllerAdvice
public class GlobalControllerExceptionHandler {
@ExceptionHandler(MyException.class)
public ResponseEntity<String> reponseMyException(Exception e) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("my message");
}
}
确保两件事,您的代码就能正常工作。
- 您的
@ControllerAdvice
class 在组件扫描路径中可用。
- 确保您
@ControllerAdvice
中的方法具有类似这样的结构-
@ExceptionHandler(value = { RequestProcessingException.class })
public @ResponseBody ResponseEntity<ErrorMessageBO> hotelConfigServiceExceptionHandler(HttpServletRequest request, RequestProcessingException e) {
logger.error("Exception with tracking Id: {}, dev message: {} and Message:", RequestContextKeeper.getContext().getRequestId(), e.getDeveloperMessage(),e);
return new ResponseEntity<ErrorMessageBO>(new ErrorMessageBO(e.getErrorCode(), e.getMessage(),RequestContextKeeper.getContext().getRequestId(),e.getDeveloperMessage()), HttpStatus.OK);
}
Spring 框架提供了以下方法来帮助我们实现健壮的异常处理。
基于控制器 – 我们可以在我们的控制器中定义异常处理程序方法classes。我们只需要用@ExceptionHandler 注解来注解这些方法。此注释将 Exception class 作为参数。因此,如果我们为 Exception class 定义了其中之一,那么我们的请求处理程序方法抛出的所有异常都将得到处理。
这些异常处理方法就像其他请求处理方法一样,我们可以构建错误响应并使用不同的错误页面进行响应。我们还可以发送 JSON 错误响应,我们将在稍后的示例中查看。
如果定义了多个异常处理程序方法,则使用最接近异常 class 的处理程序方法。例如,如果我们为 IOException 和 Exception 定义了两个处理程序方法,并且我们的请求处理程序方法抛出 IOException,那么将执行 IOException 的处理程序方法。
Global Exception Handler – 异常处理是一个横切关注点,它应该为我们应用程序中的所有切入点完成。我们已经研究了 Spring AOP,这就是为什么 Spring 提供了 @ControllerAdvice 注释,我们可以将其与任何 class 一起使用来定义我们的全局异常处理程序。
Global Controller Advice 中的处理方法与基于控制器的异常处理方法相同,并在控制器 class 无法处理异常时使用。
HandlerExceptionResolver – 对于一般异常,大多数时候我们提供静态页面。 Spring 框架提供了 HandlerExceptionResolver 接口,我们可以实现它来创建全局异常处理程序。这种定义全局异常处理程序的额外方式背后的原因是 Spring 框架还提供了默认实现 classes 我们可以在我们的 spring bean 配置文件中定义以获得 spring框架异常处理的好处。
SimpleMappingExceptionResolver 是默认实现 class,它允许我们配置 exceptionMappings,我们可以在其中指定用于特定异常的资源。我们还可以重写它以使用我们的应用程序特定更改创建我们自己的全局处理程序,例如记录异常消息。
我正在尝试将我的其余控制器的异常映射到具有正文的响应,并在一个中心位置进行。
我试过这个:
@Order(Ordered.HIGHEST_PRECEDENCE)
@ControllerAdvice
public class RestErrorResponseExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleExceptionInternal(
Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {
super.handleExceptionInternal(ex, body, headers, status, request);
return ResponseEntity.status(status).body(Error.from(status));
}
}
问题是从未触发处理程序。
如果我在其余控制器中使用 @ExceptionHandler
定义自定义方法,或扩展具有 @ExceptionHandler
的方法,则一切正常,但引入了一些糟糕的设计。
据我了解,Spring 将首先尝试在控制器中查找异常处理方法,然后检查已注册的处理程序。
我正在尝试通过 WebMvcTest 验证行为,但我得到的响应不是我期望的错误对象。
有什么我遗漏的吗?
ControllerAdvice 是必须由 Spring 注册的配置。你必须把你的class移到config包里或者你可以注解注册
就我而言,我使用这样的 controllerAdvice :
@ControllerAdvice
public class GlobalControllerExceptionHandler {
@ExceptionHandler(MyException.class)
public ResponseEntity<String> reponseMyException(Exception e) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("my message");
}
}
确保两件事,您的代码就能正常工作。
- 您的
@ControllerAdvice
class 在组件扫描路径中可用。 - 确保您
@ControllerAdvice
中的方法具有类似这样的结构-
@ExceptionHandler(value = { RequestProcessingException.class })
public @ResponseBody ResponseEntity<ErrorMessageBO> hotelConfigServiceExceptionHandler(HttpServletRequest request, RequestProcessingException e) {
logger.error("Exception with tracking Id: {}, dev message: {} and Message:", RequestContextKeeper.getContext().getRequestId(), e.getDeveloperMessage(),e);
return new ResponseEntity<ErrorMessageBO>(new ErrorMessageBO(e.getErrorCode(), e.getMessage(),RequestContextKeeper.getContext().getRequestId(),e.getDeveloperMessage()), HttpStatus.OK);
}
Spring 框架提供了以下方法来帮助我们实现健壮的异常处理。
基于控制器 – 我们可以在我们的控制器中定义异常处理程序方法classes。我们只需要用@ExceptionHandler 注解来注解这些方法。此注释将 Exception class 作为参数。因此,如果我们为 Exception class 定义了其中之一,那么我们的请求处理程序方法抛出的所有异常都将得到处理。 这些异常处理方法就像其他请求处理方法一样,我们可以构建错误响应并使用不同的错误页面进行响应。我们还可以发送 JSON 错误响应,我们将在稍后的示例中查看。 如果定义了多个异常处理程序方法,则使用最接近异常 class 的处理程序方法。例如,如果我们为 IOException 和 Exception 定义了两个处理程序方法,并且我们的请求处理程序方法抛出 IOException,那么将执行 IOException 的处理程序方法。
Global Exception Handler – 异常处理是一个横切关注点,它应该为我们应用程序中的所有切入点完成。我们已经研究了 Spring AOP,这就是为什么 Spring 提供了 @ControllerAdvice 注释,我们可以将其与任何 class 一起使用来定义我们的全局异常处理程序。 Global Controller Advice 中的处理方法与基于控制器的异常处理方法相同,并在控制器 class 无法处理异常时使用。
HandlerExceptionResolver – 对于一般异常,大多数时候我们提供静态页面。 Spring 框架提供了 HandlerExceptionResolver 接口,我们可以实现它来创建全局异常处理程序。这种定义全局异常处理程序的额外方式背后的原因是 Spring 框架还提供了默认实现 classes 我们可以在我们的 spring bean 配置文件中定义以获得 spring框架异常处理的好处。 SimpleMappingExceptionResolver 是默认实现 class,它允许我们配置 exceptionMappings,我们可以在其中指定用于特定异常的资源。我们还可以重写它以使用我们的应用程序特定更改创建我们自己的全局处理程序,例如记录异常消息。