原作传送: justry_deng
原作传送:
JSR(Java Specification Requests)是Java界的重要标准;JSR又细分很多标准,其中JSR303就代表Bean Validation。更多细节可参考:https://jcp.org/en/jsr/detail?id=303
JSR303定义的校验类型
空检查
@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=) 验证注解的元素值长度在min和max区间内
日期检查
@Past 验证 Date 和 Calendar 对象是否在当前时间之前
@Future 验证 Date 和 Calendar 对象是否在当前时间之后
@Pattern 验证 String 对象是否符合正则表达式的规则
数值检查,建议使用在Stirng,Integer类型,不建议使用在int类型上,因为表单值为“”时无法转换为int,但可以转换为Stirng为"",Integer为null
@Min 验证 Number 和 String 对象是否大等于指定的值
@Max 验证 Number 和 String 对象是否小等于指定的值
@DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度
@DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度
@Digits 验证 Number 和 String 的构成是否合法
@Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。
@Range(min=, max=) 验证注解的元素值在最小值和最大值之间
@Range(min=10000,max=50000,message="range.bean.wage")
private BigDecimal wage;
@Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证)
@CreditCardNumber信用卡验证
@Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证。
@ScriptAssert(lang= ,script=, alias=)
@URL(protocol=,host=, port=,regexp=, flags=)
环境
SpringBoot引入相关依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
约束性注解
常用的注解
@AssertFalse
可以为null,如果不为null的话必须为false
@AssertTrue
可以为null,如果不为null的话必须为true
@DecimalMax
设置不能超过最大值
@DecimalMin
设置不能超过最小值
@Digits
设置必须是数字且数字整数的位数和小数的位数必须在指定范围内
@Future
日期必须在当前日期的未来
@Past
日期必须在当前日期的过去
@Max
最大不得超过此最大值
@Min
最大不得小于此最小值
@NotNull
不能为null,可以是空
@Null
必须为null
@Pattern
必须满足指定的正则表达式
@Size
集合、数组、map等的size()值必须在指定范围内
必须是email格式
@Length
长度必须在指定范围内
@NotBlank
字符串不能为null,字符串trim()后也不能等于“”
@NotEmpty
不能为null,集合、数组、map等size()不能为0;字符串trim()后可以等于“”
@Range
值必须在指定范围内
@URL
必须是一个URL
@Validated的使用时机
@Validated的使用位置较多(可详见源码),但其主流的使用位置却是以下两种:
1、
在Controller层中,放在模型参数对象前
当Controller层中参数是一个对象模型时,只有将@Validated直接放在该模型前,该模型内部的字段才会被
校验(如果有对该模型的字段进行约束的话)。
2、
在Controller层中,放在类上
当一些约束是直接出现在Controller层中的参数前时,只有将@Validated放在类上时,参数前的约束才会生效。
以下是简单的测试代码:
@Validated与@Valid的简单对比说明
@Valid注解与@Validated注解功能大部分类似;两者的不同主要在于:
@Valid属于
javax
下的,而@Validated属于spring
下;
@Valid支持嵌套校验、而@Validated不支持,
@Validated支持分组,而@Valid不支持。
测试一下上述各注解
测试所用模型为:
import lombok.Getter;
import lombok.Setter;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.Range;
import org.hibernate.validator.constraints.URL;
import javax.validation.constraints.*;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* Validation注解
*
* @author JustryDeng
* @date 2019/1/15 0:43
*/
public class ValidationBeanModel {
@Setter
@Getter
public class AbcAssertFalse {
@AssertFalse
private Boolean myAssertFalse;
}
@Setter
@Getter
public class AbcAssertTrue {
@AssertTrue
private Boolean myAssertTrue;
}
@Setter
@Getter
public class AbcDecimalMax {
@DecimalMax(value = "12.3")
private String myDecimalMax;
}
@Setter
@Getter
public class AbcDecimalMin {
@DecimalMin(value = "10.3")
private String myDecimalMin;
}
@Setter
@Getter
public class AbcDigits {
@Digits(integer = 5, fraction = 3)
private Integer myDigits;
}
@Setter
@Getter
public class AbcEmail {
@Email
private String myEmail;
}
@Setter
@Getter
public class AbcFuture {
@Future
private Date myFuture;
}
@Setter
@Getter
public class AbcLength {
@Length(min = 5, max = 10)
private String myLength;
}
@Setter
@Getter
public class AbcMax {
@Max(value = 200)
private Long myMax;
}
@Setter
@Getter
public class AbcMin {
@Min(value = 100)
private Long myMin;
}
@Setter
@Getter
public class AbcNotBlank {
@NotBlank
private String myStringNotBlank;
@NotBlank
private String myObjNotBlank;
}
@Setter
@Getter
public class AbcNotEmpty {
@NotEmpty
private String myStringNotEmpty;
@NotEmpty
private String myNullNotEmpty;
@NotEmpty
private Map<String, Object> myMapNotEmpty;
@NotEmpty
private List<Object> myListNotEmpty;
@NotEmpty
private Object[] myArrayNotEmpty;
}
@Setter
@Getter
public class AbcNotNull {
@NotNull
private String myStringNotNull;
@NotNull
private Object myNullNotNull;
@NotNull
private Map<String, Object> myMapNotNull;
}
@Setter
@Getter
public class AbcNull {
@Null
private String myStringNull;
@Null
private Map<String, Object> myMapNull;
}
@Setter
@Getter
public class AbcPast {
@Past
private Date myPast;
}
@Setter
@Getter
public class AbcPattern {
@Pattern(regexp = "\\d+")
private String myPattern;
}
@Setter
@Getter
public class AbcRange {
@Range(min = 100, max = 100000000000L)
private Double myRange;
}
@Setter
@Getter
public class AbcSize {
@Size(min = 3, max = 5)
private List<Integer> mySize;
}
@Setter
@Getter
public class AbcURL {
@URL
private String myURL;
}
}
import com.aspire.model.*;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.util.*;
@RunWith(SpringRunner.class)
@SpringBootTest
public class ValidationDemoApplicationTests {
private Validator validator;
@Before
public void initValidator() {
ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
validator = validatorFactory.getValidator();
}
/**
* 在myAssertTrue属性上加@AssertTrue注解
* <p>
* 程序输出: com.aspire.model.ValidationBeanModel$AbcAssertTrue类的myAssertTrue属性 -> 只能为true
*/
@Test
public void testAssertTrue() {
ValidationBeanModel.AbcAssertTrue vm = new ValidationBeanModel().new AbcAssertTrue();
vm.setMyAssertTrue(false);
fa(vm);
}
/**
* 在myAssertFalse属性上加@AssertFalse注解
* <p>
* 程序输出: com.aspire.model.ValidationBeanModel$AbcAssertFalse类的myAssertFalse属性 -> 只能为false
*/
@Test
public void testAssertFalse() {
ValidationBeanModel.AbcAssertFalse vm = new ValidationBeanModel().new AbcAssertFalse();
vm.setMyAssertFalse(true);
fa(vm);
}
/**
* 在myDecimalMax属性上加@DecimalMax(value = "12.3")注解
* <p>
* 程序输出: com.aspire.model.ValidationBeanModel$AbcDecimalMax类的myDecimalMax属性 -> 必须小于或等于12.3
*/
@Test
public void testDecimalMax() {
ValidationBeanModel.AbcDecimalMax vm = new ValidationBeanModel().new AbcDecimalMax();
vm.setMyDecimalMax("123");
fa(vm);
}
/**
* 在myDecimalMin属性上加@DecimalMin(value = "10.3")注解
* <p>
* 程序输出: com.aspire.model.ValidationBeanModel$AbcDecimalMin类的myDecimalMin属性 -> 必须大于或等于10.3
*/
@Test
public void testDecimalMin() {
ValidationBeanModel.AbcDecimalMin vm = new ValidationBeanModel().new AbcDecimalMin();
vm.setMyDecimalMin("1.23");
fa(vm);
}
/**
* 在myDigits属性上加@Digits(integer = 5, fraction = 3)注解
* <p>
* 程序输出: com.aspire.model.ValidationBeanModel$AbcDigits类的myDigits属性 -> 数字的值超出了允许范围(只允许在5位整数和3位小数范围内)
*/
@Test
public void testDigits() {
ValidationBeanModel.AbcDigits vm = new ValidationBeanModel().new AbcDigits();
vm.setMyDigits(1000738);
fa(vm);
}
/**
* 在myEmail属性上加@Email注解
* <p>
* 程序输出: com.aspire.model.ValidationBeanModel$AbcEmail类的myEmail属性 -> 不是一个合法的电子邮件地址
*/
@Test
public void testEmail() {
ValidationBeanModel.AbcEmail vm = new ValidationBeanModel().new AbcEmail();
vm.setMyEmail("asd@.com");
fa(vm);
}
/**
* 在myFuture属性上加@Future注解
* <p>
* 程序输出: com.aspire.model.ValidationBeanModel$AbcFuture类的myFuture属性 -> 需要是一个将来的时间
*/
@Test
public void testFuture() {
ValidationBeanModel.AbcFuture vm = new ValidationBeanModel().new AbcFuture();
vm.setMyFuture(new Date(10000L));
fa(vm);
}
/**
* 在myLength属性上加@Length(min = 5, max = 10)注解
* <p>
* 程序输出: com.aspire.model.ValidationBeanModel$AbcLength类的myLength属性 -> 长度需要在5和10之间
*/
@Test
public void testLength() {
ValidationBeanModel.AbcLength vm = new ValidationBeanModel().new AbcLength();
vm.setMyLength("abcd");
fa(vm);
}
/**
* 在myMax属性上加@Max(value = 200)注解
* <p>
* 程序输出: com.aspire.model.ValidationBeanModel$AbcMax类的myMax属性 -> 最大不能超过200
*/
@Test
public void testMax() {
ValidationBeanModel.AbcMax vm = new ValidationBeanModel().new AbcMax();
vm.setMyMax(201L);
fa(vm);
}
/**
* 在myMin属性上加@Min(value = 200)注解
* <p>
* 程序输出: com.aspire.model.ValidationBeanModel$AbcMin类的myMin属性 -> 最小不能小于100
*/
@Test
public void testMin() {
ValidationBeanModel.AbcMin vm = new ValidationBeanModel().new AbcMin();
vm.setMyMin(99L);
fa(vm);
}
/**
* 在myStringNotBlank属性上加@NotBlank注解
* 在myObjNotBlank属性上加@NotBlank注解
*
* 注:如果属性值为null 或者 .trim()后等于"",那么会提示 不能为空
* <p>
* 程序输出: com.aspire.model.ValidationBeanModel$AbcNotBlank类的myObjNotBlank属性 -> 不能为空
* com.aspire.model.ValidationBeanModel$AbcNotBlank类的myStringNotBlank属性 -> 不能为空
*/
@Test
public void testNotBlank() {
ValidationBeanModel.AbcNotBlank vm = new ValidationBeanModel().new AbcNotBlank();
vm.setMyObjNotBlank(null);
vm.setMyStringNotBlank(" ");
fa(vm);
}
/**
* 在myStringNotEmpty属性上加@NotEmpty注解
* 在myNullNotEmpty属性上加@NotEmpty注解
* 在myMapNotEmpty属性上加@NotEmpty注解
* 在myListNotEmpty属性上加@NotEmpty注解
* 在myArrayNotEmpty属性上加@NotEmpty注解
*
* 注:String可以是.trim()后等于""的字符串,但是不能为null
* 注:MAP、Collection、Array既不能是空,也不能是null
*
* <p>
* 程序输出: com.aspire.model.ValidationBeanModel$AbcNotEmpty类的myNullNotEmpty属性 -> 不能为空
* com.aspire.model.ValidationBeanModel$AbcNotEmpty类的myListNotEmpty属性 -> 不能为空
* com.aspire.model.ValidationBeanModel$AbcNotEmpty类的myArrayNotEmpty属性 -> 不能为空
* com.aspire.model.ValidationBeanModel$AbcNotEmpty类的myMapNotEmpty属性 -> 不能为空
*/
@Test
public void testNotEmpty() {
ValidationBeanModel.AbcNotEmpty vm = new ValidationBeanModel().new AbcNotEmpty();
vm.setMyStringNotEmpty(" ");
vm.setMyNullNotEmpty(null);
vm.setMyMapNotEmpty(new HashMap<>(0));
vm.setMyListNotEmpty(new ArrayList<>(0));
vm.setMyArrayNotEmpty(new String[]{});
fa(vm);
}
/**
* 在myStringNotNull属性上加@NotNull注解
* 在myNullNotNull属性上加@NotNull注解
* 在myMapNotNull属性上加@NotNull注解
*
* 注:属性值可以是空的, 但是就是不能为null
* <p>
* 程序输出: com.aspire.model.ValidationBeanModel$AbcNotNull类的myNullNotNull属性 -> 不能为null
*/
@Test
public void testNotNull() {
ValidationBeanModel.AbcNotNull vm = new ValidationBeanModel().new AbcNotNull();
vm.setMyStringNotNull(" ");
vm.setMyNullNotNull(null);
vm.setMyMapNotNull(new HashMap<>(0));
fa(vm);
}
/**
* 在myStringNull属性上加@Null注解
* 在myMapNotNull属性上加@Null注解
*
* 注:属性值必须是null, 是空都不行
* <p>
* 程序输出: com.aspire.model.ValidationBeanModel$AbcNull类的myMapNull属性 -> 必须为null
* com.aspire.model.ValidationBeanModel$AbcNull类的myStringNull属性 -> 必须为null
*/
@Test
public void testNull() {
ValidationBeanModel.AbcNull vm = new ValidationBeanModel().new AbcNull();
vm.setMyStringNull(" ");
vm.setMyMapNull(new HashMap<>(0));
fa(vm);
}
/**
* 在myPast属性上加@Past注解
*
* <p>
* 程序输出: com.aspire.model.ValidationBeanModel$AbcPast类的myPast属性 -> 需要是一个过去的时间
*/
@Test
public void testPast() {
ValidationBeanModel.AbcPast vm = new ValidationBeanModel().new AbcPast();
vm.setMyPast(new Date(20000000000000000L));
fa(vm);
}
/**
* 在myPattern属性上加@Pattern(regexp = "\\d+")注解
*
* <p>
* 程序输出: com.aspire.model.ValidationBeanModel$AbcPattern类的myPattern属性 -> 需要匹配正则表达式"\d"
*/
@Test
public void testPattern() {
ValidationBeanModel.AbcPattern vm = new ValidationBeanModel().new AbcPattern();
vm.setMyPattern("ABC");
fa(vm);
}
/**
* 在myRange属性上加@Range(min = 100, max = 100000000000L)注解
*
* <p>
* 程序输出: com.aspire.model.ValidationBeanModel$AbcRange类的myRange属性 -> 需要在100和100000000000之间
*/
@Test
public void testRange() {
ValidationBeanModel.AbcRange vm = new ValidationBeanModel().new AbcRange();
vm.setMyRange(32222222222222222222222222222222.323);
fa(vm);
}
/**
* 在mySize属性上加@Size(min = 3, max = 5)注解
*
* <p>
* 程序输出: com.aspire.model.ValidationBeanModel$AbcSize类的mySize属性 -> 个数必须在3和5之间
*/
@Test
public void testSize() {
ValidationBeanModel.AbcSize vm = new ValidationBeanModel().new AbcSize();
List<Integer> list = new ArrayList<>(4);
list.add(0);
list.add(1);
vm.setMySize(list);
fa(vm);
}
/**
* 在myURL属性上加@URL注解
*
* <p>
* 程序输出: com.aspire.model.ValidationBeanModel$AbcURL类的myURL属性 -> 需要是一个合法的URL
*/
@Test
public void testURL() {
ValidationBeanModel.AbcURL vm = new ValidationBeanModel().new AbcURL();
vm.setMyURL("www.baidu.xxx");
fa(vm);
}
private <T> void fa(T obj) {
Set<ConstraintViolation<T>> cvSet = validator.validate(obj);
for (ConstraintViolation<T> cv : cvSet) {
System.err.println(cv.getRootBean().getClass().getName() + "类的"
+ cv.getPropertyPath() + "属性 -> " + cv.getMessage());
}
}
}