Spring 引导 REST 验证错误响应
Spring boot REST validation error response
控制器方法:
public Mission createMission(final @Valid @RequestBody Mission mission) {
//save..
return mission;
}
我想将所有验证错误消息枚举为 json 和 return。
我可以通过创建新异常 class、在控制器方法参数中添加 BindingResult、在绑定结果有错误时抛出新异常并在 @ControllerAdvice class 中处理异常来做到这一点。
if (bindingResult.hasErrors()) {
throw new InvalidRequestException("Fix input and try again", bindingResult);
}
但我想避免在每个控制器方法中检查 BindingResult,而是全局处理。如果我能处理异常,我本可以做到的:org.springframework.web.bind.MethodArgumentNotValidException。但不幸的是 Spring 引导不允许
@ExceptionHandler(MethodArgumentNotValidException.class)
它显示了不明确的异常处理程序,因为处理了相同的异常 ResponseEntityExceptionHandler,而且我无法覆盖 handleException,因为它是最终的。我尝试通过捕获 Exception.class 来覆盖受保护的 ResponseEntity handleMethodArgumentNotValid(),但这根本没有被调用。
有什么方法可以实现这个目标吗?对于一个简单的任务来说似乎有很多事情:(
我发现了问题,controller advice 放在了common util 模块中,Spring 似乎没有使用它,尽管它在组件扫描的同一个基础包下。我所做的是在全局抽象 class(在公共模块中)中重写 ResponseEntityExceptionHandler 的方法,然后在其他模块中扩展 class.
您应该创建一个使用 @ControllerAdvice
并扩展 ResponseEntityExceptionHandler
的 class。然后你可以覆盖方法handleMethodArgumentNotValid
。你可以使用类似的东西:
@ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
@Override
@ResponseStatus(HttpStatus.BAD_REQUEST)
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
final List<FieldError> fieldErrors = ex.getBindingResult().getFieldErrors();
Map <String, Set<String>> errorsMap = fieldErrors.stream().collect(
Collectors.groupingBy(FieldError::getField,
Collectors.mapping(FieldError::getDefaultMessage, Collectors.toSet())
)
);
return new ResponseEntity(errorsMap.isEmpty()? ex:errorsMap, headers, status);
}
}
如果您不想扩展到 ResponseEntityExceptionHandler
,您需要将 GlobalExceptionHandler
注释为 @ControllerAdvice
和 @ResponseBody
。
更新:
Spring Boot 结合 @ControllerAdvice
和 @ResponseBody
创建了一个新注释 @RestControllerAdvice
。
控制器方法:
public Mission createMission(final @Valid @RequestBody Mission mission) {
//save..
return mission;
}
我想将所有验证错误消息枚举为 json 和 return。
我可以通过创建新异常 class、在控制器方法参数中添加 BindingResult、在绑定结果有错误时抛出新异常并在 @ControllerAdvice class 中处理异常来做到这一点。
if (bindingResult.hasErrors()) {
throw new InvalidRequestException("Fix input and try again", bindingResult);
}
但我想避免在每个控制器方法中检查 BindingResult,而是全局处理。如果我能处理异常,我本可以做到的:org.springframework.web.bind.MethodArgumentNotValidException。但不幸的是 Spring 引导不允许
@ExceptionHandler(MethodArgumentNotValidException.class)
它显示了不明确的异常处理程序,因为处理了相同的异常 ResponseEntityExceptionHandler,而且我无法覆盖 handleException,因为它是最终的。我尝试通过捕获 Exception.class 来覆盖受保护的 ResponseEntity handleMethodArgumentNotValid(),但这根本没有被调用。
有什么方法可以实现这个目标吗?对于一个简单的任务来说似乎有很多事情:(
我发现了问题,controller advice 放在了common util 模块中,Spring 似乎没有使用它,尽管它在组件扫描的同一个基础包下。我所做的是在全局抽象 class(在公共模块中)中重写 ResponseEntityExceptionHandler 的方法,然后在其他模块中扩展 class.
您应该创建一个使用 @ControllerAdvice
并扩展 ResponseEntityExceptionHandler
的 class。然后你可以覆盖方法handleMethodArgumentNotValid
。你可以使用类似的东西:
@ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
@Override
@ResponseStatus(HttpStatus.BAD_REQUEST)
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
final List<FieldError> fieldErrors = ex.getBindingResult().getFieldErrors();
Map <String, Set<String>> errorsMap = fieldErrors.stream().collect(
Collectors.groupingBy(FieldError::getField,
Collectors.mapping(FieldError::getDefaultMessage, Collectors.toSet())
)
);
return new ResponseEntity(errorsMap.isEmpty()? ex:errorsMap, headers, status);
}
}
如果您不想扩展到 ResponseEntityExceptionHandler
,您需要将 GlobalExceptionHandler
注释为 @ControllerAdvice
和 @ResponseBody
。
更新:
Spring Boot 结合 @ControllerAdvice
和 @ResponseBody
创建了一个新注释 @RestControllerAdvice
。