Spring Boot 1.4.3和@ControllerAdvice

时间:2017-10-26 08:26:59

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

我有一个带有ControllerAdvice的spring 4应用程序,它扩展了ResponseEntityExceptionHandler,当异常上升时可以正常工作。

@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 Bad Request by spring。它根本没有记录。

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

这是正常的吗?我认为ControllerAdvice可以集中所有异常处理,无需在每个控制器中安装ExceptionHandler。

1 个答案:

答案 0 :(得分:1)

刚找到解决方案:删除extends ResponseEntityExceptionHandler。如果@ControllerAdvice没有扩展任何内容,它看起来效果会更好。