java bean 验证
这篇文章总结了一些简单,快速的示例,这些示例说明了您想使用Java Beans Validation API(JSR 349,JSR 303)进行的最常见操作。 记住,Beans Validation独立于Java EE。 尽管它是作为Java EE兼容服务器的一部分内置的,但该API也可以在Java SE应用程序中轻松使用。 所有这些示例都使用Java SE。
要求
我使用以下主要技术完成了本文的所有工作。 您可能可以使用不同的技术或版本来做相同的事情,但不能保证。
- Java 1.8.0_65_x64
- NetBeans 8.2
- Maven 3.0.5(与NetBeans捆绑在一起)
<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.1.2.Final</version>
</dependency>
<dependency><groupId>javax.el</groupId><artifactId>javax.el-api</artifactId><version>2.2.4</version>
</dependency>
<dependency><groupId>org.glassfish.web</groupId><artifactId>javax.el</artifactId><version>2.2.4</version>
</dependency>
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope>
</dependency>
下载
访问我的GitHub页面https://github.com/mjremijan以查看我所有的开源项目。 这篇文章的代码位于: https : //github.com/mjremijan/thoth-beanvalidation
基本
此示例显示了使用内置的标准约束和内置的标准验证器进行Bean验证的基础。
清单1.1 –验证的Bean
package org.thoth.beanvalidation.basics;import javax.validation.constraints.NotNull;public class Widget {@NotNullprotected String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}
清单1.2 –如何验证
package org.thoth.beanvalidation.basics;import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;public class WidgetTest {protected Validator validator;@Beforepublic void before() {validator = Validation.buildDefaultValidatorFactory().getValidator();}@Testpublic void violations_size() {// setupWidget w = new Widget();// actionSet<ConstraintViolation<Widget>> violations= validator.validate(w);// assertAssert.assertEquals(1, violations.size());}@Testpublic void violation_message() {// setupWidget w = new Widget();// actionSet<ConstraintViolation<Widget>> violations= validator.validate(w);// assertConstraintViolation<Widget> v= violations.stream().findFirst().get();Assert.assertEquals("may not be null", v.getMessage());}@Testpublic void violation_messageTemplate() {// setupWidget w = new Widget();// actionSet<ConstraintViolation<Widget>> violations= validator.validate(w);// assertConstraintViolation<Widget> v= violations.stream().findFirst().get();Assert.assertEquals("{javax.validation.constraints.NotNull.message}", v.getMessageTemplate());}@Testpublic void violation_propertyPath() {// setupWidget w = new Widget();// actionSet<ConstraintViolation<Widget>> violations= validator.validate(w);// assertConstraintViolation<Widget> v= violations.stream().findFirst().get();Assert.assertEquals("name", v.getPropertyPath().toString());}
}
自定义消息模板
本示例说明如何使用自定义错误消息而不是使用内置标准错误消息来定制内置标准约束。
清单2.1 – ValidationMessages.properties
Candy.name.NotNull=A candy name is required.
清单2.2 –验证的Bean
package org.thoth.beanvalidation.custommessage;import javax.validation.constraints.NotNull;public class Candy {@NotNull(message = "{Candy.name.NotNull}")protected String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}
清单2.3 –如何验证
package org.thoth.beanvalidation.custommessage;import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;public class CandyTest {protected static Validator validator;@BeforeClasspublic static void before() {validator = Validation.buildDefaultValidatorFactory().getValidator();}@Testpublic void notnull_violation_message() {// setupCandy candy = new Candy();// actionSet<ConstraintViolation<Candy>> violations= validator.validate(candy);// assertConstraintViolation<Candy> v= violations.stream().findFirst().get();Assert.assertEquals("A candy name is required.", v.getMessage());}@Testpublic void notnull_violation_messageTemplate() {// setupCandy candy = new Candy();// actionSet<ConstraintViolation<Candy>> violations= validator.validate(candy);// assertConstraintViolation<Candy> v= violations.stream().findFirst().get();Assert.assertEquals("{Candy.name.NotNull}", v.getMessageTemplate());}
}
具有可变替换的自定义消息模板
此示例说明了如何使用自定义错误消息配置内置的标准约束,该错误消息中的变量值在运行时由Bean验证替换。 可以替换的变量的示例包括已验证的实际值以及@Size
约束的min和max属性。
清单3.1 – ValidationMessages.properties
Candy.name.Size.message=The candy name "${validatedValue}" is invalid. It must be between {min} and {max} characters long
清单3.2 –验证的Bean
package org.thoth.beanvalidation.variablereplacement;import javax.validation.constraints.Size;public class Candy {private String name;@Size(message = "{Candy.name.Size.message}", min=5, max=10)public String getName() {return name;}public void setName(String name) {this.name = name;}
}
清单3.3 –如何验证
package org.thoth.beanvalidation.variablereplacement;import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.thoth.beanvalidation.variablereplacement.Candy;public class CandyTest {protected static Validator validator;@BeforeClasspublic static void before() {validator = Validation.buildDefaultValidatorFactory().getValidator();}@Testpublic void does_the_constraint_have_the_correct_messageTemplate() {// setupCandy candy = new Candy();candy.setName("");// actionSet<ConstraintViolation<Candy>> violations= validator.validate(candy);// assertConstraintViolation<Candy> v= violations.stream().findFirst().get();Assert.assertEquals("{Candy.name.Size.message}", v.getMessageTemplate());}@Testpublic void is_the_message_correct_if_size_is_too_small() {// setupCandy candy = new Candy();candy.setName("foo");// actionSet<ConstraintViolation<Candy>> violations= validator.validate(candy);// assertConstraintViolation<Candy> v= violations.stream().findFirst().get();Assert.assertEquals("The candy name \"foo\" is invalid. It must be between 5 and 10 characters long", v.getMessage());}@Testpublic void is_the_message_correct_if_size_is_too_big() {// setupCandy candy = new Candy();candy.setName("123456789|1");// actionSet<ConstraintViolation<Candy>> violations= validator.validate(candy);// assertConstraintViolation<Candy> v= violations.stream().findFirst().get();Assert.assertEquals("The candy name \"123456789|1\" is invalid. It must be between 5 and 10 characters long", v.getMessage());}
}
自定义属性验证器
本示例说明如何为类的属性创建您自己的约束和您自己的验证器。
清单4.1 – ValidationMessages.properties
org.thoth.beanvalidation.propertyvalidator.Excludes.message=The value "${validatedValue}" is one of {value} which is forbidden.
清单4.2 –约束注释
package org.thoth.beanvalidation.propertyvalidator;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;@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {ExcludesValidator.class})
@Documented
public @interface Excludes {String message() default "{org.thoth.beanvalidation.propertyvalidator.Excludes.message}";Class[] groups() default {};Class[] payload() default {};String[] value() default {};
}
清单4.3 –约束验证器
package org.thoth.beanvalidation.propertyvalidator;import java.util.Arrays;
import java.util.List;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;public class ExcludesValidatorimplements ConstraintValidator< Excludes, String> {private List<String> excludeTheseValues;@Overridepublic void initialize(Excludes arg) {String[] strarr = arg.value();if (strarr == null) {strarr = new String[]{};}excludeTheseValues = Arrays.asList(strarr);}@Overridepublic boolean isValid(String value, ConstraintValidatorContext cvc) {if (excludeTheseValues.contains(value)) {return false;} else {return true;}}
}
清单4.4 –验证的Bean
package org.thoth.beanvalidation.propertyvalidator;public class Candy {private String name;public Candy(String name) {this.name = name;}@Excludes({"foo", "bar", "shrubbery"})public String getName() {return name;}
}
清单4.5 –如何验证
package org.thoth.beanvalidation.propertyvalidator;import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import static org.junit.Assert.assertEquals;
import org.junit.BeforeClass;
import org.junit.Test;public class CandyTest {protected static Validator validator;@BeforeClasspublic static void before() {validator = Validation.buildDefaultValidatorFactory().getValidator();}@Testpublic void a_non_excludeded_name_should_not_give_you_a_constraint_violation() {// setupCandy candy = new Candy("hershey");// actionSet<ConstraintViolation<Candy>> violations= validator.validate(candy);// assertassertEquals(0, violations.size());}@Testpublic void do_you_get_a_constraint_violation_if_you_use_excluded_name_foo() {// setupCandy candy = new Candy("foo");// actionConstraintViolation<Candy> violation= validator.validate(candy).iterator().next();// assertassertEquals("{org.thoth.beanvalidation.propertyvalidator.Excludes.message}", violation.getMessageTemplate());assertEquals("The value \"foo\" is one of [foo, bar, shrubbery] which is forbidden.", violation.getMessage());}@Testpublic void do_you_get_a_constraint_violation_if_you_use_excluded_name_bar() {// setupCandy candy = new Candy("bar");// actionConstraintViolation<Candy> violation= validator.validate(candy).iterator().next();// assertassertEquals("{org.thoth.beanvalidation.propertyvalidator.Excludes.message}", violation.getMessageTemplate());assertEquals("The value \"bar\" is one of [foo, bar, shrubbery] which is forbidden.", violation.getMessage());}@Testpublic void do_you_get_a_constraint_violation_if_you_use_excluded_name_shrubbery() {// setupCandy candy = new Candy("shrubbery");// actionConstraintViolation<Candy> violation= validator.validate(candy).iterator().next();// assertassertEquals("{org.thoth.beanvalidation.propertyvalidator.Excludes.message}", violation.getMessageTemplate());assertEquals("The value \"shrubbery\" is one of [foo, bar, shrubbery] which is forbidden.", violation.getMessage());}
}
自定义类验证器
此示例说明如何创建适用于整个类的约束和验证器。
清单5.1 – ValidationMessages.properties
org.thoth.beanvalidation.classvalidator.IdentificationExists.message=At least one of social security number, drivers license number, or passport number must exist.
清单5.2 –约束注释
package org.thoth.beanvalidation.classvalidator;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.Payload;@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {IdentificationExistsValidator.class})
@Documented
public @interface IdentificationExists {String message() default "{org.thoth.beanvalidation.classvalidator.IdentificationExists.message}";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};
}
清单5.3 –约束验证器
package org.thoth.beanvalidation.classvalidator;import java.util.Objects;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;public class IdentificationExistsValidator implements ConstraintValidator<IdentificationExists, Identification> {@Overridepublic void initialize(IdentificationExists a) {}@Overridepublic boolean isValid(Identification t, ConstraintValidatorContext cvc) {boolean invalid =Objects.equals(t.getDriversLicenseNumber(), null)&&Objects.equals(t.getPassportNumber(), null)&&Objects.equals(t.getSocialSecurityNumber(), null);return !invalid;}
}
清单5.4 –验证的Bean
package org.thoth.beanvalidation.classvalidator;@IdentificationExists
public class Identification {protected String socialSecurityNumber;protected String driversLicenseNumber;protected String passportNumber;public String getSocialSecurityNumber() {return socialSecurityNumber;}public void setSocialSecurityNumber(String socialSecurityNumber) {this.socialSecurityNumber = socialSecurityNumber;}public String getDriversLicenseNumber() {return driversLicenseNumber;}public void setDriversLicenseNumber(String driversLicenseNumber) {this.driversLicenseNumber = driversLicenseNumber;}public String getPassportNumber() {return passportNumber;}public void setPassportNumber(String passportNumber) {this.passportNumber = passportNumber;}
}
清单5.5 –如何验证
package org.thoth.beanvalidation.classvalidator;import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;public class IdentificationTest {protected Validator validator;@Beforepublic void before() {validator = Validation.buildDefaultValidatorFactory().getValidator();}@Testpublic void violation_if_all_are_missing() {// setupIdentification id = new Identification();// actionSet<ConstraintViolation<Identification>> violations= validator.validate(id);// assertConstraintViolation<Identification> v= violations.stream().findFirst().get();Assert.assertEquals("At least one of social security number, drivers license number, or passport number must exist.", v.getMessage());}@Testpublic void no_violation_if_social_security_number_exists() {// setupIdentification id = new Identification();id.setSocialSecurityNumber("a");// actionSet<ConstraintViolation<Identification>> violations= validator.validate(id);// assertAssert.assertEquals(0, violations.size());}@Testpublic void no_violation_if_drivers_license_number_exists() {// setupIdentification id = new Identification();id.setDriversLicenseNumber("a");// actionSet<ConstraintViolation<Identification>> violations= validator.validate(id);// assertAssert.assertEquals(0, violations.size());}@Testpublic void no_violation_if_passport_number_exists() {// setupIdentification id = new Identification();id.setPassportNumber("a");// actionSet<ConstraintViolation<Identification>> violations= validator.validate(id);// assertAssert.assertEquals(0, violations.size());}
}
组序列(短路)
此示例显示了在进行验证时如何使用@GroupSequence
作为短路。 这意味着,如果第一轮验证未通过,则验证“短路”,并且不会执行第二轮验证。
默认情况下,所有bean验证约束都放入“默认”组序列中。 但是,通过将@GroupSequence
放在类上(如下所示),仅针对该类重新定义“默认”组序列。 使用下面的类上的@GroupSequence
,其基本作用是在bean验证期间,第一个操作是验证该类中未专门分配组的所有约束。 首先是@NotNull
约束。 如果所有这些都OK,那么第二个操作是验证Second.class
组中的所有约束。 那就是@Size
约束。 如果所有这些都OK,那么第三Third.class
操作将验证Third.class
组中的所有约束。 那就是@Pattern
约束。 如果某个小组在任何时候都无法通过验证,则验证将“短路”,并且验证不再进行。
清单6.1 –验证的Bean
package org.thoth.beanvalidation.groupsequence;import javax.validation.GroupSequence;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;@GroupSequence({Candy.class, Candy.Second.class, Candy.Third.class})
public class Candy {protected interface Second {}protected interface Third {}private String name;@NotNull()@Size(min=4, max=10, groups = Second.class )@Pattern(regexp = "[a-z]", groups = Third.class)public String getName() {return name;}public void setName(String name) {this.name = name;}
}
清单6.2 –如何验证
package org.thoth.beanvalidation.groupsequence;import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.Test;public class CandyTest {private Validator validator;@Beforepublic void before() {validator = Validation.buildDefaultValidatorFactory().getValidator();}@Testpublic void short_circuits_first_if_null() {// setupCandy w = new Candy();// actionSet<ConstraintViolation<Candy>> violations//= validator.validate(w, CheckGroupSequence.class);= validator.validate(w);// assertassertEquals(1, violations.size());assertEquals("may not be null", violations.iterator().next().getMessage());}@Testpublic void short_circut_if_size_is_in_violation() {// setupCandy w = new Candy();w.setName("foo");// actionSet<ConstraintViolation<Candy>> violations= validator.validate(w);// assertassertEquals(1, violations.size());assertEquals("size must be between 4 and 10", violations.iterator().next().getMessage());}@Testpublic void short_circuit_if_pattern_is_in_violation() {// setupCandy w = new Candy();w.setName("SHRUBBERY");// actionSet<ConstraintViolation<Candy>> violations= validator.validate(w);// assertassertEquals(1, violations.size());assertEquals("must match \"[a-z]\"", violations.iterator().next().getMessage());}
}
摘要
Bean验证是一种功能强大的API,尤其是因为它可以在Java EE服务器或独立的Java SE应用程序中使用。 这只是Bean验证API基础知识的简短摘要,但是通常,它足以涵盖开发人员有关如何使用它的大多数问题。
翻译自: https://www.javacodegeeks.com/2017/07/java-bean-validation-basics.html
java bean 验证