Spring Boot REST 验证错误响应

Sha*_*iul 8 java validation spring hibernate-validator spring-boot

控制器方法:

public Mission createMission(final @Valid @RequestBody Mission mission) {

    //save..

    return mission;
}
Run Code Online (Sandbox Code Playgroud)

我想将所有验证错误消息枚举为 json 并返回。

我可以通过创建一个新的异常类来做到这一点,在控制器方法参数中添加 BindingResult,当绑定结果有错误时抛出新的异常并在 @ControllerAdvice 类中处理异常。

if (bindingResult.hasErrors()) {
        throw new InvalidRequestException("Fix input and try again", bindingResult);
    }
Run Code Online (Sandbox Code Playgroud)

但我想避免在每个控制器方法中检查 BindingResult,而是全局处理。如果我可以处理异常,我可以做到这一点:org.springframework.web.bind.MethodArgumentNotValidException。但不幸的是 Spring Boot 不允许

@ExceptionHandler(MethodArgumentNotValidException.class)
Run Code Online (Sandbox Code Playgroud)

它显示了不明确的异常处理程序,因为处理了相同的异常 ResponseEntityExceptionHandler,并且我无法覆盖 handleException,因为它是最终的。我尝试通过捕获 Exception.class 来覆盖受保护的 ResponseEntity handleMethodArgumentNotValid(),但这根本没有被调用。

有没有办法实现这个目标?对于一个简单的任务来说,这似乎有很多事情:(

小智 8

您应该创建一个使用@ControllerAdvice和扩展的类ResponseEntityExceptionHandler。然后您可以覆盖该方法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);
    }
}
Run Code Online (Sandbox Code Playgroud)


Sha*_*iul 0

我发现了问题,控制器建议放在common util模块中,尽管它位于组件扫描的相同基础包下,但Spring似乎没有使用该模块。我所做的是重写全局抽象类(在公共模块中)中 ResponseEntityExceptionHandler 的方法,然后在其他模块中扩展该类。