Spring中BindingResult参数存在与否是否会决定校验抛出的异常类型?
为什么BindingResult会影响抛出的异常类型
Spring MVC对@RequestBody参数的校验逻辑由RequestResponseBodyMethodProcessor实现,校验触发后的错误处理逻辑是固定的:
- 若
@Valid/@Validated标注的@RequestBody参数紧挨着的下一个参数是BindingResult类型,校验失败的错误会直接注入该BindingResult对象,不会主动抛出异常。此时你类上标注的@Validated会触发方法级校验逻辑,扫描到校验错误后会抛出ConstraintViolationException,这就是你之前加了未使用的BindingResult时的运行逻辑。 - 若
@RequestBody参数后没有紧跟BindingResult,校验失败后RequestResponseBodyMethodProcessor会直接抛出MethodArgumentNotValidException,不会进入后续方法级校验的流程。
移除未使用的BindingResult同时保持抛出ConstraintViolationException的方案
推荐两种落地成本最低的适配方案:
方案1:新增异常转译处理器
直接新增MethodArgumentNotValidException的异常处理器,把它的错误信息转换成你需要的格式,或者直接转抛为ConstraintViolationException即可,无需改动现有接口逻辑,兼容性最好,示例代码:
@ExceptionHandler(MethodArgumentNotValidException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) ProblemDetails handleMethodArgumentNotValid(MethodArgumentNotValidException e) { Set<ConstraintViolation<?>> violations = e.getBindingResult().getFieldErrors().stream() .map(fieldError -> { // 按你原有ConstraintViolation的结构构造对象即可 return ConstraintViolationImpl.forBeanValidation( null, null, fieldError.getDefaultMessage(), Request.class, null, fieldError.getRejectedValue(), null, null, null, fieldError.getField() ); }) .collect(Collectors.toSet()); throw new ConstraintViolationException(violations); // 也可以直接在这里构造符合要求的ProblemDetails返回,不需要二次转抛 }
方案2:完全走方法级校验
关闭Spring MVC参数绑定阶段的自动校验,所有校验逻辑由类上@Validated触发的方法级校验处理,校验失败直接抛出ConstraintViolationException,不需要加BindingResult参数:
- 在配置文件中添加配置关闭绑定阶段校验:
# application.properties spring.mvc.validate-on-binding=false
- 接口参数保留
@Valid注解即可,不需要其他改动:
@PostMapping @ResponseStatus(HttpStatus.CREATED) public ResponseEntity<?> create(@Valid @RequestBody Request request, UriComponentsBuilder uriBuilder) { // ... }
内容的提问来源于stack exchange,提问作者Roddy of the Frozen Peas
相关产品推荐
相关产品推荐

