quot;;
// 分组
Class[] groups() default {};
// 负载
Class[] payload() default {};
}
实现 ConstraintValidator 接口编写约束校验器
public class EncryptIdValidator implements ConstraintValidator<EncryptId, String> {
private static final Pattern PATTERN = Pattern.compile("^[a-f\\d]{32,256}$");
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
// 不为null才进行校验
if (value != null) {
Matcher matcher = PATTERN.matcher(value);
return matcher.find();
}
return true;
}
}
编程式校验
上面的示例都是基于注解来实现自动校验的,在某些情况下,我们可能希望以编程方式调用验证。这个时候可以注入
javax.validation.Validator 对象,然后再调用其 api。
@Autowired
private javax.validation.Validator globalValidator;
// 编程式校验
@PostMapping("/saveWithCodingValidate")
public Result saveWithCodingValidate(@RequestBody UserDTO userDTO) {
Set<constraintviolation> validate = globalValidator.validate(userDTO, UserDTO.Save.class);
// 如果校验通过,validate 为空;否则,validate 包含未校验通过项
if (validate.isEmpty()) {
// 校验通过,才会执行业务逻辑处理
} else {
for (ConstraintViolation userDTOConstraintViolation : validate) {
// 校验失败,做其它逻辑
System.out.println(userDTOConstraintViolation);
}
}
return Result.ok();
}
快速失败(Fail Fast)配置
Spring Validation 默认会校验完所有字段,然后才抛出异常。可以通过一些简单的配置,开启 Fali Fast 模式,一旦校验失败就立即返回。
@Bean
public Validator validator() {
ValidatorFactory validatorFactory = Validation.byProvider(Hibernateva lidator.class)
.configure()
// 快速失败模式
.failFast(true)
.buildValidatorFactory();
return validatorFactory.getValidator();
}
校验信息的国际化
Spring 的校验功能可以返回很友好的校验信息提示,而且这个信息支持国际化。
这块功能暂时暂时不常用,具体可以参考这篇文章
@Validated 和@Valid 的区别联系
首先,@Validated 和@Valid 都能实现基本的验证功能,也就是如果你是想验证一个参数是否为空,长度是否满足要求这些简单功能,使用哪个注解都可以。
但是这两个注解在分组、注解作用的地方、嵌套验证等功能上两个有所不同。下面列下这两个注解主要的不同点。
- @Valid 注解是 JSR303 规范的注解,@Validated 注解是 Spring 框架自带的注解;
- @Valid 不具有分组校验功能,@Validate 具有分组校验功能;
- @Valid 可以用在方法、构造函数、方法参数和成员属性(字段)上,@Validated 可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上,两者是否能用于成员属性(字段)上直接影响能否提供嵌套验证的功能;
- @Valid 加在成员属性上可以对成员属性进行嵌套验证,而@Validate 不能加在成员属性上,所以不具备这个功能。
这边说明下,什么叫嵌套验证。
我们现在有个实体叫做 Item:
public class Item {
@NotNull(message = "id不能为空")
@Min(value = 1, message = "id必须为正整数")
private Long id;
@NotNull(message = "props不能为空")
@Size(min = 1, message = "至少要有一个属性")
private List<Prop> props;
}
Item 带有很多属性,属性里面有:pid、vid、pidName 和 vidName,如下所示:
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;
}
属性这个实体也有自己的验证机制,比如 pid 和 vid 不能为空,pidName 和 vidName 不能为空等。
现在我们有个 ItemController 接受一个 Item 的入参,想要对 Item 进行验证,如下所示:
@RestController
public class ItemController {
@RequestMapping("/item/add")
public void addItem(@Validated Item item, BindingResult bindingResult) {
doSomething();
}
}
在上图中,如果 Item 实体的 props 属性不额外加注释,只有@NotNull 和@Size,无论入参采用@Validated 还是@Valid 验证,Spring Validation 框架只会对 Item 的 id 和 props 做非空和数量验证,不会对 props 字段里的 Prop 实体进行字段验证,也就是@Validated 和@Valid 加在方法参数前,都不会自动对参数进行嵌套验证。也就是说如果传的 List 中有 Prop 的 pid 为空