Hibernate Validator简单使用

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

参数验证是一个常见的问题,例如验证用户输入的密码是否为空、邮箱是否合法等。但是无论是前端还是后台,都需对用户输入进行验证,以此来保证系统数据的正确性。对于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})//类界别校验的顺序
@Slf4j
public 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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值