Bean Validation

夏博
2023-12-01

概述

JSR-303 是JAVA EE 6 中的一项子规范,叫做Bean Validation,Hibernate Validator 是 Bean Validation 的参考实现 . Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint 的实现,除此之外还有一些附加的 constraint。(详见Reference[1])

JSR-303 constraint,如: @Null/@NotNull/@Min/@Max,位于 package javax.validation.constraints;

Hibernate Validator 附加的 constraint,如@Email/@Length/@Range,位于
package org.hibernate.validator.constraints;

实践

对象定义

@Data
public class ValidParam {

    @Length(max = 20,min = 2)
    private String name;
    @Range(max = 200)
    private Integer age;
}

正面案例

PostBody

// import ***;

@RestController
@RequestMapping("valid")
public class ValidTestController {
    /**
     * postBody
     * @param param
     * @return
     */
    @PostMapping("postBody")
    public Result postBody(@RequestBody @Valid ValidParam param) {
        return new Result<>();
    }

    /**
     * postBody
     * @param param
     * @return
     */
    @PostMapping("postBodyValidated")
    public Result postBodyValidated(@RequestBody @Validated ValidParam param) {
        return new Result<>();
    }

}

PostForm

// import ***;
@RestController
@RequestMapping("valid")
public class ValidTestController {

    @PostMapping("postForm")
    public Result postForm(@Validated ValidParam param) {

        return new Result<>();
    }
}

GetPostParam

注意 Controller上加注解@Validated

@Validated
@RestController
@RequestMapping("valid")
public class ValidTestController {


    /**
     * getParam valid
     * @param name
     * @param age
     * @return
     */
    @GetMapping("getParam")
    public Result getParam(@Length(max = 20,min = 2) String name,
                           @Range(max = 200) Integer age) {

        return new Result<>();
    }

    /**
     * postParam valid
     * @param name
     * @param age
     * @return
     */
     @PostMapping("postParam")
     public Result postParam(@Length(max = 20,min = 2) String name,
                             @Range(max = 200) Integer age) {
        return new Result<>();
     }
}

异常类

不同校验方式抛出的异常类不同

  • PostBody
    org.springframework.web.bind.MethodArgumentNotValidException

  • PostForm
    org.springframework.validation.BindException

  • GetPostParam
    javax.validation.ConstraintViolationException

实现原理

  • PostBody
    由 RequestResponseBodyMethodProcessor 处理
    实现了HandlerMethodArgumentResolver 接口,在参数解析后进行校验。

    validateIfApplicable中实现
    可以看到@Validated、@Valid两个注解为什么可以混用

	protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
		Annotation[] annotations = parameter.getParameterAnnotations();
		for (Annotation ann : annotations) {
			Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
			if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
				Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
				Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
				binder.validate(validationHints);
				break;
			}
		}
	}
  • PostForm
    由 ModelAttributeMethodProcessor 处理
    实现了HandlerMethodArgumentResolver 接口,在参数解析后进行校验,同上类似。

  • GetPostParam
    工作都由MethodValidationPostProcessor完成。

	@Override
	public void afterPropertiesSet() {
		// 根据@Validated注解是否开启代理
		Pointcut pointcut = new AnnotationMatchingPointcut(this.validatedAnnotationType, true);
		this.advisor = new DefaultPointcutAdvisor(pointcut, createMethodValidationAdvice(this.validator));
	}
// Create AOP advice for method validation purposes
	protected Advice createMethodValidationAdvice(@Nullable Validator validator) {
		return (validator != null ? new MethodValidationInterceptor(validator) : new MethodValidationInterceptor());
	}
核心验证由 MethodValidationInterceptor 实现。
获取分组,进行校验,逻辑简单,不再赘述。

进阶

  • 嵌套验证

嵌套字段上标注@Valid注解

  • 自定义注解验证

详见Reference[4]

Reference

  1. https://developer.ibm.com/zh/articles/j-lo-jsr303/
  2. https://www.cnblogs.com/cjyboy/p/11465876.html
  3. https://blog.csdn.net/fgszdgbzdb/article/details/93477296
  4. https://blog.csdn.net/fgszdgbzdb/article/details/93595660
 类似资料:

相关阅读

相关文章

相关问答