数据校验是贯穿所有应用程序层(从表示层到持久层)的常见任务。通常在每个层中实现相同的验证逻辑,这是耗时且容易出错的。这里我们可以使用Hibernate Validator来帮助我处理这项任务。对此,Hibernate Validator提供了一些注解来作为数据约束,我们只需要将这些注解添加到我们需要校验的属性/参数上面,就可以轻松的完成这项任务。
常见注解介绍
常见的注解,这里只是列出了一些常见的属性上面的约束以及他们所拥有的一些属性,更加详细的介绍请看 官方文档。
注解 | 数据类型 | 属性 | 注解说明 | |
@NotNull | 字符串 | 添加注解的属性不能是null | ||
@NotBlank | 字符串 | 检查字符串是否是null,且去掉空格后长度是否是0 | ||
@AssertTrue | 布尔 | 检查值是否是true | ||
@AssertFalse | 布尔 | 检查值是否是false | ||
@DecimalMax | 数字 | 检查值是否大于设定值 | ||
value | 设置的最大值 | |||
inclusive | 是否等于 | |||
@DecimalMin | 数字 | 检查值是否小于设定值 | ||
value | 设置的最大值 | |||
inclusive | 是否等于 | |||
@Digits | 数字 | 校验数字小数点前后位数 | ||
integer |
小数点前几位 | |||
fraction |
小数点后几位 | |||
字符串 | 校验是不是邮箱 | |||
@Future | 时间 | 检查日期是不是在将来 | ||
@Past | 时间 | 检查日期是否在过去 | ||
@Max | 数字类型 | 是否大于最大值 | ||
@Min | 数字类型 | 是否小于最小值 | ||
@Pattern | 字符串 | 使用正则校验 | ||
@Size | 字符串,集合,数组 | 检查长度 |
简单的使用
看到上面的那么多注解是不是觉得很实用呢?有没有想试一试看看好不好用呢?接下来我们开始写一些代码来用一用,首先我们需要添加它的依赖。
<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.15.Final</version> </dependency> <dependency> <groupId>org.glassfish</groupId> <artifactId>javax.el</artifactId> <version>3.0.1-b09</version> </dependency>
接下来定义一个Class,然后在他的属性上添加Hibernate Validator提供的一些注解
import lombok.Getter; import lombok.Setter; import lombok.ToString; import javax.validation.constraints.*; import java.util.Date; /** * 产品表 * * @author hejiaxuan */ @Getter @Setter @ToString public class Demo { @NotNull @Digits(integer = 0, fraction = 3) private Double aDouble; @Past(message = "time必须在今天之后") private Date time; @Max(value = 5, message = "status不能大于5") @Min(value = 0, message = "status不能小于0") @NotNull(message = "status不能为null") private Integer status; @Size(min = 2, max = 5, message = "name长度必须在2~5之间") @NotBlank(message = "name不能为null") private String name; }
对象定义好了,下面看看怎么用吧。
校验值:validator.validateValue
上面的代码中,我们定义的了一个对象,并且在它的每个属性上面添加了我们需要的校验规则(注解)。现在说一个不需要实例化对象就可以测试这些规则的方法, 代码如下:
//单独校验Class中的某个属性和值 Set<ConstraintViolation<Demo>> result = validator.validateValue(Demo.class, "name", "hahahaha"); Iterator<ConstraintViolation<Demo>> iterator = result.iterator(); while (iterator.hasNext()) { ConstraintViolation<Demo> next = iterator.next(); //打印校验结果 System.out.println(next.getMessage()); } //运行结果 name长度必须在2~5之间
校验整个对象:validator.validate
这里是校验这个对象的所有属性
//待校验对象 Demo demo = new Demo(); demo.setName("00000000"); demo.setADouble(200.001); demo.setStatus(200); //得到Validator实例 ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); Validator validator = factory.getValidator(); //开始校验 Set<ConstraintViolation<Demo>> result = validator.validate(demo); Iterator<ConstraintViolation<Demo>> iterator = result.iterator(); while (iterator.hasNext()) { ConstraintViolation<Demo> next = iterator.next(); //打印校验结果 System.out.println(next.getMessage()); } //运行结果 name不能为null 不能为null status不能为null
因为对象没有设置任何值,所以校验结果都是 “某某某字段不能为null”,现在我们给demo对象设置几个值试一下
demo.setName("00000000"); demo.setADouble(200.001); demo.setStatus(200); //运行结果 数字的值超出了允许范围(只允许在0位整数和3位小数范围内) status不能大于5 name长度必须在2~5之间
这里是校验整个对象的所有属性,但是如果我们只想校验一个对象里的部分属性怎么办呢?
校验单个属性 validator.validateProperty
这里是单独校验某一个对象其中的某几个属性,代码如下
//第一个参数是要校验的对象,后面的参数是要校验的对象属性名称 Set<ConstraintViolation<Demo>> result = validator.validateProperty( demo, "status" ); //输出结果 status不能大于5
对于方法的校验
上面讲的都是对象属性的校验,那么怎样对一个方法的入参和出参进行校验呢?这里分为 方法参数的校验 和 返回值的校验。下面我们先给Demo.java添加一个方法,并添加约束注解:
public class Demo { /** * 要校验的方法 * * @param string * @return */ public @Size(min = 3, max = 10, message = "结果长度在3~10之间") String getString(@NotBlank String string) { return string; } }
校验方法的返回值:executableValidator.validateReturnValue
//对于方法的校验 ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); ExecutableValidator executableValidator = factory.getValidator().forExecutables(); //实例化对象 Demo object = new Demo(); //获取对应的方法 Method method = Demo.class.getMethod("getString", String.class); //获取它的返回值 Object returnValue = method.invoke(object, "这是方法的参数,要大于是个字"); Set<ConstraintViolation<Demo>> violations = executableValidator.validateReturnValue( object, method, returnValue ); //结果 Iterator<ConstraintViolation<Demo>> iterator = violations.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next().getMessage()); } //执行结果 结果长度在3~10之间
校验方法的入参:executableValidator.validateParameters
//对于方法的校验 ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); ExecutableValidator executableValidator = factory.getValidator().forExecutables(); //实例化对象 Demo object = new Demo(); //获取对应的方法 Method method = Demo.class.getMethod("getString", String.class); //方法的入参 Object[] parameters = {null}; Set<ConstraintViolation<Demo>> violations = executableValidator.validateParameters( object, method, parameters ); //结果 Iterator<ConstraintViolation<Demo>> iterator = violations.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next().getMessage()); } //执行结果 不能为空