Hibernate Validator JSR303示例教程
欢迎使用Hibernate Validator示例教程。
数据验证是任何应用程序不可或者缺的一部分。
您将在使用Javascript的表示层进行数据验证。
然后在服务器端编码之前处理客户端数据。
数据验证也将在持久化之前进行,以确保其遵循正确的格式。
Hibernate 验证器
验证是一项跨领域的任务,因此我们应尽量将其与业务逻辑分开。
因此,JSR303和JSR349提供了使用批注来验证bean的规范。
Hibernate Validator提供了这两个bean验证规范的参考实现。
使用Hibernate Validator非常容易,最重要的是,我们可以轻松扩展它并创建自己的自定义验证注释。
今天,我们将通过示例详细研究Hibernate 验证器。
最后,我们将有一个测试程序来检查验证。
我为所有Hibernate 验证示例创建了一个示例项目,下图显示了最终的项目结构。
Hibernate Validator Maven依赖关系
我们需要添加JSR303和Hibernate Validator依赖项才能使用它们。
<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.1.Final</version> </dependency>
Hibernate Validator还需要实现统一表达式语言(JSR 341)来评估约束违例消息中的动态表达式。
如果您的应用程序在Servlet容器(例如JBoss)中运行,则已经提供了它。
但是,如果要在像我的示例项目这样的独立应用程序中使用它,则需要手动添加它们。
所需的依赖关系是;
<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>
检查镜像中项目中所有的Maven依赖项。
现在,我们准备开始使用Hibernate 验证示例。
Hibernate 验证示例
让我们创建一个简单的类,并向其中添加一些验证。
Employee.java
package com.theitroad.validator.hibernate.model; import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import org.hibernate.validator.constraints.CreditCardNumber; import org.hibernate.validator.constraints.Email; public class Employee { @Min(value=1, groups=EmpIdCheck.class) private int id; @NotNull(message="Name cannot be null") @Size(min=5, max=30) private String name; @Email private String email; @CreditCardNumber private String creditCardNumber; //default no-args constructor public Employee(){} public Employee(int id, String name, String email, String ccNum){ this.id=id; this.name=name; this.email=email; this.creditCardNumber=ccNum; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getCreditCardNumber() { return creditCardNumber; } public void setCreditCardNumber(String creditCardNumber) { this.creditCardNumber = creditCardNumber; } }
我们应该避免使用特定于实现的注释进行松散耦合。
但是Hibernate 验证器提供了一些非常好的验证注释,例如," @ Email"和" @CreditCardNumber"。
我们还可以提供自定义错误消息,以用于任何验证。
如果未定义任何消息,则将使用Hibernate 内置错误消息。
我们可以将组分配给任何验证,这仅对验证一组字段有用。
例如,如果我只需要验证Employee id字段,则可以使用EmpIdCheck
组。
为此,我们需要定义一个类/接口。
EmpIdCheck.java
package com.theitroad.validator.hibernate.model; public interface EmpIdCheck { }
稍后我们将在测试程序中查看它的用法。
Hibernate Validator自定义错误消息
我们也可以定义自定义错误消息,我们所要做的就是在类路径中有" ValidationMessages.properties"文件。
ValidationMessages.properties
#Hibernate Bug for @CreditCardNumber Workaround - https://hibernate.atlassian.net/browse/HV-881 org.hibernate.validator.constraints.LuhnCheck.message=The check digit for ${validatedValue} is invalid, Luhn Modulo 10 checksum failed. org.hibernate.validator.constraints.Email.message=Invalid email address
这些属性文件还支持本地化,在这种情况下,我们需要保留诸如ValidationMessages_tr_TR.properties之类的文件名。
消息的属性名称是完全分类的注释名称,末尾是message,您可以轻松地从以上示例中找出来。
基于XML的约束验证
有时我们想对第三方类进行验证,然后就不能对它们使用批注。
在这种情况下,基于xml配置的验证非常方便。
例如,假设我们有一个没有任何验证注释的类,如下所示。
EmployeeXMLValidation.java
package com.theitroad.validator.hibernate.model; public class EmployeeXMLValidation { private int id; private String name; private String email; private String creditCardNumber; //default no-args constructor public EmployeeXMLValidation(){} public EmployeeXMLValidation(int id, String name, String email, String ccNum){ this.id=id; this.name=name; this.email=email; this.creditCardNumber=ccNum; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getCreditCardNumber() { return creditCardNumber; } public void setCreditCardNumber(String creditCardNumber) { this.creditCardNumber = creditCardNumber; } }
上面的beanHibernate 验证的一个简单示例如下所示。
employeeXMLValidation.xml
<constraint-mappings xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jboss.org/xml/ns/javax/validation/mapping validation-mapping-1.1.xsd" xmlns="https://jboss.org/xml/ns/javax/validation/mapping" version="1.1"> <default-package>com.theitroad.validator.hibernate.model</default-package> <bean class="EmployeeXMLValidation" ignore-annotations="true"> <field name="id"> <constraint annotation="javax.validation.constraints.Min"> <element name="value">1</element> </constraint> </field> <field name="name"> <constraint annotation="javax.validation.constraints.NotNull" <constraint annotation="javax.validation.constraints.Size"> <element name="min">5</element> <element name="max">30</element> </constraint> </field> <field name="email"> <constraint annotation="org.hibernate.validator.constraints.Email" </field> <field name="creditCardNumber"> <constraint annotation="org.hibernate.validator.constraints.CreditCardNumber" </field> </bean> </constraint-mappings>
default-package用于定义基本软件包,因此我们可以跳过长软件包名称。
ignore-annotations用于告诉Hibernate验证程序忽略类中存在的用于验证目的的任何注释,仅执行xml文件中配置的验证。
我们可以在一个文件中进行多个bean验证,我们需要将此文件加载到验证器的工厂配置中,稍后将给出一个示例。
属性级别约束
我们也可以在getter方法上应用约束,我们不应该在setter方法上应用约束。
另外,我们应该避免在字段和getter方法上都应用约束,因为这样它将被两次验证。
MyBean.java
package com.theitroad.validator.hibernate.model; import javax.validation.constraints.NotNull; public class MyBean { private String name; @NotNull public String getName() { return name; } public void setName(String name) { this.name = name; } }
具有继承的Hibernate 验证
Bean验证是继承的,因此,如果我们要验证子类的对象,则还将执行父类中的任何验证。
MyChildBean.java
package com.theitroad.validator.hibernate.model; import javax.validation.constraints.NotNull; public class MyChildBean extends MyBean { private String data; @NotNull public String getData() { return data; } public void setData(String data) { this.data = data; } }
如果我们将验证MyChildBean的实例,则MyBean名称字段也将被验证。
使用@Valid批注进行组合验证
如果有合成,我们可以使用@ Valid
批注,以便执行验证。
AnotherBean.java
package com.theitroad.validator.hibernate.model; import javax.validation.Valid; import javax.validation.constraints.NotNull; public class AnotherBean { @NotNull @Valid private MyChildBean childBean; public MyChildBean getChildBean() { return childBean; } public void setChildBean(MyChildBean childBean) { this.childBean = childBean; } }
现在,如果我们验证AnotherBean
实例,则还将验证MyChildBean
对象。
方法参数Hibernate 验证
我们也可以定义方法参数的约束,下面给出一个简单的例子。
ParamValidationBean.java
package com.theitroad.validator.hibernate.model; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; public class ParamValidationBean { private String name; //using @NotNull at constructor rather than at field public ParamValidationBean(@NotNull String name){ this.name = name; } public void printData(@NotNull @Size(min=5) String data){ System.out.println("Data is::"+data); } public String getName() { return name; } }
Hibernate Validator示例测试程序
我们已经看到了很多验证方案,这里是测试程序,以显示验证它们的过程。
ValidatorTest.java
package com.theitroad.validator.hibernate.main; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.lang.reflect.Method; import java.util.Set; import javax.validation.Configuration; import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.Validator; import javax.validation.ValidatorFactory; import javax.validation.executable.ExecutableValidator; import org.hibernate.validator.HibernateValidator; import com.theitroad.validator.hibernate.model.AnotherBean; import com.theitroad.validator.hibernate.model.EmpIdCheck; import com.theitroad.validator.hibernate.model.Employee; import com.theitroad.validator.hibernate.model.EmployeeXMLValidation; import com.theitroad.validator.hibernate.model.MyChildBean; import com.theitroad.validator.hibernate.model.ParamValidationBean; public class ValidatorTest { public static void main(String[] args) throws FileNotFoundException, NoSuchMethodException, SecurityException { //Getting Validator instance with Annotations ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory(); Validator validator = validatorFactory.getValidator(); //If there are multiple JSR303 implementations in classpath //we can get HibernateValidator specifically too ValidatorFactory hibernateVF = Validation.byProvider(HibernateValidator.class) .configure().buildValidatorFactory(); System.out.println("\nSimple field level validation example"); Employee emp = new Employee(-1, "Name","email","123"); Set<ConstraintViolation<Employee>> validationErrors = validator.validate(emp); if(!validationErrors.isEmpty()){ for(ConstraintViolation<Employee> error : validationErrors){ System.out.println(error.getMessageTemplate()+"::"+error.getPropertyPath()+"::"+error.getMessage()); } } System.out.println("\nXML Based validation example"); //XML Based validation Configuration<?> config = Validation.byDefaultProvider().configure(); config.addMapping(new FileInputStream("employeeXMLValidation.xml")); ValidatorFactory validatorFactory1 = config.buildValidatorFactory(); Validator validator1 = validatorFactory1.getValidator(); EmployeeXMLValidation emp1 = new EmployeeXMLValidation(10, "Name","email","123"); Set<ConstraintViolation<EmployeeXMLValidation>> validationErrors1 = validator1.validate(emp1); if(!validationErrors1.isEmpty()){ for(ConstraintViolation<EmployeeXMLValidation> error : validationErrors1){ System.out.println(error.getMessageTemplate()+"::"+error.getInvalidValue()+"::"+ error.getPropertyPath()+"::"+error.getMessage()); } } System.out.println("\nValidation Group example"); validationErrors = validator.validate(emp, EmpIdCheck.class); if(!validationErrors.isEmpty()){ for(ConstraintViolation<Employee> error : validationErrors){ System.out.println(error.getMessageTemplate()+"::"+error.getPropertyPath()+"::"+error.getMessage()); } } System.out.println("\nValidation with inheritance example"); //Validation inheritance and Property-level constraints example MyChildBean childBean = new MyChildBean(); Set<ConstraintViolation<MyChildBean>> validationInheritanceErrors = validator.validate(childBean); if(!validationInheritanceErrors.isEmpty()){ for(ConstraintViolation<MyChildBean> error : validationInheritanceErrors){ System.out.println(error.getMessageTemplate()+"::"+error.getPropertyPath()+"::"+error.getMessage()); } } System.out.println("\nValidation in composition using @Valid annotation"); //@Valid annotation - validation in composition example AnotherBean compositionBean = new AnotherBean(); compositionBean.setChildBean(new MyChildBean()); Set<ConstraintViolation<AnotherBean>> validationCompositionErrors = validator.validate(compositionBean); if(!validationCompositionErrors.isEmpty()){ for(ConstraintViolation<AnotherBean> error : validationCompositionErrors){ System.out.println(error.getMessageTemplate()+"::"+error.getPropertyPath()+"::"+error.getMessage()); } } System.out.println("\nParameter validation example"); ParamValidationBean paramValidationBean = new ParamValidationBean("hyman"); Method method = ParamValidationBean.class.getMethod("printData", String.class); Object[] params = {"1234"}; ExecutableValidator executableValidator = validator.forExecutables(); Set<ConstraintViolation<ParamValidationBean>> violations = executableValidator.validateParameters(paramValidationBean, method, params); if(!violations.isEmpty()){ for(ConstraintViolation<ParamValidationBean> error : violations){ System.out.println(error.getMessageTemplate()+"::"+error.getPropertyPath()+"::"+error.getMessage()); } } } }
当我们在Hibernate 验证器示例程序之上运行时,我们得到以下输出。
May 25, 2014 3:51:56 AM org.hibernate.validator.internal.util.Version <clinit> INFO: HV000001: Hibernate Validator 5.1.1.Final Simple field level validation example {javax.validation.constraints.Size.message}::name::size must be between 5 and 30 {org.hibernate.validator.constraints.CreditCardNumber.message}::creditCardNumber::invalid credit card number {org.hibernate.validator.constraints.Email.message}::email::Invalid email address XML Based validation example {org.hibernate.validator.constraints.Email.message}::email::email::Invalid email address {javax.validation.constraints.Size.message}::Name::name::size must be between 5 and 30 {org.hibernate.validator.constraints.CreditCardNumber.message}::123::creditCardNumber::invalid credit card number Validation Group example {javax.validation.constraints.Min.message}::id::must be greater than or equal to 1 Validation with inheritance example {javax.validation.constraints.NotNull.message}::data::Jan not be null {javax.validation.constraints.NotNull.message}::name::Jan not be null Validation in composition using @Valid annotation {javax.validation.constraints.NotNull.message}::childBean.data::Jan not be null {javax.validation.constraints.NotNull.message}::childBean.name::Jan not be null Parameter validation example {javax.validation.constraints.Size.message}::printData.arg0::size must be between 5 and 2147483647
来自Hibernate 验证器测试程序的重要要点是:
Validator实例是线程安全的,因此我们可以对其进行缓存并重用。
如果存在多个JSR303实现,则可以使用" Validation.byProvider()"方法获取Hibernate Validator实例。
请注意,使用的是组验证,它仅验证组中的字段。
ExecutableValidator用于验证方法的参数。
ExecutableValidator提供了一些方法来验证构造函数的参数并返回值,这些方法是validateateReturnValue(),validateConstructorParameters()和validateConstructorReturnValue()。
Hibernate Validator自定义验证和Spring Framework集成
我们也可以创建自己的自定义验证器,请阅读Spring Hibernate Validator Example以更好地了解此功能。