繁体   English   中英

Spring 引导:RestControllerAdvice:处理包装异常

[英]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)方法,它应该可以按预期工作。

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/ExceptionHandler.ZFC35FDC70D5FC69D2269EZ83A82

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM