针对对象、对象成员、方法、构造函数的数据验证。
1. 一个验证的小例子
(1) 添加引用jar
<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.7.Final</version> </dependency> <dependency> <groupId>org.glassfish</groupId> <artifactId>javax.el</artifactId> <version>3.0.1-b09</version> </dependency>
(2) 编写工具类
public static <T> void validate(T t) throws ValidationException { ValidatorFactory vFactory = Validation.buildDefaultValidatorFactory(); Validator validator = vFactory.getValidator(); Set<ConstraintViolation<T>> set = validator.validate(t); if (set.size() > 0) { StringBuilder validateError = new StringBuilder(); for (ConstraintViolation<T> val : set) { validateError.append(val.getMessage()); } throw new ValidationException(validateError.toString()); } }
(3) 编写bean
package beans; import javax.validation.constraints.NotNull; public class Person { @NotNull(message="用户名不能为空") private String username; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } }
(4) 编写测试类
package init; import javax.xml.bind.ValidationException; import beans.Person; import validation.ValidationUtil; public class Test { public static void main(String [] args ){ Person person = new Person(); try { ValidationUtil.validate(person); } catch (ValidationException e) { System.out.println(e.getMessage()); //输出结果是:用户名不能为空 } } }
(5)输出结果
用户名不能为空
2. 内置bean验证约束
(1)@AsserFalse
字段的值必须是false.
(2)@AsserTrue
字段的值必须是true.
(3)@DecimalMax
字段的值必须是一个小数值,应小于或者等于value元素中的数
(4)@DecimalMin
字段的值必须是一个小数值,应该大于或者等于value元素中的数
(5)@Digits
字段必须是指定范围内的一个数,integer元素指定了这个数的最大小整数位数,ftaction元素指定这个数的最大小数
(6)@Future
字段的值必须是将来一个日期
(7)@Max
字段必须是一个整数类型,应该小于或者等于value的数
(8)@Min
字段必须一个整数类型,应该大于或者等于value的数
(9)NotNull
字段的值必须不能为空
(10)@Null
字段的值必须为空
(11)@Past
字段的值必须是过去的一个日期
(12)@Pattern
字段的值必须与正则表达式匹配
(13)@Size
字段的大小,必须指定在一个范围匹配
package beans.validation; import java.math.BigDecimal; import java.util.Date; import java.util.List; import java.util.Map; import javax.validation.constraints.AssertFalse; import javax.validation.constraints.AssertTrue; import javax.validation.constraints.DecimalMax; import javax.validation.constraints.DecimalMin; import javax.validation.constraints.Digits; import javax.validation.constraints.Future; import javax.validation.constraints.Max; import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; import javax.validation.constraints.Null; import javax.validation.constraints.Past; import javax.validation.constraints.Pattern; import javax.validation.constraints.Size; public class BuiltInValidationBean { @AssertTrue(message="isActive @AssertTrue 值应该为true") private boolean isActive; @AssertFalse(message="isUnsupported @AssertFalse 值应该为false") private boolean isUnsupported; @Max(value=100, message="quantityMax @Max 最大值是100") private int quantityMax; @Min(value=10, message="quantityMin @Min 最小值是10") private int quantityMin; @DecimalMax(value="100", message="discountMax @DecimalMax 最大值是100") private BigDecimal discountMax; @DecimalMin(value="10", message="discountMin @DecimalMin 最小值是10") private BigDecimal discountMin; @Digits(integer=3, fraction=1, message="price @Digits 最大整数位数是3, 最大小数位数是1") private BigDecimal price; @Future(message="eventDate @Future 字段值必须是一个将来的日期") private Date eventDate; @Past(message="birthday @Past 字段值必须是一个过去的日期") private Date birthday; @NotNull(message="username @NotNull username不能为空") private String username; @Null(message="unusedString @Null unusedString必须为空") private String unusedString; @Pattern(regexp="\\(\\d(3)\\)\\d{9}", message="phoneNumber @Pattern 手机号码不正确") private String phoneNumber; @Size(min=2, max=8, message="briefMessage @Size 字符串最短2,最长8") private String briefMessage; @Size(min=2, max=8, message="briefList @Size list最短2,最长8") private List<String> briefList; @Size(min=2, max=8, message="briefMap @Size map最短2,最长8") private Map<String, String> briefMap; public boolean isActive() { return isActive; } public void setActive(boolean isActive) { this.isActive = isActive; } public boolean isUnsupported() { return isUnsupported; } public void setUnsupported(boolean isUnsupported) { this.isUnsupported = isUnsupported; } public int getQuantityMax() { return quantityMax; } public void setQuantityMax(int quantityMax) { this.quantityMax = quantityMax; } public int getQuantityMin() { return quantityMin; } public void setQuantityMin(int quantityMin) { this.quantityMin = quantityMin; } public BigDecimal getDiscountMax() { return discountMax; } public void setDiscountMax(BigDecimal discountMax) { this.discountMax = discountMax; } public BigDecimal getDiscountMin() { return discountMin; } public void setDiscountMin(BigDecimal discountMin) { this.discountMin = discountMin; } public BigDecimal getPrice() { return price; } public void setPrice(BigDecimal price) { this.price = price; } public Date getEventDate() { return eventDate; } public void setEventDate(Date eventDate) { this.eventDate = eventDate; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getUnusedString() { return unusedString; } public void setUnusedString(String unusedString) { this.unusedString = unusedString; } public String getPhoneNumber() { return phoneNumber; } public void setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber; } public String getBriefMessage() { return briefMessage; } public void setBriefMessage(String briefMessage) { this.briefMessage = briefMessage; } public List<String> getBriefList() { return briefList; } public void setBriefList(List<String> briefList) { this.briefList = briefList; } public Map<String, String> getBriefMap() { return briefMap; } public void setBriefMap(Map<String, String> briefMap) { this.briefMap = briefMap; } }
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency>
Validates all constraints on object -- 验证所有字段
static ValidatorFactory vFactory = Validation.buildDefaultValidatorFactory(); static Validator validator = vFactory.getValidator(); static ExecutableValidator executableValidator = validator.forExecutables(); public static <T> void validate(T object, Class<?>... groups) throws ValidationException { Set<ConstraintViolation<T>> set = validator.validate(object, groups); if (set.size() > 0) { StringBuilder validateError = new StringBuilder(); validateError.append("validate:\r\n"); for (ConstraintViolation<T> val : set) { validateError.append(val.getMessage()).append("\r\n"); } throw new ValidationException(validateError.toString()); } }
BuiltInValidationBean builtInValidationBean = new BuiltInValidationBean(); builtInValidationBean.setActive(false); builtInValidationBean.setUnsupported(true); builtInValidationBean.setQuantityMax(101); builtInValidationBean.setQuantityMin(9); builtInValidationBean.setDiscountMax(new BigDecimal("100.1")); builtInValidationBean.setDiscountMin(new BigDecimal("9.9")); builtInValidationBean.setPrice(new BigDecimal("9999")); builtInValidationBean.setEventDate(new Date(1999, 12, 31)); builtInValidationBean.setBirthday(new Date(2999, 12, 31)); builtInValidationBean.setUsername(null); builtInValidationBean.setUnusedString("test"); builtInValidationBean.setPhoneNumber(""); builtInValidationBean.setBriefMessage(""); builtInValidationBean.setBriefList(new ArrayList<>(20)); builtInValidationBean.setBriefMap(new HashMap<>(20)); try { ValidationUtil.validate(builtInValidationBean); } catch (ValidationException e) { System.out.println("builtInValidationTest--validate"); System.out.println(e.getMessage()); }
输出结果
builtInValidationTest--validateusername @NotNull username不能为空
briefMessage @Size 字符串最短2,最长8
quantityMin @Min 最小值是10
isUnsupported @AssertFalse 值应该为false
unusedString @Null unusedString必须为空
discountMax @DecimalMax 最大值是100
price @Digits 最大整数位数是3, 最大小数位数是1
discountMin @DecimalMin 最小值是10
isActive @AssertTrue 值应该为true
quantityMax @Max 最大值是100
birthday @Past 字段值必须是一个过去的日期
briefList @Size list最短2,最长8
phoneNumber @Pattern 手机号码不正确
briefMap @Size map最短2,最长8
Validates all constraints placed on the property of object named propertyName -- 验证指定字段
public static <T> void validateProperty(T object, String propertyName, Class<?>... groups) throws ValidationException { ValidatorFactory vFactory = Validation.buildDefaultValidatorFactory(); Validator validator = vFactory.getValidator(); Set<ConstraintViolation<T>> set = validator.validateProperty(object, propertyName, groups); if (set.size() > 0) { StringBuilder validateError = new StringBuilder(); validateError.append("validateProperty:\r\n"); for (ConstraintViolation<T> val : set) { validateError.append(val.getMessage()).append("\r\n"); } throw new ValidationException(validateError.toString()); } }
builtInValidationBean = new BuiltInValidationBean(); builtInValidationBean.setBriefMessage(""); try { ValidationUtil.validateProperty(builtInValidationBean, "briefMessage"); } catch (ValidationException e) { System.out.println("builtInValidationTest--validateProperty"); System.out.println(e.getMessage()); }
输出结果
builtInValidationTest--validateProperty
briefMessage @Size 字符串最短2,最长8
正则表达式全部符号解释
字符 | 描述 |
---|---|
\ | 将下一个字符标记为一个特殊字符、或一个原义字符、或一个 向后引用、或一个八进制转义符。例如,'n' 匹配字符 "n"。'\n' 匹配一个换行符。序列 '\\' 匹配 "\" 而 "\(" 则匹配 "("。 |
^ | 匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 '\n' 或 '\r' 之后的位置。 |
$ | 匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 '\n' 或 '\r' 之前的位置。 |
* | 匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等价于{0,}。 |
+ | 匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。 |
? | 匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}。 |
{n} | n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。 |
{n,} | n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。 |
{n,m} | m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。 |
? | 当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?' 将匹配单个 "o",而 'o+' 将匹配所有 'o'。 |
. | 匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。 |
(pattern) | 匹配 pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 $0…$9 属性。要匹配圆括号字符,请使用 '\(' 或 '\)'。 |
(?:pattern) | 匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 "或" 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 'industry|industries' 更简略的表达式。 |
(?=pattern) | 正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,'Windows (?=95|98|NT|2000)' 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 |
(?!pattern) | 负向预查,在任何不匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如'Windows (?!95|98|NT|2000)' 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始 |
x|y | 匹配 x 或 y。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 则匹配 "zood" 或 "food"。 |
[xyz] | 字符集合。匹配所包含的任意一个字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'。 |
[^xyz] | 负值字符集合。匹配未包含的任意字符。例如, '[^abc]' 可以匹配 "plain" 中的'p'。 |
[a-z] | 字符范围。匹配指定范围内的任意字符。例如,'[a-z]' 可以匹配 'a' 到 'z' 范围内的任意小写字母字符。 |
[^a-z] | 负值字符范围。匹配任何不在指定范围内的任意字符。例如,'[^a-z]' 可以匹配任何不在 'a' 到 'z' 范围内的任意字符。 |
\b | 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。 |
\B | 匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。 |
\cx | 匹配由 x 指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。 |
\d | 匹配一个数字字符。等价于 [0-9]。 |
\D | 匹配一个非数字字符。等价于 [^0-9]。 |
\f | 匹配一个换页符。等价于 \x0c 和 \cL。 |
\n | 匹配一个换行符。等价于 \x0a 和 \cJ。 |
\r | 匹配一个回车符。等价于 \x0d 和 \cM。 |
\s | 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。 |
\S | 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。 |
\t | 匹配一个制表符。等价于 \x09 和 \cI。 |
\v | 匹配一个垂直制表符。等价于 \x0b 和 \cK。 |
\w | 匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。 |
\W | 匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。 |
\xn | 匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,'\x41' 匹配 "A"。'\x041' 则等价于 '\x04' & "1"。正则表达式中可以使用 ASCII 编码。. |
\num | 匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,'(.)\1' 匹配两个连续的相同字符。 |
\n | 标识一个八进制转义值或一个向后引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为向后引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。 |
\nm | 标识一个八进制转义值或一个向后引用。如果 \nm 之前至少有 nm 个获得子表达式,则 nm 为向后引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的向后引用。如果前面的条件都不满足,若 n 和 m 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm。 |
\nml | 如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值 nml。 |
\un | 匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, \u00A9 匹配版权符号 (?)。 |
3. 验证Null和空串
允许JSF将空串当作null处理
<context-param> <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name> <param-value>true</param-value> </context-param>如果某个元素有@NotNull约束, 且以上为true,则会传入null到bean验证, 会使@NotNull约束失败。
4. 验证构造函数
针对构造函数的参数设置bean约束;
package beans.validation; import java.math.BigDecimal; import javax.validation.constraints.Digits; import javax.validation.constraints.NotNull; public class ConstructorValidationBean { private String name; private BigDecimal salary; private String currency; public ConstructorValidationBean( @NotNull(message="name不能为空") String name, @NotNull(message="salary不能为空") @Digits(integer=6, fraction=2, message="工资最大整数位数是6, 最大小数位数是2") BigDecimal salary, @NotNull(message="currency不能为空") String currency) { this.name = name; this.salary = salary; this.currency = currency; } @NotNull(message="name/salary 不能为空") //跨参数约束, 应用于构造函数中所有参数 public ConstructorValidationBean(String name, BigDecimal salary) { this.name = name; this.salary = salary; } public String getName() { return name; } public void setName(String name) { this.name = name; } public BigDecimal getSalary() { return salary; } public void setSalary(BigDecimal salary) { this.salary = salary; } public String getCurrency() { return currency; } public void setCurrency(String currency) { this.currency = currency; } }
public static <T> void validateConstructorParameters(Constructor<? extends T> constructor, Object[] parameterValues, Class<?>... groups) throws ValidationException { Set<ConstraintViolation<T>> set = executableValidator.validateConstructorParameters(constructor, parameterValues, groups); if (set.size() > 0) { StringBuilder validateError = new StringBuilder(); validateError.append("validateConstructorParameters:\r\n"); for (ConstraintViolation<T> val : set) { validateError.append(val.getMessage()).append("\r\n"); } throw new ValidationException(validateError.toString()); } } public static <T> void validateConstructorReturnValue(Constructor<? extends T> constructor, T createdObject, Class<?>... groups) throws ValidationException { Set<ConstraintViolation<T>> set = executableValidator.validateConstructorReturnValue(constructor, createdObject, groups); if (set.size() > 0) { StringBuilder validateError = new StringBuilder(); validateError.append("validateConstructorReturnValue:\r\n"); for (ConstraintViolation<T> val : set) { validateError.append(val.getMessage()).append("\r\n"); } throw new ValidationException(validateError.toString()); } }
@Test public void constructorValidationBeanTest() throws Exception { Constructor<? extends ConstructorValidationBean> constructor = ConstructorValidationBean.class.getConstructor(String.class, BigDecimal.class, String.class); Object[] parameterValues = { null, new BigDecimal("8888888.88"),null }; try { ValidationUtil.validateConstructorParameters(constructor, parameterValues); } catch (ValidationException e) { System.out.println("constructorValidationBean--validateConstructorParameters"); System.out.println(e.getMessage()); } constructor = ConstructorValidationBean.class.getConstructor(String.class, BigDecimal.class); parameterValues = new Object[]{null, new BigDecimal("8888888.88")}; try { ValidationUtil.validateConstructorReturnValue(constructor, parameterValues); } catch (ValidationException e) { System.out.println("constructorValidationBean--validateConstructorParameters--跨参数约束"); System.out.println(e.getMessage()); } constructor = ConstructorValidationBean.class.getConstructor(String.class, BigDecimal.class); try { ValidationUtil.validateConstructorReturnValue(constructor, new ConstructorValidationBean(null, new BigDecimal("8888888.88"))); } catch (ValidationException e) { System.out.println("constructorValidationBean--validateConstructorReturnValue"); System.out.println(e.getMessage()); }
输出结果
constructorValidationBean--validateConstructorParameters
validateConstructorParameters:
name不能为空
currency不能为空
工资最大整数位数是6, 最大小数位数是2
5. 验证方法
针对非静态方法的参数以及非静态方法的返回值设置bean约束;
package beans.validation; import java.util.ArrayList; import java.util.List; import javax.validation.constraints.Max; import javax.validation.constraints.Size; public class MethodValidationBean { public void drive(@Max(80) int speedInMph) { // ... } @Size(min = 3, max = 8) public List<String> getPassengers() { return new ArrayList<>(); } }
public static <T> void validateParameters(T object, Method method, Object[] parameterValues, Class<?>... groups) throws ValidationException { Set<ConstraintViolation<T>> set = executableValidator.validateParameters(object, method, parameterValues, groups); if (set.size() > 0) { StringBuilder validateError = new StringBuilder(); validateError.append("validateParameters:\r\n"); for (ConstraintViolation<T> val : set) { validateError.append(val.getMessage()).append("\r\n"); } throw new ValidationException(validateError.toString()); } } public static <T> void validateReturnValue(T object, Method method, Object returnValue, Class<?>... groups) throws ValidationException { Set<ConstraintViolation<T>> set = executableValidator.validateReturnValue(object, method, returnValue, groups); if (set.size() > 0) { StringBuilder validateError = new StringBuilder(); validateError.append("validateReturnValue:\r\n"); for (ConstraintViolation<T> val : set) { validateError.append(val.getMessage()).append("\r\n"); } throw new ValidationException(validateError.toString()); } }
@Test public void methodValidationBeanTest() throws Exception { MethodValidationBean methodValidationBean = new MethodValidationBean(); Method method = MethodValidationBean.class.getMethod("drive", int.class); Object[] parameterValues = { 81 }; try { ValidationUtil.validateParameters(methodValidationBean, method, parameterValues); } catch (ValidationException e) { System.out.println("methodValidationBeanTest--validateParameters"); System.out.println(e.getMessage()); } method = MethodValidationBean.class.getMethod("getPassengers"); Object returnValue = Collections.emptyList(); try { ValidationUtil.validateReturnValue(methodValidationBean, method, returnValue); } catch (ValidationException e) { System.out.println("methodValidationBeanTest--validateReturnValue"); System.out.println(e.getMessage()); } }
执行结果
methodValidationBeanTest--validateParameters
validateParameters:
最大不能超过80
methodValidationBeanTest--validateReturnValue
validateReturnValue:
个数必须在3和8之间
6. 自定义约束
package beans.validation.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.validation.Constraint; import javax.validation.ConstraintTarget; import javax.validation.Payload; import javax.validation.constraints.Pattern; import validation.EmailValidator; @Pattern.List({ @Pattern(regexp="[a-z0-9!#$%&'*+/=?^_`{|}~-]+"+"(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*"+"@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?") }) @Constraint(validatedBy={EmailValidator.class}) @Documented @Target({ ElementType.METHOD,ElementType.FIELD,ElementType.ANNOTATION_TYPE,ElementType.CONSTRUCTOR,ElementType.PARAMETER }) @Retention(RetentionPolicy.RUNTIME) public @interface Email { String message() default "invalid email"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; String[] value() default {}; //设置约束 // ConstraintTarget validationAppliesTo() default ConstraintTarget.PARAMETERS; @Target({ ElementType.METHOD,ElementType.FIELD,ElementType.ANNOTATION_TYPE,ElementType.CONSTRUCTOR,ElementType.PARAMETER }) @Retention(RetentionPolicy.RUNTIME) @Documented @interface List{ Email[] value(); } }
package validation; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; import beans.validation.annotation.Email; public class EmailValidator implements ConstraintValidator<Email, String> { @Override public boolean isValid(String value, ConstraintValidatorContext context) { System.out.println(value); return true; } }
package beans.validation; import beans.validation.annotation.Email; public class EmailBean { @Email private String email; public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
@Test public void selfDefineValidationBeanTest() { EmailBean emailBean = new EmailBean(); emailBean.setEmail("email"); try { ValidationUtil.validate(emailBean); } catch (ValidationException e) { System.out.println("selfDefineValidationBeanTest--validate"); System.out.println(e.getMessage()); } }执行结果
selfDefineValidationBeanTest--validate
validate:
需要匹配正则表达式"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?"
去除约束目标的二义性
ConstraintTarget validationAppliesTo() default ConstraintTarget.PARAMETERS;
???
http://blog.csdn.net/java_1111/article/details/22603731
https://www.ibm.com/support/knowledgecenter/zh/SSEQTP_8.5.5/com.ibm.websphere.nd.multiplatform.doc/ae/cdat_beanvaljpa.html
7. 组合约束
(1) 验证组
约束组由接口表示,约束组也可由其它组继承(到时候也会验证超类中的所有约束)
interface Employee{} interface Manager extends Employee{} interface Contractor{}指定约束组
package beans.validation; import javax.validation.constraints.NotNull; public class ConstraintGroupBean { @NotNull(groups={Employee.class, Contractor.class}) private String workPhone; @NotNull(groups=Contractor.class) private String homePhone; public String getWorkPhone() { return workPhone; } public void setWorkPhone(String workPhone) { this.workPhone = workPhone; } public String getHomePhone() { return homePhone; } public void setHomePhone(String homePhone) { this.homePhone = homePhone; } }缺省情况下,如果在单个约束上没有指定验证组或多个组,那么使用 javax.validation.groups.Default 组来予以验证
(2) 指定验证顺序 GroupSequence
GroupSequence中第一个验证过了,才会验证第二个
https://www.jianshu.com/p/cf51061de60c?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes
https://stackoverflow.com/questions/30359124/java-groupsequenceprovider-for-validation-object-is-null-in-getvalidationgroup#
8. 使用 META-INF/validation.xml
https://docs.oracle.com/javaee/6/api/javax/validation/Configuration.html