spring boot 最佳实践(二)--使用Bean Validation

JavaBean定义了一组规则,JavaBean就是遵循此规则的平常的Java对象。Bean Validation是Java定义的一套基于注解/xml的数据校验规范,目前已经从JSR 303的1.0版本升级到JSR 349的1.1版本,再到JSR 380的2.0版本(2.0完成于2017.08),已经经历了三个版本。

JavaBean满足这三个条件:

  1. JavaBean类必须有一个没有参数的构造函数。
  2. JavaBean类所有的属性最好定义为私有的。
  3. 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详细信息
@Email被注释的元素必须是电子邮箱地址
@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 ValidationHibernate ValidationJDKSpring Boot
1.15.4 +6+1.5.x
2.06.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,它自己也扩展了一些注解支持。

  1. 6.0以上版本新增(对应标准2.0版本):@UniqueElements、@ISBN、@CodePointLength
  2. 6.0以下版本可以使用的: @URL、@ScriptAssert、@SafeHtml、@Range、@ParameterScriptAssert、@Mod11Check、@Mod10Check、@LuhnCheck、@Length、@EAN、@Currency、@CreditCardNumber、@ConstraintComposition、
  3. 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

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值