Hibernate Validator简单使用

来源:互联网 发布:移动网络转换器 编辑:程序博客网 时间:2024/06/03 03:53

使用的主要的作用:进行注解式的参数校验——让代码更少、更加专注于业务逻辑

参数验证是一个常见的问题,例如验证用户输入的密码是否为空、邮箱是否合法等。但是无论是前端还是后台,都需对用户输入进行验证,以此来保证系统数据的正确性。对于web来说,有些人可能理所当然的想在前端验证就行了,但这样是非常错误的做法,前台的验证一般是通过JavaScript,js代码是可以被禁用和篡改的,所以相对后台检验而言,安全性会低一些。前端代码对于用户来说是透明的,稍微有点技术的人就可以绕过这个验证,直接提交数据到后台。无论是前端网页提交的接口,还是提供给外部的接口,参数验证随处可见,也是必不可少的。总之,一切用户的输入都是不可信的。

基于这样的常识,在后端的代码开发中,参数校验是一个永远也绕不开的话题。然而编写参数校验代码的过程是一个技术含量不高,及其耗时,繁琐的过程。比如极大多数的参数校验代码就是:判断一下用户名是否已经存在、用户名长度是否满足要求、用户填写的邮箱是否合法。年龄参数是不是一个整数等等。为了减少重复代码的开发,许多有技术积淀的公司,一般都会提供一套或多套特有的参数校验工具类。以此减少代码量。这种做法在项目中非常普遍,有了这些工具类库,程序员在编写业务代码的过程中,工作效率可以大大提升。

然而,即便聪明如上述做法,我们的业务逻辑中依然还是可以见到大量的参数校验逻辑,倘若项目架构的不够合理,这些与参数校验逻辑有关的代码量会更多,真是XXX的裹脚布,又臭又长。大量繁杂的参数校验代码混杂在业务逻辑中,一来降低了代码的可读性;二是让人对业务本身的理解难度加大,很多刚加入公司的人往往是通过读码来理解业务的,公司的一些业务培训一般只能讲个大概,然而在阅读代码的过程中稍有不慎便会被这些“额外”的代码扰乱思路,对于新手,那更是异常噩梦,倘若老员工辞职了,撒手抛给新来的,这样的项目能不能维护下去都是个问题了。

以上参考:http://blog.csdn.net/nmgrd/article/details/57088192

Hibernate Validator

Express validation rules in a standardized way using annotation-based constraints and benefit from transparent integration with a wide variety of frameworks.(标准化方式使用基于注释的约束来表达验证规则,并从与各种框架的透明集成中受益),可以扩展,可自定义约束的类型。Hibernate Validator 5.x is the reference implementation Bean Validation 1.1!。hibernate Validator是 Bean Validation 的参考实现,Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint 的实现,除此之外还有一些附加的 constraint(约束)。为了满足特定的需求,用户还可以自实现更多的constraint以便满足特定的需求。
网址:http://hibernate.org/validator/
参考文档:http://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#validator-gettingstarted-createproject

实际的场景

在后台的业务逻辑中,对数据值的校验在各层都存在(展示层,业务层,数据访问层等),并且各层校验的规则又不尽相同,在各层中重复的校验逻辑既导致了不必要的资源消耗,还使得逻辑不够单一(每层都夹杂着校验的逻辑),JSR 303 Bean Validation就是在这种背景下产生的一个数据验证的J2EE规范。使用起来非常的简单规范,而且校验的规则的代码都是一样的,都是基于JavaBean的注解的校验。

实际的使用

** 引入需要的maven配置

       <dependency>            <groupId>org.hibernate</groupId>            <artifactId>hibernate-validator</artifactId>            <version>5.4.0.Final</version>        </dependency>        <dependency>            <groupId>javax.el</groupId>            <artifactId>el-api</artifactId>            <version>2.2</version>            <scope>provided</scope>        </dependency>        <dependency>            <groupId>org.glassfish.web</groupId>            <artifactId>javax.el</artifactId>            <version>2.2.6</version>        </dependency>

* 创建需要校验的类*

package com.common.utils.Hibernatevalidatedemo;import org.hibernate.validator.constraints.Email;import javax.validation.constraints.*;import java.util.Date;/** * descrption: 测试类,看看Validate * authohr: wangji * date: 2017-08-12 10:36 */public class ValidateInfoBean {    @NotNull(message = "姓名不能为空!")    @Min(value = 1, message = "Id只能大于等于1,小于等于10")    @Max(value = 10, message = "Id只能大于等于1,小于等于10")    private Integer id;    @NotNull(message = "姓名不能为空!")    @Size(min = 2, max = 4, message = "姓名长度必须在{min}和{max}之间")    @Pattern(regexp = "[\u4e00-\u9fa5]+", message = "名称只能输入是中文字符")    private String userName;    @NotNull(message = "密码不能为空!")    @Size(min = 6, max = 12, message = "密码长度必须在{min}和{max}之间")    private String passWord;    @NotNull(message = "日期不能为空!")    @Past(message = "你只能输入过去的日期")    private Date birthday;    @NotNull(message = "邮件不能为空!")    @Email(message = "邮件格式不正确")    private String email;    public Integer getId() {        return id;    }    public void setId(Integer id) {        this.id = id;    }    public String getUserName() {        return userName;    }    public void setUserName(String userName) {        this.userName = userName;    }    public String getPassWord() {        return passWord;    }    public void setPassWord(String passWord) {        this.passWord = passWord;    }    public Date getBirthday() {        return birthday;    }    public void setBirthday(Date birthday) {        this.birthday = birthday;    }    public String getEmail() {        return email;    }    public void setEmail(String email) {        this.email = email;    }}

其中该类中用到Max,Min,NotNull,Size等都是JSR 303中内置的约束条件(constraint),还有一些是Hibernate扩充的约束,我们自己也是可以扩充这个约束进行使用。下面看看如何验证吧。

开始校验首先获取校验器

  ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();    Validator validator = validatorFactory.getValidator();

创建一个校验类的实例

        ValidateInfoBean infoBean = new ValidateInfoBean();        infoBean.setId(-1);        infoBean.setUserName("中国wj");        infoBean.setPassWord("12345");        infoBean.setEmail("testt.com");        infoBean.setBirthday(new Date(2015,3,2));

校验一共有几种校验的方式(返回的都是违反约束的字段的集合)

 //特定类实例,然后分组(就是一个校验的标识,确定先后顺序,是否校验等) <T> Set<ConstraintViolation<T>> validate(T object, Class< ?>... groups); //特定实例上的某个字段<T> Set<ConstraintViolation<T>> validateProperty(T object,                                                     String propertyName,                                                     Class< ?>... groups); //使用某个类上的某个字段进行校验 <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType,                                                  String propertyName,                                                  Object value,                                                  Class<?>... groups);

输出函数:

public static void pringValidateStr(Set<ConstraintViolation<ValidateInfoBean>> set2) {        for (ConstraintViolation<ValidateInfoBean> constraintViolation : set2){            log.info("错误:" + constraintViolation.getMessage());            log.info("字段:"+constraintViolation.getPropertyPath().toString());        }    }

校验所有的字段

  Set<ConstraintViolation<ValidateInfoBean>> set = validator.validate(infoBean);        pringValidateStr(set);    2017-08-12 13:54:50,931  INFO [Version.java:30] : HV000001: Hibernate Validator 5.4.0.Final    2017-08-12 13:54:51,251  INFO [ValidateTest.java:52] : 错误:你只能输入过去的日期    2017-08-12 13:54:51,251  INFO [ValidateTest.java:53] : 字段:birthday    2017-08-12 13:54:51,251  INFO [ValidateTest.java:52] : 错误:Id只能大于等于1,小于等于10    2017-08-12 13:54:51,252  INFO [ValidateTest.java:53] : 字段:id    2017-08-12 13:54:51,252  INFO [ValidateTest.java:52] : 错误:名称只能输入是中文字符    2017-08-12 13:54:51,253  INFO [ValidateTest.java:53] : 字段:userName    2017-08-12 13:54:51,253  INFO [ValidateTest.java:52] : 错误:邮件格式不正确    2017-08-12 13:54:51,253  INFO [ValidateTest.java:53] : 字段:email    2017-08-12 13:54:51,253  INFO [ValidateTest.java:52] : 错误:密码长度必须在612之间    2017-08-12 13:54:51,253  INFO [ValidateTest.java:53] : 字段:passWord

特定实例上的某个字段

Set<ConstraintViolation<ValidateInfoBean>> set3 =validator.validateProperty(infoBean,"userName");        pringValidateStr(set3);    2017-08-12 13:59:14,262  INFO [Version.java:30] : HV000001: Hibernate Validator 5.4.0.Final    2017-08-12 13:59:14,556  INFO [ValidateTest.java:52] : 错误:名称只能输入是中文字符    2017-08-12 13:59:14,557  INFO [ValidateTest.java:53] : 字段:userName

使用某个类上的某个字段进行校验

 Set<ConstraintViolation<ValidateInfoBean>> set2 =validator.validateValue(ValidateInfoBean.class,"userName","中国lihai");        pringValidateStr(set2);    2017-08-12 14:00:32,533  INFO [Version.java:30] : HV000001: Hibernate Validator 5.4.0.Final    2017-08-12 14:00:33,136  INFO [ValidateTest.java:52] : 错误:名称只能输入是中文字符    2017-08-12 14:00:33,136  INFO [ValidateTest.java:53] : 字段:userName    2017-08-12 14:00:33,137  INFO [ValidateTest.java:52] : 错误:姓名长度必须在24之间    2017-08-12 14:00:33,137  INFO [ValidateTest.java:53] : 字段:userName

还有很多这样的约束

  @Null 被注释的元素必须为 null   @NotNull 被注释的元素必须不为 null   @AssertTrue 被注释的元素必须为 true   @AssertFalse 被注释的元素必须为 false   @Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值   @Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值   @DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值   @DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值   @Size(max, min) 被注释的元素的大小必须在指定的范围内   @Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内   @Past 被注释的元素必须是一个过去的日期   @Future 被注释的元素必须是一个将来的日期   @Pattern(value) 被注释的元素必须符合指定的正则表达式   表 2. Hibernate Validator 附加的 constraint   @Email 被注释的元素必须是电子邮箱地址   @Length 被注释的字符串的大小必须在指定的范围内   @NotEmpty 被注释的字符串的必须非空   @Range 被注释的元素必须在合适的范围内

还有校验分组,确定校验哪些,校验的顺序,就是一个简单的标识,可以随便创建一个标识的类的信息。这里创建了两个空的接口。除此之外还有很多的使用,比如继承,级联,详情见官网,这里仅仅简单的查看如何使用。

package com.common.utils.Hibernatevalidatedemo;import lombok.extern.slf4j.Slf4j;import javax.validation.*;import javax.validation.constraints.NotNull;import javax.validation.constraints.Past;import javax.validation.constraints.Pattern;import javax.validation.constraints.Size;import java.util.Date;import java.util.Set;/** * descrption: 校验分组 * authohr: wangji * date: 2017-08-12 14:04 */@GroupSequence({First.class,Second.class,ValidateGroup.class})//类界别校验的顺序@Slf4jpublic class ValidateGroup {    @NotNull(message = "姓名不能为空!", groups = {First.class})    @Size(min = 2, max = 4, message = "姓名长度必须在{min}和{max}之间",groups = {First.class})    @Pattern(regexp = "[\u4e00-\u9fa5]+", message = "名称只能输入是中文字符",groups = {First.class})    private String userName;    @NotNull(message = "密码不能为空!",groups = {Second.class})    @Size(min = 6, max = 12, message = "密码长度必须在{min}和{max}之间",groups = {Second.class})    private String passWord;    @NotNull(message = "日期不能为空!")    @Past(message = "你只能输入过去的日期")    private Date birthday;    public static void main(String[] args) {        ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();        Validator validator = validatorFactory.getValidator();        ValidateGroup testFirst = new ValidateGroup();        testFirst.setUserName("wangji");        //下面这里使用来分类进行校验,通过Group唯一标识进行区别,也可以使用多个进行先后顺序的校验        //还可以进行类界别的校验顺序@GroupSequence,如果没有定义Group那么就会使用,当前类进行标识       // pringValidateStr(validator.validate(testFirst,First.class));//        2017-08-12 14:22:13,899  INFO [ValidateGroup.java:44] : 错误:姓名长度必须在2和4之间//        2017-08-12 14:22:13,900  INFO [ValidateGroup.java:45] : 字段:userName//        2017-08-12 14:22:13,900  INFO [ValidateGroup.java:44] : 错误:名称只能输入是中文字符//        2017-08-12 14:22:13,900  INFO [ValidateGroup.java:45] : 字段:userName//        通过@GroupSequence指定验证顺序://        先验证First分组,如果有错误立即返回//        而不会验证Second分组,接着如果First分组验证通过了,//        那么才去验证Second分组,最后指定User.class表示那些没有分组的在最后。//        这样我们就可以实现按顺序验证分组了。         pringValidateStr(validator.validate(testFirst));//        输出的只是第一个校验错误,其他的不继续校验了//        2017-08-12 14:27:46,378  INFO [Version.java:30] : HV000001: Hibernate Validator 5.4.0.Final//        2017-08-12 14:27:46,649  INFO [ValidateGroup.java:55] : 错误:姓名长度必须在2和4之间//        2017-08-12 14:27:46,650  INFO [ValidateGroup.java:56] : 字段:userName//        2017-08-12 14:27:46,650  INFO [ValidateGroup.java:55] : 错误:名称只能输入是中文字符//        2017-08-12 14:27:46,650  INFO [ValidateGroup.java:56] : 字段:userName    }    public static void pringValidateStr(Set<ConstraintViolation<ValidateGroup>> set2) {        for (ConstraintViolation<ValidateGroup> constraintViolation : set2){            log.info("错误:" + constraintViolation.getMessage());            log.info("字段:"+constraintViolation.getPropertyPath().toString());        }    }    public String getUserName() {        return userName;    }    public void setUserName(String userName) {        this.userName = userName;    }    public String getPassWord() {        return passWord;    }    public void setPassWord(String passWord) {        this.passWord = passWord;    }    public Date getBirthday() {        return birthday;    }    public void setBirthday(Date birthday) {        this.birthday = birthday;    }}

以上就是简单的使用,还有很多的新特性,可以参考官方上的说明进行简单的查看。

网址: https://github.com/WangJi92/mybatits-study/blob/master/mybatis-study/study-6-spring-Hibernate/src/main/java/com/common/utils/Hibernatevalidatedemo/ValidateInfoBean.java