![](/img/trans.png)
[英]Spring Boot @RestControllerAdvice not Catching Custom Exceptions
[英]Spring Boot: RestControllerAdvice: handle wrapped exceptions
假设我们有@RestControllerAdvice
-annotated class 像这样:
@RestControllerAdvice
public class RestResponseExceptionHandler {
@ExceptionHandler(MyBusinessException .class)
public ResponseEntity<ErrorResponse> handleMyBusinessException (MyBusinessException ex) {
return createResponseEntity(ex, ex.getErrorCode());
}
@ExceptionHandler({IllegalArgumentException.class, ValidationException.class, DataIntegrityViolationException.class})
public ResponseEntity<ErrorResponse> handleInvalidPropertyException(RuntimeException ex) {
return createResponseEntity(ex, ErrorCode.DATA_INVALID);
}
[...]
@ExceptionHandler(RuntimeException.class)
public ResponseEntity<ErrorResponse> handleRuntimeException(RuntimeException ex) {
return createResponseEntity(ex, ErrorCode.UNKNOWN);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleException(Exception ex) {
return createResponseEntity(ex, ErrorCode.UNKNOWN);
}
@ExceptionHandler(WrapperException .class)
public ResponseEntity<ErrorResponse> handleWrapperException (WrapperException ex) {
Exception exception = ex.getWrappedException();
// re-dispatch exception here
}
}
对于已知的WrapperException
,是否有可能以某种方式重新调度包装的异常?
我尝试了几件事,例如重新抛出包装的 excption 或显式调用我们的 ErrorController 的自定义方法并在那里重新抛出异常,但到目前为止没有运气。
为什么要重新抛出可能会产生不必要的分支。 您可以进行条件检查并调用适当的异常处理程序方法,如下所示。
@ExceptionHandler(WrapperException .class)
public ResponseEntity<ErrorResponse> handleWrapperException (WrapperException ex) {
Exception exception = ex.getWrappedException();
if (exception instanceof MyBusinessException) {
return handleMyBusinessException((MyBusinessException) exception);
}
return //Default
}
我想我想出了春天的方式来做到这一点。 您可以在这种类型的RestResponseExceptionHandler
bean 中自动装配 - HandlerExceptionResolver
。 Spring 为您自动配置其中的一些,我设法使它与这个 - handlerExceptionResolver
工作。 像这样的东西:
@ControllerAdvice
public class ErrorHandler {
private final HandlerExceptionResolver resolver;
@Autowired
public ErrorHandler(@Qualifier("handlerExceptionResolver") HandlerExceptionResolver resolver) {
this.resolver = resolver;
}
//that's the wrapped exception handler from your case
@ExceptionHandler(Exception.class)
public void exception(Exception exception, HttpServletRequest request, HttpServletResponse response) {
//get the wrapped exception
Exception wrappedException = (Exception) exception.getCause();
//this will dispatch the handling to the handler for the wrapped exception
this.resolver.resolveException(request, response, null, wrappedException);
}
@ExceptionHandler(IndexOutOfBoundsException.class)
public ResponseEntity<Object> indexOutOfBoundsException() {
return ResponseEntity.of(Optional.of("IndexOutOfBoundsException"));
}
@ExceptionHandler(NullPointerException.class)
public ResponseEntity<Object> runtimeException() {
return ResponseEntity.of(Optional.of("NullPointerException"));
}
@ExceptionHandler(IOException.class)
public ResponseEntity<Object> ioException() {
return ResponseEntity.of(Optional.of("IOException"));
}
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<Object> illegalArgumentException() {
return ResponseEntity.of(Optional.of("IllegalArgumentException"));
}
}
您必须在包装的异常处理程序中使用请求和响应,否则将无法处理它。 当您使用包装的异常调用resolveException()
时,它会将其重新路由到包装异常的正确处理程序。 我使用 controller 进行了一些测试,以抛出类似这样的异常,一切都得到了正确解决。
@Controller
public class ExcController {
@GetMapping("/thr")
public String throwExc() throws Exception {
throw new Exception(new NullPointerException());
}
@GetMapping("/thr2")
public String throwExc2() throws Exception {
throw new IOException();
}
}
从@ExceptionHandler
5.3 开始,@ExceptionHandler 在尝试查找匹配项时已经查看了cause
异常。 因此,如果您使用的是最近的 Spring 版本,您可以删除您的@ExceptionHandler(WrapperException.class)
方法,它应该可以按预期工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.