概述
在这个文章里,我们简单介绍一如何使用标准校验框架来完成基本的Java Bean校验,该框架即JSR380,也被称为Bean Validation 2.0。
校验用户输入,在大多是应用程序中是超级常见的需求,Java Bean校验框架即是处理这部分逻辑的标准工具。
JSR308-Bean Validation 2.0
JSR 308是JavaBean校验API规范,它是JavaEE和JavaSE的一部分。该规范使用@NotNull,@Min和@Max这样的注解来确保一个Bean的属性符合特定的条件。
这个版本要求使用Java8或更高版本,利用Java8提供的新特性例如类型注解,并且支持新的类型例如Optional和LocalDate。
要获得更完整的信息,可以进一步阅读JSR 308的文档。
依赖
-
JSR 308规范的的标准API包含在validation-api中:
<dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency>
-
Hibernate Validator是validation-api的参考实现:
<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.2.Final</version> </dependency>
另外,Hibernate Validator还提供了一个注解处理器,利用Java编译时注解处理机制,帮助开发人员发现校验注解使用的错误。仅需要添加如下依赖即可:
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator-annotation-processor</artifactId>
<version>6.0.2.Final</version>
<scop>provided</scop>
</dependency>
hibernate-validator与hibernate的持久化框架支持是完全分离的,引入hibnernate-validator依赖并不会间接引入hibernate持久化相关的依赖。
- 表达式语言依赖
JSR 308规范支持违约信息的变量解析,并允许使用表达式。
为了解析表达式,我们必须添加表达式语言API和它的某个实现,GlassFish项目提供了表达式语言API的参考实现:
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.6</version>
</dependency>
如果没有添加这些依赖到应用中,您会在运行时得到如下错误信息:
HV000183: Unable to load ‘javax.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath, or use ParameterMessageInterpolator instead
使用校验注解
我们在这里使用UserBean作为例子,为它添加一些简单的校验。
import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.validation.constraints.Email;
public class User {
@NotNull(message = "Name cannot be null")
private String name;
@AssertTrue
private boolean working;
@Size(min = 10, max = 200, message
= "About Me must be between 10 and 200 characters")
private String aboutMe;
@Min(value = 18, message = "Age should not be less than 18")
@Max(value = 150, message = "Age should not be greater than 150")
private int age;
@Email(message = "Email should be valid")
private String email;
// standard setters and getters
}
该例子中使用的所有注解都是标准JSR注解:
- @NotNull-校验被注解的属性不能为null
- @AssertTrue-校验被注解的属性值必须为true
- @Size-校验被注解的属性的尺寸必须在min和max之间,该注解可以在String,Collection,Map和数组属性上使用
- @Min,@Max-校验备注解的属性值必须大于或小于指定的值
- @Email-校验备注接的属性必须是有效的emal地址
JSR中还包含其他一些注解:
- @NotEmpty-校验属性不能为null或空;可以在String,Collection,Map或数组类型属性上使用
- @NotBlank-只能使用在文本类型的属性上,校验该属性不能为null或空白
- @Positive,@PositiveOrZero-使用在数值属性上,校验该属性必须为正数或0
- @Negative,@NegativeOrZero-使用在数值属性上,校验该属性必须为负数或0
- @Past,@PastOrPresent-校验日期类型值必须是过去的时间或现在;支持Java8中新增加的日期类型,例如LocalDateTime
- @Future,@FutureOrPresent-校验日期类型值必须在未来或现在
所有注解都可以设置messge属性,这个属性的值在校验失败时被用来渲染违约消息。
Validation-API提供的标准注解的message属性大都有默认值,使用者如无特别需求,无须设置该属性。
校验注解可以施加在集合的元素上
List<@NotBlank String> preferences;
在这个例子中,集合中的的所有元素都会被校验不能为null或空白
规范也支持Java8中新增的Optional类型:
private LocalDate dateOfBirth;
public Optional<@Past LocalDate> getDateOfBirth() {
return Optional.of(dateOfBirth);
}
这个例子中,校验框架会自动将LocalDate值取出并校验。
编程校验
- 一些框架,例如Spring,仅仅使用注解即可出发校验过程。让我们不必直接编程使用校验API。但我们应当对其有所了解,以理解框架的运作原理。
下面让我们来手动编程配置一个校验环境:
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
我们必须首先构建一个校验器(validator)对象,才能校验一个Bean。
-
定义一个待校验的Bean
User user = new User(); user.setWorking(true); user.setAboutMe("Its all about me!"); user.setAge(50);
-
对上面定义的Bean进行校验
Set<ConstraintViolation<User>> violations = validator.validate(user);
将user对象作为validate方法的参数传递给校验器对象,所有违背User对象定义的约束条件的信息包装为ConstraintViolation对象集合返回。
遍历违约信息,我们可以得到所有的违约消息
for (ConstraintViolation<User> violation : violations) {
log.error(violation.getMessage());
}
在我们的例子中,违约对象集合中只会包含一个违约信息,“Name cannot be null”。
这个违约消息可以通过校验注解的message属性进行定义。
总结
本教程聚焦于标准Java校验API的基本内容,展示了使用基本javax.validation注解和API的使用方法。
所有的示例代码可以在GitHub上获取。