我已經閱讀了Spring Boot的官方教程和Stack Overflow的幾個帖子,包括這個,嘗試了@Ordered(Order=HIGHEST_PRECEDENCE),但是除了ConstraintViolationException.class以外的任何例外都被DefaultHandlerExceptionResolver
VERSIONS
- Spring Boot - 2.5.3 。
- Spring - 5.3.9 。
問題
我希望MyRestController中的任何例外都能被我定義的ControllerAdvice中的處理程式所處理,這樣我就能在發送給客戶端之前對回應物件進行操作。
@Validated
@RestController
@RequestMapping(value = "/myctx", produces = MediaType.APPLICATION_JSON_VALUE)
public class MyRestController {
private static final Logger logger = LoggerFactory. getLogger(MyRestController)。
@RequestMapping(
path = "/{element}"。
method = RequestMethod.POST。
消耗 = MediaType.APPLICATION_JSON_VALUE。
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ApiResponse> findAndSave()
@Allowed(values = { "a1"/span>, "a2"/span>, "a3"/span> }) @PathVariable String元素。
@ValidateMetadata @RequestBody Metadata metadata) {
...
...
}
我定義的注解@Allowed和@ValidateMetadata如期作業
@ControllerAdvice
//@Order(Ordered.HIGHEST_PRECEDENCE)
public class ErrorControllerAdvice extends ResponseEntityExceptionHandler{
private static final Logger logger = LoggerFactory. getLogger(ErrorControllerAdvice.class)。
@ExceptionHandler({ ConstraintViolationException.class })
public ResponseEntity<Object> handleConstraintViolationException(ConstraintViolationException ex, WebRequest request) {
ApiResponse apiResponse = ApiResponse.builder()
.timestamp(new Date()
.status(HttpStatus.BAD_REQUEST)
.message(ex.getLocalizedMessage())
.path(((ServletWebRequest) request).getRequest().getRequestURI()
//.metadata(metadata)。
.build()。
return handleExceptionInternal(ex, apiResponse, new HttpHeaders(), apiResponse.getStatus(), request) 。
}
@ExceptionHandler({ Exception.class })
public ResponseEntity<Object> handleAll(Exception ex, WebRequest request) throws Exception {
ResponseEntity<Object> tmpResponse = super.handleException(ex, request)。
ResponseEntity<Object> response = new ResponseEntity< >("來自catch-all例外處理器的回應", tmpResponse. getHeaders(), tmpResponse.getStatusCode())。
return回應。
}
在這一點上,當我用POST請求測驗我的端點并注入一個ContraintViolation時,我的自定義錯誤回應被發送到客戶端。然而,對于任何其他的例外,handleAll()方法在ErrorControllerAdvice甚至不被呼叫。例如,從測驗代碼中,我嘗試發送一個GET而不是POST,或者改變URI以包含myct而不是myctx
為什么它不作業?為什么在上述情況下我會得到默認的錯誤資訊?
更新
我甚至嘗試從控制器方法中拋出一個NullPointerException,但這也沒有呼叫handleAll()方法。
uj5u.com熱心網友回復:
你的實作是錯誤的,handleException方法將只處理@ExceptionHandler注解中定義的例外
@ExceptionHandler({
HttpRequestMethodNotSupportedException.class,
HttpMediaTypeNotSupportedException.class。
HttpMediaTypeNotAcceptableException.class,
MissingPathVariableException.class,
MissingServletRequestParameterException.class,
ServletRequestBindingException.class。
ConversionNotSupportedException.class。
TypeMismatchException.class。
HttpMessageNotReadableException.class,
HttpMessageNotWritableException.class,
MethodArgumentNotValidException.class,
MissingServletRequestPartException.class,
BindException.class。
NoHandlerFoundException.class。
AsyncRequestTimeoutException.class。
})
因此,這幾行代碼將總是拋出一個例外。
try {
tmpResponse = super.handleException(ex, request) 。
} catch (Exception handlerEx) {
logger.error(handlerEx.getMessage(), handlerEx)。
這個想法是個錯誤:
這個想法是個錯誤。
因為我是從ResourceEntityExceptionHandler擴展而來,所以所有的例外都是由該類中的handleException()方法處理的。
uj5u.com熱心網友回復:
ResponseEntityExceptionHandler處理了很多的例外,所以handleAll將只處理那些不包括在ResponseEntityExceptionHandler中的例外,你可以在ResponseEntityExceptionHandler里面的handleException方法中添加一個斷點,看看它是否在捕捉例外。你可以做的另一件事是在findAndSave中拋出一個RuntimeException,并檢查它是否被handleAll所處理。
@ExceptionHandler({
HttpRequestMethodNotSupportedException.class,
HttpMediaTypeNotSupportedException.class。
HttpMediaTypeNotAcceptableException.class,
MissingPathVariableException.class,
MissingServletRequestParameterException.class,
ServletRequestBindingException.class。
ConversionNotSupportedException.class。
TypeMismatchException.class。
HttpMessageNotReadableException.class,
HttpMessageNotWritableException.class,
MethodArgumentNotValidException.class,
MissingServletRequestPartException.class,
BindException.class。
NoHandlerFoundException.class。
AsyncRequestTimeoutException.class。
})
uj5u.com熱心網友回復:
我能夠自己解決這個問題。我又細細地看了一遍這里發布的細節。設定多個@ControllerAdvice @ExceptionHandlers的優先級
這就是我的@ControllerAdvice Bean現在的樣子,讓我有能力為Rest Controller拋出的任何例外縫合一個自定義ApiResponse物件。
@RestControllerAdvice
public class ErrorControllerAdvice extends ResponseEntityExceptionHandler {
private static final Logger logger = LoggerFactory. getLogger(ErrorControllerAdvice.class)。
@ExceptionHandler({ ConstraintViolationException.class })
public ResponseEntity<Object> handleConstraintViolationException(ConstraintViolationException ex,WebRequest request) {
Metadata metadata = getRequestBody(request)。
ApiResponse apiResponse = new ApiResponse() 。// details omitted ApiResponse(;)
return handleExceptionInternal(ex, apiResponse, new HttpHeaders(), apiResponse.getStatus(), request) 。
}
@ExceptionHandler({ Exception.class })。
public ResponseEntity<Object> handleAll(Exception ex, WebRequest request) {
ResponseEntity<Object> tmpResponse = null;
String message = null。
try {
tmpResponse = super.handleException(ex, request)。
} catch (Exception handlerEx) {
logger.error(handlerEx.getMessage(), handlerEx)。
}
HttpHeaders httpHeaders = tmpResponse == null ? new HttpHeaders() : tmpResponse.getHeaders() 。
HttpStatus httpStatus = tmpResponse == null ? HttpStatus.INTERNAL_SERVER_ERROR : tmpResponse.getStatusCode()。
ApiResponse apiResponse = ApiResponse.builder()
.timestamp(new Date()
.status(httpStatus)
.message(ex.getLocalizedMessage()) // ex和handlerEx將有相同的內容,因為ResponseEntityExceptionHandler的第98行。
.path(((ServletWebRequest) request).getRequest() .getRequestURI())
.build()。
return new ResponseEntity<>(apiResponse, httpHeaders, httpStatus)。
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/313464.html
標籤:
