Hibernate Validator JSR303示例教程

194 篇文章 3 订阅
22 篇文章 0 订阅

 

Hibernate Validator JSR303示例教程

 

欢迎使用Hibernate Validator示例教程。数据验证是任何应用程序的组成部分。您将使用Javascript在表示层找到数据验证。然后在服务器端代码处理客户端数据之前。在持久化之前也会进行数据验证,以确保它遵循正确的格式。

目录[ 隐藏 ]

 

Hibernate Validator

验证是一项交叉任务,因此我们应该尝试将其与业务逻辑区分开来。这就是为什么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)来评估约束违规消息中的动态表达式。

如果您的应用程序在诸如JBoss之类的servlet容器中运行,则已经提供了它。但是如果您在我的示例项目之类的独立应用程序中使用它,则需要手动添加它们。必需的依赖项是;


<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.journaldev.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字段,我可以使用EmpIdCheckgroup。为此,我们需要定义一个类/接口。

EmpIdCheck.java


package com.journaldev.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

消息的属性名称是完全分类的注释名称,末尾有消息,您可以从上面的示例中轻松搞清楚。

基于XML的约束验证

有时我们想要对第三方类进行验证,然后我们就不能对它们使用注释。在这种情况下,基于xml配置的验证非常方便。例如,假设我们有一个没有任何验证注释的类,如下所示。

EmployeeXMLValidation.java


package com.journaldev.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;
	}
	
}

上面的bean hibernate验证的一个简单示例可能如下所示。

employeeXMLValidation.xml


<constraint-mappings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/mapping validation-mapping-1.1.xsd"
	xmlns="http://jboss.org/xml/ns/javax/validation/mapping" version="1.1">

	<default-package>com.journaldev.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.journaldev.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.journaldev.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注释使用Composition进行验证

我们可以使用@Valid注释组合,以便执行它的验证。

AnotherBean.java


package com.journaldev.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.journaldev.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.journaldev.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.journaldev.validator.hibernate.model.AnotherBean;
import com.journaldev.validator.hibernate.model.EmpIdCheck;
import com.journaldev.validator.hibernate.model.Employee;
import com.journaldev.validator.hibernate.model.EmployeeXMLValidation;
import com.journaldev.validator.hibernate.model.MyChildBean;
import com.journaldev.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("Pankaj");
		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验证器示例程序时,我们得到以下输出。


Jul 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::may not be null
{javax.validation.constraints.NotNull.message}::name::may not be null

Validation in composition using @Valid annotation
{javax.validation.constraints.NotNull.message}::childBean.data::may not be null
{javax.validation.constraints.NotNull.message}::childBean.name::may not be null

Parameter validation example
{javax.validation.constraints.Size.message}::printData.arg0::size must be between 5 and 2147483647

以上hibernate验证器测试程序的重点是:

  1. Validator实例是线程安全的,因此我们可以缓存它并重用它。
  2. 如果存在多个JSR303实现,那么我们可以使用Validation.byProvider()方法获取Hibernate Validator实例。
  3. 注意使用组的验证,它只验证属于组的字段。
  4. ExecutableValidator用于验证方法的参数。
  5. ExecutableValidator提供验证构造函数参数和返回值的方法,这些方法是validateReturnValue()validateConstructorParameters()validateConstructorReturnValue()

Hibernate Validator自定义验证和Spring Framework集成

我们也可以创建自己的自定义验证器,请阅读Spring Hibernate验证器示例以更好地理解此功能。

 

Hibernate验证器摘要

Hibernate Validator和JSR303一起提供了交叉bean验证实现的基础,如果与面向方面编程一起使用,我们可以将所有bean验证与业务逻辑分开。您可以从以下链接下载最终项目并了解更多信息。

下载Hibernate Validator项目

参考文献
Hibernate Validator 
JSR 303

 

转载来源:https://www.journaldev.com/3626/hibernate-validator-jsr303-example-tutorial

HibernateValidatorJSR303的参考实现使用指南.pdf JSR 303 的参考实现 使用指南 由 Hardy Ferentschik和Gunnar Morling and thanks to Shaozhuang Liu 4.3.1.Final 版权 © 2009 - 2011 Red Hat, Inc. & Gunnar Morling June 20, 2011 序言 1. 开始入门 1.1. 第一个Maven项目 1.2. 添加约束 1.3. 校验约束 1.4. 更进一步 2. Validation step by step 2.1. 定义约束 2.1.1. 字段级(field level) 约束 2.1.2. 属性级别约束 2.1.3. 类级别约束 2.1.4. 约束继承 2.1.5. 对象图 2.2. 校验约束 2.2.1. 获取一个Validator的实例 2.2.2. Validator中的方法 2.2.3. ConstraintViolation 中的方法 2.2.4. 验证失败提示信息解析 2.3. 校验组 2.3.1. 校验组序列 2.3.2. 对一个类重定义其默认校验组 2.4. 内置的约束条件 2.4.1. Bean Validation constraints 2.4.2. Additional constraints 3. 创建自己的约束规则 3.1. 创建一个简单的约束条件 3.1.1. 约束标注 3.1.2. 约束校验器 3.1.3. 校验错误信息 3.1.4. 应用约束条件 3.2. 约束条件组合 4. XML configuration 4.1. validation.xml 4.2. 映射约束 5. Bootstrapping 5.1. Configuration 和 ValidatorFactory 5.2. ValidationProviderResolver 5.3. MessageInterpolator 5.3.1. ResourceBundleLocator 5.4. TraversableResolver 5.5. ConstraintValidatorFactory 6. Metadata API 6.1. BeanDescriptor 6.2. PropertyDescriptor 6.3. ElementDescriptor 6.4. ConstraintDescriptor 7. 与其他框架集成 7.1. OSGi 7.2. 与数据库集成校验 7.3. ORM集成 7.3.1. 基于Hibernate事件模型的校验 7.3.2. JPA 7.4. 展示层校验 8. Hibernate Validator Specifics 8.1. Public API 8.2. Fail fast mode 8.3. Method validation 8.3.1. Defining method-level constraints 8.3.2. Evaluating method-level constraints 8.3.3. Retrieving method-level constraint meta data 8.4. Programmatic constraint definition 8.5. Boolean composition for constraint composition 9. Annotation Processor 9.1. 前提条件 9.2. 特性 9.3. 配置项 9.4. 使用标注处理器 9.4.1. 命令行编译 9.4.2. IDE集成 9.5. 已知问题 10. 进一步阅读
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值