数据校验是任何一个应用程序都会用到的功能,无论是显示层还是持久层. 通常,相同的校验逻辑会分散在各个层中, 这样,不仅浪费了时间还会导致错误的发生(译注: 重复代码). 为了避免重复, 开发人员经常会把这些校验逻辑直接写在领域模型里面, 但是这样又把领域模型代码和校验代码混杂在了一起, 而这些校验逻辑更应该是描述领域模型的元数据.
JSR 303 - Bean Validation - 为实体验证定义了元数据模型和API. 默认的元数据模型是通过Annotations来描述的,但是也可以使用XML来重载或者扩展. Bean Validation API 并不局限于应用程序的某一层或者哪种编程模型, 例如,如图所示, Bean Validation 可以被用在任何一层, 或者是像类似Swing的富客户端程序中.
Hibernate Validator is the reference implementation of this JSR. The implementation itself as well as the Bean Validation API and TCK are all provided and distributed under the Apache Software License 2.0.
本章将会告诉你如何使用Hibernate Validator, 在开始之前,你需要准备好下面的环境:
A JDK >= 5
网络连接 ( Maven需要通过互联网下载所需的类库)
A properly configured remote repository. Add the following to your settings.xml
:
例 1.1. Configuring the JBoss Maven repository
<repositories> <repository> <id>jboss-public-repository-group</id> <url>https://repository.jboss.org/nexus/content/groups/public-jboss</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories>
More information about settings.xml
can be found in the Maven Local Settings Model.
Hibernate Validator uses JAXB for XML parsing. JAXB is part of the Java Class Library since Java 6 which means that if you run Hibernate Validator with Java 5 you will have to add additional JAXB dependencies. Using Maven you have to add the following dependencies:
<dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.2</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>2.1.12</version> </dependency>
if you are using the SourceForge package you find the necessary libraries in the lib/jdk5
directory. In case you are not using the XML configuration you can also disable it explicitly by calling Configuration.ignoreXmlConfiguration()
during ValidationFactory
creation. In this case the JAXB dependencies are not needed.
使用Maven archetype插件来创建一个新的Maven 项目
例 1.2. 使用Maven archetype 插件来创建一个简单的基于Hibernate Validator的项目
mvn archetype:generate -DarchetypeGroupId=org.hibernate -DarchetypeArtifactId=hibernate-validator-quickstart-archetype -DarchetypeVersion=4.2.0.Final -DarchetypeRepository=http://repository.jboss.org/nexus/content/groups/public-jboss/ -DgroupId=com.mycompany -DartifactId=hv-quickstart
Maven 将会把你的项目创建在hv-quickstart目录中. 进入这个目录并且执行:
mvn test
这样, Maven会编译示例代码并且运行单元测试, 接下来,让我们看看生成的代码.
From version 4.2.0.Beta2, the maven command mvn archetype:create
will be no longer supported and will fail. You should use the command described in the above listing. If you want more details, look at Maven Archetype plugin page.
例 1.3. 带约束性标注(annotated with constraints)的Car 类
package com.mycompany;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
public class Car {
@NotNull
private String manufacturer;
@NotNull
@Size(min = 2, max = 14)
private String licensePlate;
@Min(2)
private int seatCount;
public Car(String manufacturer, String licencePlate, int seatCount) {
this.manufacturer = manufacturer;
this.licensePlate = licencePlate;
this.seatCount = seatCount;
}
//getters and setters ...
}
@NotNull
, @Size
and @Min
就是上面所属的约束性标注( constraint annotations), 我们就是使用它们来声明约束, 例如在Car
的字段中我们可以看到:
manufacturer永远不能为null
licensePlate永远不能为null,并且它的值字符串的长度要在2到14之间
seatCount的值要不能小于2
我们需要使用Validator
来对上面的那些约束进行校验. 让我们来看看CarTest
这个类:
例 1.4. 在CarTest中使用校验
package com.mycompany;
import static org.junit.Assert.*;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import org.junit.BeforeClass;
import org.junit.Test;
public class CarTest {
private static Validator validator;
@BeforeClass
public static void setUp() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
}
@Test
public void manufacturerIsNull() {
Car car = new Car(null, "DD-AB-123", 4);
Set<ConstraintViolation<Car>> constraintViolations =
validator.validate(car);
assertEquals(1, constraintViolations.size());
assertEquals("may not be null", constraintViolations.iterator().next().getMessage());
}
@Test
public void licensePlateTooShort() {
Car car = new Car("Morris", "D", 4);
Set<ConstraintViolation<Car>> constraintViolations =
validator.validate(car);
assertEquals(1, constraintViolations.size());
assertEquals("size must be between 2 and 14", constraintViolations.iterator().next().getMessage());
}
@Test
public void