主要内容
JSR-303 Validation
JSR-303 是 JAVA EE 中的一项子规范,叫做 Bean Validation,官方参考实现是Hibernate Validator。
本文以 spring boot
V2.4.6 版本为例说明如何使用。
更新历史
无
JSR 303 基本的校验规则
常用的
空检查
@Null
验证对象是否为null@NotNull
验证对象是否不为null, 无法查检长度为0的字符串@NotBlank
检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.@NotEmpty
检查约束元素是否为NULL或者是EMPTY.Booelan检查
@AssertTrue
验证 Boolean 对象是否为 true@AssertFalse
验证 Boolean 对象是否为 false长度检查
@Size(min=, max=)
验证对象(Array,Collection,Map,String)长度是否在给定的范围之内@Length(min=, max=)
验证约束字符串是否包含在最小和最大之间。日期检查
@Past
验证 Date 和 Calendar 对象是否在当前时间之前,验证成立的话被注释的元素一定是一个过去的日期@Future
验证 Date 和 Calendar 对象是否在当前时间之后,验证成立的话被注释的元素一定是一个将来的日期@Pattern
验证 String 对象是否符合正则表达式的规则,被注释的元素符合制定的正则表达式,regexp:正则表达式 flags: 指定Pattern.Flag 的数组,表示正则表达式的相关选项。数值检查
建议使用在Stirng,Integer类型,不建议使用在 int 类型上,因为表单值为 空 时无法转换为 int,@Min
验证 Number 和 String 对象是否大等于指定的值@Max
验证 Number 和 String 对象是否小等于指定的值@DecimalMax
被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度( Double, float, BigDecimal )@DecimalMin
被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度@Digits
验证 Number 和 String 的构成是否合法@Digits(integer=,fraction=)
验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。@Range(min=, max=)
被指定的元素必须在合适的范围内@Range(min=10000,max=50000,message=”range.bean.wage”)
@Valid
递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证)@CreditCardNumber
信用卡验证@Email
验证是否是邮件地址,如果为null,不进行验证,算通过验证。@ScriptAssert(lang= ,script=, alias=)
@URL(protocol=,host=, port=,regexp=, flags=)
spring 结合
自动触发
controller
在 controller 中搭配@Valid
BindingResult
使用, 校验entity的数据1
2
3
4
5
6
7
8
9
public ResponseEntity add( { AppEntity entity , BindingResult result)
if (result.hasErrors()) {
return ResponseEntity.badRequest().body(result.getAllErrors().stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage)
.reduce((m1, m2) -> m1 + ";" + m2)
.orElse("参数输入有误!"));
}
}Spring data jpa
Spring data jpa 在事务提交前也会触发,如果数据没通过校验会出现如下类似的异常1
2
3
4
5
6
7
8org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction
...
Caused by: javax.validation.ConstraintViolationException: Validation failed for classes [xxx.xxx.xxxEntity] during update time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
ConstraintViolationImpl{interpolatedMessage='不是金额形式', propertyPath=mobile, rootBeanClass=class xxx.xxx.xxxEntity, messageTemplate='不是金额形式'}
ConstraintViolationImpl{interpolatedMessage='个数必须在0和16之间', propertyPath=mobile, rootBeanClass=class xxx.xxx.xxxEntity, messageTemplate='{javax.validation.constraints.Size.message}'}
...这是异常,应该要避免出现。
手动触发
Bean Validation 还可自定义规划并且手动触发校验。
注意 MoneyValidator
和 Money
相互一致
自定义Validation注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19import xxx.MoneyValidator;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public Money {
String message() default"不是金额形式";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}自定义Validation校验
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23import xxx.Money;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.regex.Pattern;
public class MoneyValidator implements ConstraintValidator<Money, String> {
private String moneyReg = "^\\d+(\\.\\d{1,2})?$";//表示金额的正则表达式
private Pattern moneyPattern = Pattern.compile(moneyReg);
public void initialize(Money constraintAnnotation) {
ConstraintValidator.super.initialize(constraintAnnotation);
}
public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
if (value == null)
return true;
return moneyPattern.matcher(value).matches();
}
}手动触发
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import javax.validation.groups.Default;
import java.util.List;
import java.util.Set;
public class ServiceTest{
// 自动注入 validator
private Validator validator;
public void userTest() {
UrUserEntity user = new UrUserEntity();
user.setVersion(0);
user.setMobile("123456789012345678s");
// 手动触发
Set<ConstraintViolation<UrUserEntity>> violationSet = validator.validate(user, Default.class);
if (null != violationSet) {
String messages = violationSet.stream()
.map(ConstraintViolation::getMessage)
.reduce((m1, m2) -> m1 + ";" + m2)
.orElse("参数输入有误!");
System.out.println(messages);
}
}
}bean
1
2
3
4
5
6
7
8
9
10
public class UrUserEntity {
private String mobile;
...
}@Money 给 mobile校验仅仅是玩笑