ConstraintViolationException 和 MethodArgumentNotValidException 有什么区别

JOH*_*HND 10 java validation spring jsr bean-validation

当我在 javax.validations 中使用 @valid 注释验证 bean 时,对于某些对象,我收到 ConstraintViolationException,而对于某些对象,我收到 MethodArgumentNotValidException。

我明白,如果我在 controller 处验证 @ResponseBody 中的任何内容,它会抛出 MethodArgumentNotValidException。

但是对于类级别的某些自定义验证(例如@MyCustomValidation),即使在@ResponseValidation 中对其进行验证,它也会抛出ConstraintViolationException。

对于不同 REST 端点的其他一些自定义验证,它会抛出 MethodArgumentNotValidException。

我发现它有点难以理解,因为它是一种行为。

@PostMapping(path = "/someEndPoint")    
@Validated(OnASave.class)
public ResponseEntity<ClassA> saveObjA(@Valid @RequestBody ClassA objA)
Run Code Online (Sandbox Code Playgroud)

结果 - 抛出 MethodArgumentNotValidException

@PostMapping(path = "/someOtherEndPoint")   
@Validated(OnBSave.class)
public ResponseEntity<ClassB> saveObjB(@Valid @RequestBody ClassB objB)
Run Code Online (Sandbox Code Playgroud)

结果 - 抛出 ConstraintViolationException

ClassA 和 ClassB 都有自定义验证。

小智 15

为了简单理解,如果使用注释在控制器/服务层进行验证@Valid,则会生成MethodArgumentNotValidException. 您可以为此添加一个处理程序并相应地返回响应。该类是Spring框架的一部分,验证由Spring框架执行。请参阅下面的示例:

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Response> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
    
        logger.info("Invalid arguments found : " + ex.getMessage());
        // Get the error messages for invalid fields
        List<FieldError> errors = ex.getBindingResult()
                .getFieldErrors()
                .stream()
                .map(fieldError -> new FieldError(fieldError.getField(), fieldError.getDefaultMessage()))
                .collect(Collectors.toList());
    
        String message = messageSource.getMessage("invalid.data.message", null, LocaleContextHolder.getLocale());
        Response response = new Response(false, message)
                .setErrors(errors);
        ResponseEntity<Response> responseEntity = ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
        return responseEntity;
    }
Run Code Online (Sandbox Code Playgroud)

相反,如果您不使用@Valid注释进行验证,Hibernate 将在 JPA 层引发异常并生成ConstraintViolationException. 此异常是 Javax bean 验证框架的一部分,并在执行持久性操作时(在实际 SQL 执行之前)引发。请参阅下面的示例:

    @ExceptionHandler(ConstraintViolationException.class)
        public ResponseEntity<Response> handleConstraintViolationException(ConstraintViolationException ex) {
            List<FieldError> errors = ex.getConstraintViolations()
                    .stream()
                    .map(constraintViolation -> {
                        return new FieldError(constraintViolation.getRootBeanClass().getName() + " " + constraintViolation.getPropertyPath(), constraintViolation.getMessage());
                    })
                    .collect(Collectors.toList());
    
            String message = messageSource.getMessage("invalid.data.message", null, LocaleContextHolder.getLocale());
            Response response = new Response(false, message)
                    .setErrors(errors);
            ResponseEntity<Response> responseEntity = ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
            return responseEntity;
        }
Run Code Online (Sandbox Code Playgroud)


Moh*_*lam 6

当您使用@Valid 时,您正在应用您在模型类字段上定义的验证,而验证有不同类型,您可以选择@NotNull、@Max、@Min 等,您将获得匹配类型。

通常,所有这些都与MethodArgumentNotValidException并行,在所有情况下都会抛出MethodArgumentNotValidException

来自官方文档

当对用 @Valid 注释的参数的验证失败时抛出的异常。

当违反某些约束时,休眠实体管理器会抛出 ConstraintViolationException,因此这意味着您违反了正在使用的某些实体中的某些字段。

  • 非常感谢您的快速回复。即使我也有同样的假设,但奇怪的是,当我将所有验证移至服务层时,它总是为所有验证抛出 ConstraintViolationException 。甚至单个验证也不会抛出 MethodArgumentNotValidException (2认同)

Chr*_*ang 5

看看这篇文章。当你将 spring 的验证框架与 bean 验证混合使用时,这些异常会在不同的情况下抛出。