OVAL验证框架

介绍

官方文档:https://sebthom.github.io/oval/USERGUIDE.html#project-preparation
 

依赖

 1 <!-- java验证框架 oval https://mvnrepository.com/artifact/net.sf.oval/oval -->
 2 <dependency>
 3     <groupId>net.sf.oval</groupId>
 4     <artifactId>oval</artifactId>
 5     <version>1.90</version>
 6 </dependency>
 7 
 8 <!--   groovy 表达式支持  oval需要  -->
 9 <dependency>
10     <groupId>org.codehaus.groovy</groupId>
11     <artifactId>groovy-all</artifactId>
12     <version>2.2.2</version>
13 </dependency>

注解释义

参考:https://my.oschina.net/u/1429811/blog/877433

使用

基本用法

注解加载bean属性上

 1 /**
 2  * 功能
 3  *
 4  * @author ztw
 5  * @data 2022/3/31
 6  */
 7 @Data
 8 public class People {
 9     public int id;
10 
11     @Length(max = 2, min = 1)
12     public String name;
13 
14     @NotBlank
15     public String sex;
16 
17     @NotNull
18     public Integer age;
19 
20     public Date birthDate;
21 
22 }

注解加在get方法上

方法需要用 注释@net.sf.oval.configuration.annotation.IsInvariant,在验证期间忽略缺少此注释的方法指定的返回值约束
1 @IsInvariant
2 @NotNull
3 public Date getBirthDate() {
4     return this.birthDate;
5 }

嵌套验证 

主体 people  嵌套Employee 

 1 @Data
 2 public class People {
 3     private int id;
 4 
 5     /**
 6      * 约束加在注解上
 7      */
 8     @Length(max = 2, min = 1)
 9     private  String name;
10 
11     @Assert(expr = "_value == '男' || _value == '女'", lang = "groovy",message = "sex must be '男' or '女'.")
12     private String sex;
13 
14     @NotEmpty
15     private Integer age;
16 
17     private Date birthday;
18 
19     /**
20      * @note @AssertValid 递归验证
21      */
22     // @Max(target = "age",value = 20)
23     @AssertValid
24     private Employee employee;
... ...

employee   age最大为30

@Data
public class Employee {
    public Integer empId;

    public String name;

    @Max(value = 30)
    public Integer age;
    public Date inductionDate;
    public Date quitDate;
    public String identityDesc;
    public String statusFlag;
}

入参:以employee.age测试

{
    "name":"张三",
    "age": 25,
    "birthday": "2022-04-04",
    "sex":"男",
    "employee": {
        "age": 35
    }
}

 

递归校验

场景一:不加@AssertValid,结论,嵌套验证不生效

1     // @Max(target = "age",value = 20)
2    //  @AssertValid
3     private Employee employee;

 

场景二: 加@AssertValid, 结论,嵌套验证生效

    // @Max(target = "age",value = 20)
    @AssertValid
    private Employee employee;

 

{
    "code": "-1",
    "message": "com.springboot.demo.webbase.repository.People.employee is invalid",
    "date": null
}

对比非嵌套属性约束验证,此时 causes是null,即causes对应有嵌套时

 

 

结论:@AssertValid能够验证嵌套属性是否满足其内的约束,能够触发嵌套的对象属性的约束校验,校验失败的具体原因在causes内,该注解的message返回“xxx is invalid”

 

target 声明嵌套属性的约束

场景一:生效,会覆盖employee.age上的约束

    @Max(target = "age",value = 20)
    @AssertValid
    private Employee employee;

 

{
    "code": "-1",
    "message": "com.springboot.demo.webbase.repository.Employee.age cannot be greater than 20.0",
    "date": null
}

 

场景二:不加@AssertValid, 生效,同样以本类上的注解优先

    @Max(target = "age",value = 20)
    // @AssertValid
    private Employee employee;

结论,使用target指定嵌套属性约束不需要@AssertValid

 

 

验证示例

 1 @PostMapping("/findAllPeople")
 2 public List<People> findAllPeople(@RequestBody People people) {
 3     Validator validator = new Validator();
 4     List<ConstraintViolation> violations = validator.validate(people);
 5     if(!violations.isEmpty()) {
 6         String validateResult =
 7                 violations.stream().map(ConstraintViolation::getMessage).collect(Collectors.joining(","));
 8         throw new IllegalStateException(validateResult);
 9     }
10     return peopleService.findPeopleByCondition(new People());
11 }

校验结果

为集合,对应每个属性的校验信息
0

 

通用属性

when 生命约束的激活规则

when属性为其他约束指定激活规则,该when属性可以包含其中一种受支持的表达式语言的公式,它以要使用的表达式语言的 id 为前缀

target 声明嵌套属性的约束

使用target约束的属性,可以指定应用约束的对象的路径
1 public class BusinessObject {
2   @AssertValid
3   @NotNull(target="homeAddress.street")// 嵌套的对象Customer,约束customer.homeAddress.street
4   private Customer customer;
5 }

message声明校验结果信息

注解

@NotNul

不能为null

@NotBlank

非“”,且length > 0 (并不包含null =》有值才会按这个校验)

@NotEmpty

非“”, (并不包含null =》有值才会按这个校验)

@Assert

断言
1 @Assert(expr = "_value == '男' || _value == '女'", lang = "groovy")

expr

参数保存要评估的脚本 ,返回值为boolean类型
Oval 提供了两个特殊变量:
  • _value- 包含要验证的值(字段值或 getter 返回值)
  • _this- 是对已验证对象的引用

lang

表达式语言
  • bsh或者beanshell对于 BeanShell,
  • groovy对于 Groovy,
  • jexl对于 JEXL,
  • js或者javascript对于 JavaScript(通过 Mozilla Rhino),
  • mvel对于 MVEL,
  • ognl对于 OGNL,
  • ruby或者jruby对于 Ruby(通过 JRuby)

errorCode

错误编码(共有属性,可以修改成自己的异常编码串)

message

错误描述(共有属性),可以通过修改message自定义校验返回结果信息
自定义message
1 @Assert(expr = "_value == '男' || _value == '女'", lang = "groovy",message = "sex must be '男' or '女'.")
2 public String sex;

返回结果

 

{
    "code": "-1",
    "message": "sex must be '男' or '女'.",
    "date": null
}

 

when

 前置条件(共有属性),可以通过when设置前置条件 a,当a为true才校验
 
对应
0

 

@AssertFalse

Check if the value is false. (检查值是否为假)

@AssertTrue

Check if the value is true. (检查值是否为真)

@AssertNull

@AssertNull 说明:Check if null. 与 @NotNull 相反;

@AssertURL

Check if the value is a valid URL. (检查值是否为有效的 URL)
参数:
connect(boolean) : 是否发起连接进行尝试;
Note: 为null也是满足的,所以可能需要配合@NotNull

@CheckWith (使用自定义验证类)

指明验证类,通过该注解可以使用自定义的验证类
参数:Class :指明验证类
 
示例:验证 User 类中的 age 字段
 
@CheckWith(value=CheckAge.class,message="agemust in (18~65)")
 
private int age;
 
验证类,要继承 CheckWithCheck.SimpleCheck,实现isSatisfied方法,如下:
publicclass CheckAge implements CheckWithCheck.SimpleCheck {

    private static final long serialVersionUID =1L;

    @Override

    public boolean isSatisfied(ObjectvalidatedObject, Object value) {

        User user = (User)validatedObject;

        int age = user.getAge();

        if(age <18 || age> 65)

            return false;

        else

            return true;

    }

}

 

 
posted on 2022-04-06 22:05  or追梦者  阅读(557)  评论(0编辑  收藏  举报