【问题标题】:Spring Boot 1.4.3 and @ControllerAdviceSpring Boot 1.4.3 和 @ControllerAdvice
【发布时间】:2018-04-07 12:55:10
【问题描述】:

我有一个 Spring 4 应用程序,它带有一个扩展 ResponseEntityExceptionHandler 的 ControllerAdvice,当异常出现时可以正常工作。

@ControllerAdvice
@Slf4j
public class ExceptionManager extends ResponseEntityExceptionHandler {

    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
                                                                  HttpHeaders headers,
                                                                  HttpStatus status,
                                                                  WebRequest request) {
        final ValidationErrors errors = getErrors(ex.getBindingResult());
        headers.setContentType(MediaType.APPLICATION_JSON);
        return handleExceptionInternal(ex, errors, headers, HttpStatus.BAD_REQUEST, request);
    }


    @Override
    protected ResponseEntity<Object> handleBindException(BindException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        final ValidationErrors errors = getErrors(ex.getBindingResult());
        headers.setContentType(MediaType.APPLICATION_JSON);
        return handleExceptionInternal(ex, errors, headers, HttpStatus.BAD_REQUEST, request);
    }

    @ExceptionHandler(ValidationException.class)
    public ResponseEntity handleValidationException(ValidationException ex) {
        log.warn("Validation error", ex);
        return ex.toResponseEntity();
    }

    @ExceptionHandler(HttpClientErrorException.class)
    public ResponseEntity handleHttpClientErrorException(HttpClientErrorException ex) {
        log.error(ex.getMessage());
        return new ResponseEntity(ex.getResponseBodyAsString(), ex.getStatusCode());
    }

    @ExceptionHandler({Exception.class, RuntimeException.class})
    protected ResponseEntity<Object> handleRootException(Exception ex, WebRequest request) {
        return handleException(request, ex);
    }

...
}

但是,在 unmarshaller 异常的情况下,例如

Exception received: 
org.springframework.http.converter.HttpMessageNotReadableException: Could not unmarshal to [class com.company.etc.v1.PojoResponse]: null; nested exception is javax.xml.bind.UnmarshalException
 - with linked exception:
[org.xml.sax.SAXParseException; lineNumber: 5; columnNumber: 28; Attribute name "entResponse" associated with an element type "assetDocum" must be followed by the ' = ' character.]
    at org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter.readFromSource(Jaxb2RootElementHttpMessageConverter.java:149)
    at org.springframework.http.converter.xml.AbstractXmlHttpMessageConverter.readInternal(AbstractXmlHttpMessageConverter.java:61)
    at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:193)
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:104)
    at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:917)
    at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:901)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:655)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613)
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:531)
    at com.company.service.impl.SearchAsset.searchAssets(SearchAsset.java:42)
    ... 57 common frames omitted
Caused by: javax.xml.bind.UnmarshalException: null
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.createUnmarshalException(AbstractUnmarshallerImpl.java:335)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.createUnmarshalException(UnmarshallerImpl.java:563)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:249)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:214)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:140)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:123)
    at org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter.readFromSource(Jaxb2RootElementHttpMessageConverter.java:133)
    ... 127 common frames omitted
Caused by: org.xml.sax.SAXParseException: Attribute name "entResponse" associated with an element type "assetDocum" must be followed by the ' = ' character.
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:203)
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:177)
    ... 131 common frames omitted

异常没有被捕获! 它发生在特定情况下,当 @RestController 使用调用外部端点的服务时。在我的情况下,外部服务返回一个 XML,如果它被破坏(如上面的异常),那么 SAXParseException 不会被捕获并在春季自动转换为 400 错误请求,主体为空。它也根本没有记录。

如果我在我的 RestController 中添加了一个方法 @ExceptionHandler(Throwable.class),这个方法会被调用,我可以控制返回的错误。

这正常吗?我在想 ControllerAdvice 可以集中所有的异常处理,不需要在每个控制器中都有 ExceptionHandler。

【问题讨论】:

  • inside handleRootExceptioninside 方法传递 Throwable 而不是 Exception ex。
  • @VinayPrajapati 我已将其更新为@ExceptionHandler(Throwable.class) @ResponseBody public ResponseEntity handleRootException(Throwable ex, WebRequest req) { log.error("Exception received: ", ex); return new ResponseEntity(ex, HttpStatus.INTERNAL_SERVER_ERROR); },但仍未调用,因此如果放置在控制器中,此确切代码可以工作
  • 您没有打印整个异常堆栈跟踪,'caused by' 表示它是一个包装的异常,而不是实际抛出的顶级异常。
  • @Gimby 我在控制器中使用@ExceptionHandler 时添加了完整堆栈。仅供参考,XML 响应被中断,在标签中间有一行返回以引发异常。
  • 所以实际可捕获的异常是HttpMessageNotReadableException;如果您不专门处理它,则应调用通用的 handleRootException()。这没有发生?

标签: java spring-mvc spring-boot-actuator


【解决方案1】:

刚刚找到解决方案:删除extends ResponseEntityExceptionHandler。如果你 @ControllerAdvice 不扩展任何东西,看起来效果会更好。

【讨论】:

  • 其实这不是一个正确的解决方案。它确实会捕获SAXParseException,但它不再捕获其他一些,例如MethodArgumentNotValidException(我猜是因为ResponseEntityExceptionHandler.handleMethodArgumentNotValid 不再被覆盖
  • 是的,确实,定义带有@ExceptionHandler(MethodArgumentNotValidException.class) 注释的方法时的事件没有被捕获。嗯,还是比以前好多了……
猜你喜欢
  • 2020-06-05
  • 1970-01-01
  • 2023-03-30
  • 2020-01-17
  • 2017-05-11
  • 2021-12-11
  • 2017-06-21
  • 2017-01-23
  • 1970-01-01
相关资源
最近更新 更多