java ee7 -- Java Bean验证
针对对象、对象成员、方法、构造函数的数据验证。
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--validate
username @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());
}
}
执行结果
email
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
java ee7 -- Java Bean验证的更多相关文章
- 开涛spring3(12.4) - 零配置 之 12.4 基于Java类定义Bean配置元数据
12.4 基于Java类定义Bean配置元数据 12.4.1 概述 基于Java类定义Bean配置元数据,其实就是通过Java类定义Spring配置元数据,且直接消除XML配置文件. 基于Java ...
- java ee7 配置文件
java ee7 配置文件 1. 项目目录 # ee pom.xml Maven构建文件 /src/main/java Java源文件 /src/main/resource ...
- Java中的数据验证
原文链接:https://www.cuba-platform.com/blog/2018-10-09/945 翻译:CUBA China CUBA-Platform 官网 : https://www. ...
- Java中的参数验证(非Spring版)
1. Java中的参数验证(非Spring版) 1.1. 前言 为什么我总遇到这种非正常问题,我们知道很多时候我们的参数校验都是放在controller层的传入参数进行校验,我们常用的校验方式就是引入 ...
- Spring学习系列(三) 通过Java代码装配Bean
上面梳理了通过注解来隐式的完成了组件的扫描和自动装配,下面来学习下如何通过显式的配置的装配bean 二.通过Java类装配bean 在前面定义了HelloWorldConfig类,并使用@Compon ...
- xml配置和基于java类的bean配置搭配使用
如果同时使用了xml配置,和java类的bean配置(当然估计项目中一般不会这样), 在初始化容器指定资源文件的时候可能会比较麻烦 此时我们可以把基于java类的bean配置整合到xml中,或xml的 ...
- 使用java连接AD域,验证账号password是否正确
web项目中有时候客户要求我们使用ad域进行身份确认,不再另外做一套用户管理系统.事实上客户就是仅仅要一套账号能够訪问全部的OA.CRM等办公系统. 这就是第三方验证.一般有AD域,Ldap,Radi ...
- java工具类(二)之java正则表达式表单验证
java正则表达式表单验证类工具类(验证邮箱.手机号码.qq号码等) 这篇文章主要介绍了java使用正则表达式进行表单验证工具类,可以验证邮箱.手机号码.qq号码等方法,需要的朋友可以参考下. jav ...
- Spring Boot 使用Java代码创建Bean并注册到Spring中
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/catoop/article/details/50558333 声明同一个类下的多个实例: packa ...
随机推荐
- 用zcat查看压缩日志中百度抓取的量
比如查看124.251.44.85这一台服务器的07-13,07-14,07-15的日志中百度抓取http://www.baidu.com/search/spider.html 的量 wc命令参考博客 ...
- jquery 1.9里面已经删除了toggle(fn1, fn2)函数:
jquery 1.9里面已经删除了toggle(fn1, fn2)函数:引用Note: This method signature was deprecated in jQuery 1.8 and r ...
- POJ3013 Big Christmas Tree
题目:http://poj.org/problem?id=3013 求每个点到1的最短路.不是最小生成树. 总是WA.看讨论里说INF至少2e10,于是真的A了! 算一下,dis最大可能3276800 ...
- CC2530中串口波特率改为9600时单个数据包来不及接收的解决方案
在调试CC2530过程中发现波特率改为9600时,单个包仅有3个Byte时,接收DMA就会启动 因而数据包被强迫拆分成多个,显然只要将接收DMA启动延时做到足够大即可. 具体修改内容如下图所示: 经过 ...
- Thinkphp自动验证规则
其实说白了,这篇文章就是转给自己看的,省的下次用的时候满网络找了.有需要的同学也可以看看.自动验证是非常有用的一个技术.平常的验证基本就是,用户名是否为空,用户名是否重复,密码,重复密码是否一致.官方 ...
- 【shell】grep命令
1.作用Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来.grep全称是Global Regular Expression Print,表示全局 ...
- innotop监控mysql
InnoTop 是一个系统活动报告,类似于Linux性能工具,它与Linux的top命令相仿,并参考mytop工具而设计. 它专门用后监控InnoDB性能和MySQL服务器.主要用于监控事务,死锁,外 ...
- Oracle 10g下emctl start dbconsole 报错:OC4J Configuration issue 问题解决
http://blog.sina.com.cn/s/blog_95b5eb8c0100x4a7.html http://blog.csdn.net/sz_bdqn/article/details/17 ...
- ComboBox智能搜索功能
cmbList.AutoCompleteSource = AutoCompleteSource.ListItems; cmbList.AutoCompleteMode = AutoCompleteMo ...
- 【C#】datetimepicker里面如何设置日期为当天日期,而时间设为0:00或23:59?
今天无意中发现要根据日期查询时间,datatimepicker控件会把时间默认成当前时间(当你的控件只显示日期时),这样查询出来的出来的数据会有误差,用来下面的办法成功设置日期为当天日期,而时间设为0 ...