JavaBean定义了一组规则,JavaBean就是遵循此规则的平常的Java对象。Bean Validation是Java定义的一套基于注解/xml的数据校验规范,目前已经从JSR 303的1.0版本升级到JSR 349的1.1版本,再到JSR 380的2.0版本(2.0完成于2017.08),已经经历了三个版本。
JavaBean满足这三个条件:
- JavaBean类必须有一个没有参数的构造函数。
- JavaBean类所有的属性最好定义为私有的。
- JavaBean类中定义函数setXxx()和getXxx()来对属性进行操作。其中Xxx是首字母大写的私有变量名称。
传统的代码从展现层、业务逻辑层、持久层、数据传输层分别有不同的对象。VO、BO、PO、DTO、POJO傻傻分不清楚。在不同层有不同的数据校验代码,编写大量的if else、code message、throw new Exception。
在spring data jpa编程范式中,Entity实体是一个简单Java对象,Repository用于对一个entity的重建。建议统一使用简单Java对象POJO定义Entity实体,减少VO、DTO定义,不要定义存储对象PO。
Bean Validation 为 JavaBean 验证定义了相应的元数据模型和 API。在应用程序中,通过使用 Bean Validation 或是你自己定义的 constraint,例如 @NotNull, @Max, @ZipCode, 就可以确保数据模型(JavaBean)的正确性。constraint 可以附加到字段,getter 方法,类或者接口上面。对于一些特定的需求,用户可以很容易的开发定制化的 constraint。Bean Validation 是一个运行时的数据验证框架,在验证之后验证的错误信息会被马上返回。
Hibernate Validator 5.x 是Bean Validation 1.1参考实现。hibernate validator官方文档提供了注解的列表。
表 1. Bean Validation 中内置的 constraint
Constraint | 详细信息 |
---|---|
@Null | 被注释的元素必须为 null |
@NotNull | 被注释的元素必须不为 null |
@AssertTrue | 被注释的元素必须为 true |
@AssertFalse | 被注释的元素必须为 false |
@Min(value) | 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 |
@Max(value) | 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 |
@DecimalMin(value) | 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 |
@DecimalMax(value) | 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 |
@Size(max, min) | 被注释的元素的大小必须在指定的范围内 |
@Digits (integer, fraction) | 被注释的元素必须是一个数字,其值必须在可接受的范围内 |
@Past | 被注释的元素必须是一个过去的日期 |
@Future | 被注释的元素必须是一个将来的日期 |
@Pattern(value) | 被注释的元素必须符合指定的正则表达式 |
表 2. Hibernate Validator 附加的 constraint
Constraint | 详细信息 |
---|---|
被注释的元素必须是电子邮箱地址 | |
@Length | 被注释的字符串的大小必须在指定的范围内 |
@NotEmpty | 被注释的字符串的必须非空 |
@Range | 被注释的元素必须在合适的范围内 |
项目搭建
首先添加hibernate validator 5依赖
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.4.1.Final</version>
</dependency>
如果想在代码中使用EL表达式还需引入。
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>2.2.4</version>
<scope>provided</scope>
</dependency>
定义一个javabean
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 ...
}
执行单元测试
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;
import static org.junit.Assert.assertEquals;
public class CarTest {
private static Validator validator;
@BeforeClass
public static void setUpValidator() {
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() );
}
}
在spring mvc中使用 bean validation
spring mvc4.0支持 bean validation1.1,可以在controller中使用 @Valid 指定要校验的实体类。
//import javax.validation.Valid;
@RequestMapping("/demo")
public String demo(@Valid Demo demo,Model model){
// do something
}
Spring Boot在2.0以后对Bean Validation 的支持已经从1.1升级到2.0。建议在新工程中直接使用2.00.
Bean Validation | Hibernate Validation | JDK | Spring Boot |
---|---|---|---|
1.1 | 5.4 + | 6+ | 1.5.x |
2.0 | 6.0 + | 8+ | 2.0.x |
Bean Validation2.0的变化
- 支持容器的校验,通过TYPE_USE类型的注解实现对容器内容的约束:List<@Email String>
支持日期/时间的校验,@Past和@Future - 拓展元数据(新增注解):@Email,@NotEmpty,@NotBlank,@Positive, @PositiveOrZero,@Negative,@NegativeOrZero,@PastOrPresent和@FutureOrPresent
像@Email、@NotEmpty、@NotBlank之前是Hibernate额外提供的,2.0标准后hibernate自动退位让贤并且标注为过期了
对于Hibernate Validator,它自己也扩展了一些注解支持。
- 6.0以上版本新增(对应标准2.0版本):@UniqueElements、@ISBN、@CodePointLength
- 6.0以下版本可以使用的: @URL、@ScriptAssert、@SafeHtml、@Range、@ParameterScriptAssert、@Mod11Check、@Mod10Check、@LuhnCheck、@Length、@EAN、@Currency、@CreditCardNumber、@ConstraintComposition、
- Hibernate Validator默认会校验完所有的属性,然后返回所有的验证失败信息。开启fail fast mode后,只要有一个验证失败,则返回验证失败信息。
Valid & Validated
@Validated (org.springframework.validation.annotation.Validated)是 Spring 对 @Valid (javax.validation.Valid)的封装,是@ Valid 的加强版,支持更多特性。
Validated 支持对 PathVariable 参数校验,以及 RequestParam 参数校验.但是注解必须写在类上:
@RestController
// 注解必须写在这里,参数校验不过会有 ConstraintViolationException 异常
@Validated
public class Valid2Controller {
@GetMapping("valid4/{data}")
public String getPathVariable(@Size(min = 3, max = 6) @PathVariable String data) {
return data;
}
@GetMapping("valid4")
public String getRequestParam(@Size(min = 3, max = 6) @RequestParam(value = "name", defaultValue = "0") String name) {
return name;
}
}
具体差异
- 1.分组
@Validated:提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制。没有添加分组属性时,默认验证没有分组的验证属性。 - 2.注解地方
@Validated:可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上
@Valid:可以用在方法、构造函数、方法参数和成员属性(字段)上
两者是否能用于成员属性(字段)上直接影响能否提供嵌套验证的功能。 - 3.嵌套验证
由于@Validated不能用在成员属性(字段)上,但是@Valid能加在成员属性(字段)上. 所以在嵌套验证的场景中我们必须要用@Valid.
public class Item {
@NotNull(message = "id不能为空")
@Min(value = 1, message = "id必须为正整数")
private Long id;
@Valid // 嵌套验证必须用@Valid
@NotNull(message = "props不能为空")
@Size(min = 1, message = "props至少要有一个自定义属性")
private List<Prop> props;
}
//--------------------------------
public class Prop {
@NotNull(message = "pid不能为空")
@Min(value = 1, message = "pid必须为正整数")
private Long pid;
@NotNull(message = "vid不能为空")
@Min(value = 1, message = "vid必须为正整数")
private Long vid;
@NotBlank(message = "pidName不能为空")
private String pidName;
@NotBlank(message = "vidName不能为空")
private String vidName;
}
@RestController
public class ItemController {
@RequestMapping("/item/add")
public void addItem(@Validated Item item, BindingResult bindingResult) {
doSomething();
}
}
Hibernate Validation自定义验证规则: https://blog.csdn.net/u011781521/article/details/79670203
深入了解数据校验:Bean Validation 2.0(JSR380):https://www.cnblogs.com/fangshixiang/p/11222572.html
springboot使用hibernate validator校验: https://www.cnblogs.com/mr-yang-localhost/p/7812038.html
SpringBoot2.X 实战8 – Valid & Validated: https://www.jianshu.com/p/764eaf6c0afe
@Validated和@Valid区别: https://blog.csdn.net/wangjiangongchn/article/details/86477386