设为首页 加入收藏

TOP

Bean Validation完结篇:你必须关注的边边角角(约束级联、自定义约束、自定义校验器、国际化失败消息...)(一)
2019-09-01 23:28:57 】 浏览:23
Tags:Bean Validation 完结 必须 关注 边角 约束 定义 校验 国际化 失败 消息 ...

每篇一句

没有任何技术方案会是一种银弹,任何东西都是有利弊的

相关阅读

【小家Java】深入了解数据校验:Java Bean Validation 2.0(JSR303、JSR349、JSR380)Hibernate-Validation 6.x使用案例
【小家Spring】Spring方法级别数据校验:@Validated + MethodValidationPostProcessor优雅的完成数据校验动作
【小家Java】深入了解数据校验(Bean Validation):从深处去掌握@Valid的作用(级联校验)以及常用约束注解的解释说明


对Spring感兴趣可扫码加入wx群:`Java高工、架构师3群`(文末有二维码)

前言

一般来说,对于web项目我们都有必要对请求参数进行校验,有的前端使用java script校验,但是为了安全起见后端的校验都是必须的。因此数据校验不仅仅是在web下,在方方面面都是一个重要的点。前端校验有它的JS校验框架(比如我之前用的jQuery Validation Plugin),后端自然也少不了。

前面洋洋洒洒已经把数据校验Bean Validation讲了很多了,如果你已经运用在你的项目中,势必将大大提高生产力吧,本文作为完结篇(不是总结篇)就不用再系统性的介绍Bean Validation他了,而是旨在介绍你在使用过程中不得不关心的周边、细节~

如果说前面是用机,那么本文就有点玩机的意思~

BV(Bean Validation)的使用范围

本次再次强调了这一点(设计思想是我认为特别重要的存在):使用范围。
Bean Validation并不局限于应用程序的某一层或者哪种编程模型, 它可以被用在任何一层, 除了web程序,也可以是像Swing这样的富客户端程序中(GUI编程)。

我抄了一副业界著名的图给大家:
在这里插入图片描述
Bean Validation的目标是简化Bean校验,将以往重复的校验逻辑进行抽象和标准化,形成统一API规范;

说到抽象统一API,它可不是乱来的,只有当你能最大程度的得到公有,这个动作才有意义,至少它一般都是与业务无关的。抽象能力是对程序员分级的最重要标准之一

约束继承

如果子类继承自他的父类,除了校验子类,同时还会校验父类,这就是约束继承(同样适用于接口)。

// child和person上标注的约束都会被执行
public class Child extends Person {
    ...
}

注意:如果子类覆盖了父类的方法,那么子类和父类的约束都会被校验

约束级联(级联校验)

如果要验证属性关联的对象,那么需要在属性上添加@Valid注解,如果一个对象被校验,那么它的所有的标注了@Valid的关联对象都会被校验,这些对象也可以是数组、集合、Map等,这时会验证他们持有的所有元素

Demo

@Getter
@Setter
@ToString
public class Person {

    @NotNull
    private String name;
    @NotNull
    @Positive
    private Integer age;

    @Valid
    @NotNull
    private InnerChild child;
    @Valid // 让它校验List里面所有的属性
    private List<InnerChild> childList;

    @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-age");
        child.setAge(-1);
        person.setChild(child);

        // 设置childList
        person.setChildList(new ArrayList<Person.InnerChild>(){{
            Person.InnerChild innerChild = new Person.InnerChild();
            innerChild.setName("innerChild1");
            innerChild.setAge(-11);
            add(innerChild);

            innerChild = new Person.InnerChild();
            innerChild.setName("innerChild2");
            innerChild.setAge(-12);
            add(innerChild);
        }});

        Validator validator = Validation.byProvider(Hibernateva lidator.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);
    }

打印校验失败的消息:

age 不能为null: null
childList[0].age 必须是正数: -11
child.age 必须是正数: -1
childList[1].age 必须是正数: -12

约束失败消息message自定义

每个约束定义中都包含有一个用于提示验证结果的消息模版message,并且在声明一个约束条件的时候,你可以通过这个约束注解中的message属性来重写默认的消息模版(这是自定义message最简单的一种方式)。

如果在校验的时候,这个约束条件没有通过,那么你配置的MessageInterpolator插值器会被用来当成解析器来解析这个约束中定义的消息模版, 从而得到最终的验证失败提示信息。
默认使用的插值器是org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator,它借助org.hibernate.validator.spi.resourceloading.ResourceBundleLocator来获取到国际化资源属性文件从而填充模版内容~

资源解析器默认使用的实现是PlatformResourceBundleLocator,在配置Configu

首页 上一页 1 2 3 4 5 下一页 尾页 1/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇maven 依赖中scope标签的配置范围.. 下一篇理解ScheduledExecutorService中s..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目