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以更好地了解此功能。

