注意:hibernate-validator 与 持久层框架 hibernate
没有什么关系,hibernate-validator 是 hibernate 组织下的一个开源项目 。
hibernate-validator
是 JSR 380(Bean Validation 2.0)
、JSR 303(Bean Validation 1.0)
规范的实现。
JSR 380
- Bean Validation 2.0
定义了一个实体和方法验证的元数据模型和 API。
JavaEE(改名为:Jakarta EE)中制定了 validation 规范,即:javax.validation-api(现为 jakarta.validation-api,jar 包的名字改变,包里面的包名、类名未变,因此使用方式不变)包,spring-boot-starter-web
、spring-boot-starter-webflux
包都已引入此依赖,直接使用即可。
有点类似于 slf4j 与 logback(log4j2)的关系,使用的时候,代码中使用 javax.validate
提供的接口规范功能,加载的时候,根据 SPI 规范加载对应的规范实现类。
它和 hibernate
没什么关系,放心大胆的使用吧。
引入依赖
首先,我们在 Maven 配置中引入 @valid 的依赖:
如果你是 springboot 项目,那么可以不用引入了,已经引入了,他就存在于最核心的 web 开发包里面。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.5.RELEASE</version>
</dependency>
如果你不是 springboot 项目,那么引入下面依赖即可:
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.4.1.Final</version>
</dependency>
标识注解
@Valid(规范、常用)
标记用于验证
级联
的属性、方法参数或方法返回类型。
在验证属性、方法参数或方法返回类型时,将验证在对象及其属性上定义的约束。
此行为是递归
应用的。
@Validated(spring)
spring
提供的扩展注解,可以方便的用于分组校验
22 个约束注解(重要、经常用到)
下面除了列出的参数,每个约束都有参数 message,groups 和 payload。这是 Bean Validation 规范的要求。
其中,message
是提示消息,groups
可以根据情况来分组。
以下每一个注解都可以在相同元素上定义多个。
@AssertFalse
检查元素是否为 false,支持数据类型:boolean、Boolean
@AssertTrue
检查元素是否为 true,支持数据类型:boolean、Boolean
@DecimalMax(value=, inclusive=)
inclusive:boolean,默认 true,表示是否包含,是否等于
value:当 inclusive=false 时,检查带注解的值是否小于指定的最大值。当 inclusive=true 检查该值是否小于或等于指定的最大值。参数值是根据 bigdecimal 字符串表示的最大值。
支持数据类型:BigDecimal、BigInteger、CharSequence、(byte、short、int、long 和其封装类)
@DecimalMin(value=, inclusive=)
支持数据类型:BigDecimal、BigInteger、CharSequence、(byte、short、int、long 和其封装类)
inclusive:boolean,默认 true,表示是否包含,是否等于
value:
当 inclusive=false 时,检查带注解的值是否大于指定的最大值。当 inclusive=true 检查该值是否大于或等于指定的最大值。参数值是根据 bigdecimal 字符串表示的最小值。
@Digits(integer=, fraction=)
检查值是否为最多包含 integer
位整数和 fraction
位小数的数字
支持的数据类型:
BigDecimal, BigInteger, CharSequence, byte, short, int, long 、原生类型的封装类、任何 Number 子类。
检查指定的字符序列是否为有效的电子邮件地址。可选参数 regexp
和 flags
允许指定电子邮件必须匹配的附加正则表达式(包括正则表达式标志)。
支持的数据类型:CharSequence
@Max(value=)
检查值是否小于或等于指定的最大值
支持的数据类型:
BigDecimal, BigInteger, byte, short, int, long, 原生类型的封装类, CharSequence 的任意子类(字符序列表示的数字), Number 的任意子类, javax.money.MonetaryAmount 的任意子类
@Min(value=)
检查值是否大于或等于指定的最大值
支持的数据类型:
BigDecimal, BigInteger, byte, short, int, long, 原生类型的封装类, CharSequence 的任意子类(字符序列表示的数字), Number 的任意子类, javax.money.MonetaryAmount 的任意子类
@NotBlank
检查字符序列是否为空,以及去空格后的长度是否大于 0。与 @NotEmpty
的不同之处在于,此约束只能应用于字符序列,并且忽略尾随空格。
支持数据类型:CharSequence
@NotNull
检查值是否不为 null
支持数据类型:任何类型
@NotEmpty
检查元素是否为 null
或 空
支持数据类型:CharSequence, Collection, Map, arrays
@Size(min=, max=)
检查元素个数是否在 min(含)和 max(含)之间
支持数据类型:CharSequence,Collection,Map, arrays
@Negative
检查元素是否严格为负数。零值被认为无效。
支持数据类型:
BigDecimal, BigInteger, byte, short, int, long, 原生类型的封装类, CharSequence 的任意子类(字符序列表示的数字), Number 的任意子类, javax.money.MonetaryAmount 的任意子类
@NegativeOrZero
检查元素是否为负或零。
支持数据类型:
BigDecimal, BigInteger, byte, short, int, long, 原生类型的封装类, CharSequence 的任意子类(字符序列表示的数字), Number 的任意子类, javax.money.MonetaryAmount 的任意子类
@Positive
检查元素是否严格为正。零值被视为无效。
支持数据类型:
BigDecimal, BigInteger, byte, short, int, long, 原生类型的封装类, CharSequence 的任意子类(字符序列表示的数字), Number 的任意子类, javax.money.MonetaryAmount 的任意子类
@PositiveOrZero
检查元素是否为正或零。
支持数据类型:
BigDecimal, BigInteger, byte, short, int, long, 原生类型的封装类, CharSequence 的任意子类(字符序列表示的数字), Number 的任意子类, javax.money.MonetaryAmount 的任意子类
@Null
检查值是否为 null
支持数据类型:任何类型
@Future
检查日期是否在未来
支持的数据类型:
java.util.Date, java.util.Calendar, java.time.Instant, java.time.LocalDate, java.time.LocalDateTime, java.time.LocalTime, java.time.MonthDay, java.time.OffsetDateTime, java.time.OffsetTime, java.time.Year, java.time.YearMonth, java.time.ZonedDateTime, java.time.chrono.HijrahDate, java.time.chrono.JapaneseDate, java.time.chrono.MinguoDate, java.time.chrono.ThaiBuddhistDate
如果 Joda Time API 在类路径中,ReadablePartial
和ReadableInstant
的任何实现类
@FutureOrPresent
检查日期是现在或将来
支持数据类型:同@Future
@Past
检查日期是否在过去
支持数据类型:同@Future
@PastOrPresent
检查日期是否在过去或现在
支持数据类型:同@Future
@Pattern(regex=, flags=)
根据给定的 flag
匹配,检查字符串是否与正则表达式 regex
匹配
支持数据类型:CharSequence
使用实例
自定义ValidatorUtils
public class ValidatorUtils {
private static Validator validator;
// 初始化 validator
static {
validator = Validation.buildDefaultValidatorFactory().getValidator();
}
/**
* 校验数据
*
* @param object
* @param groups
*/
public static void validateEntity(Object object, Class<?>... groups) {
Set<ConstraintViolation<Object>> constraintViolations = null;
try {
constraintViolations = validator.validate(object, groups);
} catch (Exception e) {
e.printStackTrace();
throw new ApiException("校验失败!");
}
if (!constraintViolations.isEmpty()) {
Iterator<ConstraintViolation<Object>> iterator = constraintViolations.iterator();
StringBuffer sb = new StringBuffer();
while (iterator.hasNext()) {
ConstraintViolation<Object> constraint = iterator.next();
sb.append(getMsg(constraint.getMessage()));
if (iterator.hasNext()) {
sb.append(",");
}
}
throw new ApiException(sb.toString());
}
}
private static String getMsg(String code) {
try {
return MessageUtils.message(code);
} catch (Exception e) {
return code;
}
}
}
示例
/** 省略代码 **/
public ApiResult add(@Valid @RequestBody SysUser user,BindingResult result) {
if(result.hasErrors()){
StringBuilder msg = new StringBuilder();
for (ObjectError error : result.getAllErrors()) {
msg.append(error.getDefaultMessage()+"\n");
}
return error(msg.toString());
}
return toApi(userService.insertUser(user));
}
public ApiResult add1(@Validated @RequestBody SysUser user) {
return toApi(userService.insertUser(user));
}
public ApiResult add2(@RequestBody ComUser bo) {
ValidatorUtils.validateEntity(bo, AddGroup.class);
return toApi(iComUserService.add(bo));
}
/** 省略代码 **/