ConstraintViolationException和MethodArgumentNotValidException有什么区别

2022-09-03 06:41:08

当我在 中使用 注释 验证 Bean 时,对于某些对象,我将获得,对于某些对象,我将获得 .@Validjavax.validationConstraintViolationExceptionMethodArgumentNotValidException

我明白,如果我在控制器中验证任何内容,它会抛出一个.@ResponseBodyMethodArgumentNotValidException

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

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

我发现有点难以理解它的行为。

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

结果 - 抛出MethodArgumentNotValidException

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

结果 - 抛出ConstraintViolationException

两者都有自定义验证。ClassAClassB


答案 1

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

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

来自官方文件

对带有 @Valid 注释的参数进行验证失败时要引发的异常。

约束暴力异常在违反某些约束时由休眠实体管理器引发,因此这意味着您违反了正在使用的某些实体中的某些字段。


答案 2

为了简单理解,如果使用@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;
}

如果您不使用@Valid注释进行验证,并且异常是由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;
    }

推荐