内容简介:掌握Java-Bean Validation
数据校验虽然简单,但是却是一个繁琐的事。我在无数的代码看到if判断参数,然后错了打日志抛异常,一片一片的这种代码,如果有点重复了,再弄出N个xxUtil来归纳代码。虽然这种做法可以达到效果,但是代码散乱,一个是编写麻烦,一个是不易阅读。
Java业界最喜欢搞规范,所以参数校验作为一个痛点,JSR 303 - Bean Validation规范出现了。
JSR 303 – Bean Validation 是一个数据验证的规范,2009年11月确定最终方案。2009年12月Java EE 6发布,Bean Validation作为一个重要特性被包含其中。Hibernate Validator是 Bean Validation 的参考实现。Hibernate Validator提供了JSR 303规范中所有内置constraint的实现,除此之外还有一些附加的constraint。
constraint就是约束条件,比如不能为空之类的,这些条件被定义,然后就能被复用,而不是每次都在if语句里写。Bean Validation为Bean的验证定义了元数据模型和API,这里的元数据就是constant,元数据默认的形式是注解,还可以使用xml来定义constraint。
引入Bean Validation
<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.0.2.Final</version>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.6</version>
</dependency>
例子
我们先看看Bean Validation怎么用,有个大体的认识。首先声明需要被校验的Java Bean:
public class User{
@NotNull(message = "用户名不能为空")
private String name;
@Min(value = 1, message = "年龄不能小于1")
@Max(value = 200, message = "年龄不能大于200")
private int age;
// 构造函数,getter,setter略
}
在User Bean中我们使用了几个注解来修饰字段,name字段上添加 @NotNull
表示这个字段不能为空,age字段上添加 @Min
和 @Max
注解,表示限制其最大和最小值。这些constraint注解是Bean Validation规范内置的。全部内置的constraint说明见下文。
然后编写入口函数,实例化Bean并进行校验:
public static void main(String[] args){
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
Set<ConstraintViolation<User>> validate = validator.validate(new User(null, 0));
for (ConstraintViolation<User> violation : validate) {
System.out.println(violation.getMessage());
}
}
输出:
用户名不能为空 年龄不能小于1
Bean Validation内置constraint
JSR 303内置了常用的constraint,我们可以直接使用。
空检查
-
@Null被注释的元素必须为 null (任何类型) -
@NotNull被注释的元素必须不为 null (任何类型)
布尔检查
-
@AssertTrue被注释的元素必须为 true (boolean或者Boolean) -
@AssertFalse被注释的元素必须为 false (boolean或者Boolean)
数字检查
-
@Min(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值 (BigDecimal,BigInteger,byte,short,int,long及其包装类) -
@Max(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值 -
@DecimalMin(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值 (CharSequence,BigDecimal,BigInteger,byte,short,int,long及其包装类) -
@DecimalMax(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值 -
@Digits (integer, fraction)被注释的元素必须是一个数字,其值必须在可接受的范围内 (BigDecimal,BigInteger,byte,short,int,long及其包装类)
字符串(集合)检查
-
@Size(max, min)被注释的元素的大小必须在指定的范围内 (CharSequence,Collection,Map,Array) -
@Pattern(value)被注释的元素必须符合指定的正则表达式 (CharSequence)
时间检查
-
@Past被注释的元素必须是一个过去的日期 (Date,Calendar) -
@Future被注释的元素必须是一个将来的日期 (Date,Calendar)
Hibernate Validator扩展的constraint
Hibernate除了实现标准的constraint,还实现了一些扩展constraint。
-
@NotEmpty被注释的字符串的必须非空 -
@NotBlank被注释的字符串的必须非空白 -
@Range被注释的元素必须在合适的范围内 (内部使用@Min和@Max实现) -
@Length被注释的字符串的大小必须在指定的范围内(同@Size) -
@URL被注释的字符串必须是合法的URL -
@Email被注释的元素必须是电子邮箱地址 -
@SafeHtml被注解的字符串必须是合法的HTML -
@CreditCardNumber被注释的元素必须是合法的信用卡号,使用的是Luhn算法 -
@ScriptAssert直接指定脚本进行校验,算是最灵活的了
自定义Constraint
虽然Bean Validation规范提供了内置的constraint,但是对于实际使用来说是根本不够用的,业务的规则千奇百怪,是需要自己自定义constraint的。
定制一个constraint需要两个部分,一个是constraint注解,一个是执行校验逻辑的类。
比如我们想要定制一个UUID格式字符串的constraint,可以这么写:
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = UUIDValidator.class)
public @interface UUID {
Stringmessage()default "UUID不合法";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
constraint注解需要使用 @Constraint(validatedBy = UUIDValidator.class)
来指定这个注解是一个Bean Validation注解,并且指定对应的校验规则实现类。
同时,constraint注解必须是 @Retention(RetentionPolicy.RUNTIME)
,因为在运行是需要使用到注解。
然后编写校验规则实现类:
public class UUIDValidatorimplements ConstraintValidator<UUID,String>{
public static final Pattern UUID_PATTERN = Pattern.compile("[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}");
@Override
public void initialize(UUID uuid){
}
@Override
public boolean isValid(String object, ConstraintValidatorContext constraintValidatorContext){
if (object == null){
return true;
}
return UUID_PATTERN.matcher(object).matches();
}
}
实现类需要实现 ConstraintValidator<A extends Annotation, T>
接口,泛型参数 A
指定该类作用于什么constraint注解上, T
指定这个校验规则作用于什么数据类型。
因为一个constraint注解是可以作用于多种数据类型上的,比如 @Size
即可用于String上,也可以用于集合上,如何做到的呢?就是为一个constraint注解实现多个校验规则实现类,并指定不同的 T
参数。
Bean Validation 2.0
上面说的都是Bean Validation 1.0和1.1。这两个分别是在JavaEE6和JavaEE7中的。对应的JSR是JSR 303。
在2017年8月, Bean Validation 2.0 发布了。
Bean Validation 2.0是JavaEE8的一部分,只支持 Java 8+。对应的JSR是JSR 380。
Bean Validation的新功能:
-
支持验证泛型参数,比如
List<@Positive Integer> positiveNumbers-
可以更灵活的验证集合中的Bean,比如
Map<@Valid CustomerType, @Valid Customer> customersByType -
支持
java.util.Optional - 支持JavaFX声明的属性
-
可以更灵活的验证集合中的Bean,比如
-
@Past和@Futur支持JSR 310的时间类型 - 新增内置constraint:@Email, @NotEmpty, @NotBlank, @Positive, @PositiveOrZero, @Negative, @NegativeOrZero, @PastOrPresent and @FutureOrPresent
- 所有的内置constraint都是repeatable的
-
ConstraintValidator#initialize()是default方法,可选实现
引入Bean Validation 2.0:
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.2.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator-annotation-processor</artifactId>
<version>6.0.2.Final</version>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.6</version>
</dependency>
以上所述就是小编给大家介绍的《掌握Java-Bean Validation》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Twenty Lectures on Algorithmic Game Theory
Tim Roughgarden / Cambridge University Press / 2016-8-31 / USD 34.99
Computer science and economics have engaged in a lively interaction over the past fifteen years, resulting in the new field of algorithmic game theory. Many problems that are central to modern compute......一起来看看 《Twenty Lectures on Algorithmic Game Theory》 这本书的介绍吧!