我正在尝试将休息控制器中的异常映射到具有主体的响应,并在中心位置执行此操作。
我试过这个:
@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 验证行为,并且我收到的响应不是我期望的 Error 对象。
我有什么遗漏的吗?
ControllerAdvice是一个必须由Spring注册的配置。您必须将您的类移动到配置包中,或者您可以通过注释注册它。
就我而言,我使用像这样的controllerAdvice:
@ControllerAdvice
public class GlobalControllerExceptionHandler {
@ExceptionHandler(MyException.class)
public ResponseEntity<String> reponseMyException(Exception e) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("my message");
}
}
Spring框架提供了以下方法来帮助我们实现健壮的异常处理。
基于控制器 – 我们可以在控制器类中定义异常处理程序方法。我们需要做的就是用 @ExceptionHandler 注解来注解这些方法。该注释将 Exception 类作为参数。因此,如果我们为 Exception 类定义了其中之一,那么我们的请求处理程序方法抛出的所有异常都将得到处理。 这些异常处理程序方法就像其他请求处理程序方法一样,我们可以构建错误响应并使用不同的错误页面进行响应。我们还可以发送 JSON 错误响应,稍后我们将在示例中查看。 如果定义了多个异常处理程序方法,则使用最接近 Exception 类的处理程序方法。例如,如果我们为 IOException 和 Exception 定义了两个处理程序方法,并且我们的请求处理程序方法抛出 IOException,则 IOException 的处理程序方法将被执行。
全局异常处理程序 – 异常处理是一个横切关注点,应该对我们应用程序中的所有切入点进行处理。我们已经研究了 Spring AOP,这就是 Spring 提供 @ControllerAdvice 注释的原因,我们可以将其与任何类一起使用来定义全局异常处理程序。 Global Controller Advice 中的处理程序方法与基于控制器的异常处理程序方法相同,并在控制器类无法处理异常时使用。
HandlerExceptionResolver – 对于通用异常,大多数时候我们提供静态页面。 Spring框架提供了HandlerExceptionResolver接口,我们可以实现它来创建全局异常处理程序。这种定义全局异常处理程序的额外方法背后的原因是 Spring 框架还提供了默认实现类,我们可以在 spring bean 配置文件中定义这些类,以获得 spring 框架异常处理的好处。 SimpleMappingExceptionResolver 是默认的实现类,它允许我们配置异常映射,在其中我们可以指定针对特定异常使用哪个资源。我们还可以重写它,以使用特定于应用程序的更改(例如记录异常消息)来创建我们自己的全局处理程序。
确保满足两件事,您的代码就能正常工作。
@ControllerAdvice
类在组件扫描路径中可用。@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);
}