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字段,我可以使用EmpIdCheck
group。为此,我们需要定义一个类/接口。
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验证器测试程序的重点是:
- Validator实例是线程安全的,因此我们可以缓存它并重用它。
- 如果存在多个JSR303实现,那么我们可以使用
Validation.byProvider()
方法获取Hibernate Validator实例。 - 注意使用组的验证,它只验证属于组的字段。
- ExecutableValidator用于验证方法的参数。
ExecutableValidator
提供验证构造函数参数和返回值的方法,这些方法是validateReturnValue()
,validateConstructorParameters()
和validateConstructorReturnValue()
Hibernate Validator自定义验证和Spring Framework集成
我们也可以创建自己的自定义验证器,请阅读Spring Hibernate验证器示例以更好地理解此功能。
Hibernate验证器摘要
Hibernate Validator和JSR303一起提供了交叉bean验证实现的基础,如果与面向方面编程一起使用,我们可以将所有bean验证与业务逻辑分开。您可以从以下链接下载最终项目并了解更多信息。
参考文献:
Hibernate Validator
JSR 303
转载来源:https://www.journaldev.com/3626/hibernate-validator-jsr303-example-tutorial