OVAL验证框架
介绍
依赖
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>
注解释义
使用
基本用法
注解加载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](https://img2022.cnblogs.com/blog/1628202/202204/1628202-20220406220514862-1635807995.png)
通用属性
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](https://img2022.cnblogs.com/blog/1628202/202204/1628202-20220406220514892-1793030244.png)
@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; } }
作者: deity-night
出处: https://www.cnblogs.com/deity-night/
关于作者:码农
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出, 原文链接 如有问题, 可邮件(***@163.com)咨询.