从深处去掌握数据校验@Valid的作用(级联校验) (4)

我们知道,每个约束注解都是交给约束校验器ConstraintValidator.isValid()这个方法来处理的,它被调用(生效)的地方在此(唯一处):

public abstract class ConstraintTree<A extends Annotation> { ... protected final <T, V> Set<ConstraintViolation<T>> validateSingleConstraint(ValidationContext<T> executionContext, ValueContext<?, ?> valueContext, ConstraintValidatorContextImpl constraintValidatorContext, ConstraintValidator<A, V> validator) { ... V validatedValue = (V) valueContext.getCurrentValidatedValue(); isValid = validator.isValid( validatedValue, constraintValidatorContext ); ... // 显然校验不通过就返回错误消息 否则返回空集合 if ( !isValid ) { return executionContext.createConstraintViolations(valueContext, constraintValidatorContext); } return Collections.emptySet(); } ... }

这个方法的调用,会在执行每个Group的时候

success = metaConstraint.validateConstraint( validationContext, valueContext );

MetaConstraint在上面检索的时候就已经准备好了,最后通过ConstrainedElement.getConstraints就拿到了每个元素的校验器们,继续调用

// ConstraintTree<A> boolean validationResult = constraintTree.validateConstraints( executionContext, valueContext );

so,最终就调用到了isValid这个真正做事的方法上了。

==说了这么多,你可能还云里雾里,那么就show一把吧:==

Demo Show

上面用一个示例校验Person这个JavaBean了,但是你会发现示例中我们全都是校验的Field属性。从理论里我们知道了Bean Validation它是有校验方法、构造器、入参甚至递归校验级联属性的能力的

校验属性Field

校验Method入参、返回值 校验Constructor入参、返回值 既校验入参,同时也校验返回值

这些是不能直接使用的,需要在运行时进行校验。具体使用可参考:【小家Spring】让Controller支持对平铺参数执行数据校验(默认Spring MVC使用@Valid只能对JavaBean进行校验)

级联校验

什么叫级联校验,其实就是带校验的成员里存在级联对象时,也要对它完成校验。这个在实际应用场景中是比较常见的,比如入参Person对象中,还持有Child对象,我们不仅仅要完成Person的校验,也依旧还要对Child内的属性校验:

@Getter @Setter @ToString public class Person { @NotNull private String name; @NotNull @Positive private Integer age; @Valid @NotNull private InnerChild child; @Getter @Setter @ToString public static class InnerChild { @NotNull private String name; @NotNull @Positive private Integer age; } }

校验逻辑如下:

public static void main(String[] args) { Person person = new Person(); person.setName("fsx"); Person.InnerChild child = new Person.InnerChild(); child.setName("fsx-son"); child.setAge(-1); person.setChild(child); // 放进去 Validator validator = Validation.byProvider(HibernateValidator.class).configure().failFast(false) .buildValidatorFactory().getValidator(); Set<ConstraintViolation<Person>> result = validator.validate(person); // 输出错误消息 result.stream().map(v -> v.getPropertyPath() + " " + v.getMessage() + ": " + v.getInvalidValue()) .forEach(System.out::println); }

运行:

child.age 必须是正数: -1 age 不能为null: null

对child.age这个级联属性校验成功~

总结

本文值得说是深入了解数据校验(Bean Validation)了,对于数据校验的基本使用一直都不是难事,特别是在Spring环境下使用就更简单了~

知识交流

若文章格式混乱,可点击:原文链接-原文链接-原文链接-原文链接-原文链接

==The last:如果觉得本文对你有帮助,不妨点个赞呗。当然分享到你的朋友圈让更多小伙伴看到也是被作者本人许可的~==

若对技术内容感兴趣可以加入wx群交流:Java高工、架构师3群。
若群二维码失效,请加wx号:fsx641385712(或者扫描下方wx二维码)。并且备注:"java入群" 字样,会手动邀请入群

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zywyjz.html