总结⼀下@Validated和@Valid在嵌套验证功能上的区别:
@Validated:在方法参上无法单独提供嵌套验证功能。不能用在成员属性(字段)上,也无法提示框架进行嵌套验证。能配合嵌套验证注解@Valid进行嵌套验证。
@Valid:用在方法入参上无法单独提供嵌套验证功能。能够用在成员属性(字段)上,提示验证框架进⾏嵌套验证。能配合嵌套验证注解
@Valid进⾏嵌套验证。使用@Valid需要配合BindingResult可以直接提供参数验证结果
基于@Validated不能用在属性上或字段上所以不能进行集合嵌套验证及@Valid需要使用BindingResult才能显示验证结果且不能进行分组验证;所以本文通过自定义注解结合@Validated实现集合验证时分组及嵌套验证。
1、自定义一个校验注解类
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 顶一个一个集合中每一个元素校验
*/
@Retention(RetentionPolicy.RUNTIME)
/**
*
*/
@Target(value = {ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Constraint(validatedBy = {CollectionValidator.class})//指定使用那些类型进行校验
public @interface CollectionAny {
//定义默认验证消息
String message() default "集合验证不通过";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
2、自定义一个校验处理类
import com.ruoyi.common.utils.bean.BeanValidators;
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorContextImpl;
import org.springframework.beans.factory.annotation.Autowired;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;
import java.util.Collection;
import java.util.Set;
/**
* 定义一个结合校验器
* 第一个参数“CollectionAny”定义校验注解的类
* 第二个参数“Collection”指定要校验的参数类型
*/
public class CollectionAnyValidator implements ConstraintValidator<CollectionAny, Collection> {
@Autowired
protected Validator validator;
/**
* 這个方法要返回“true”和“false”
* true:表示验证通过
* false:表示验证不通过,明确返回false的时候才会提示对应配置的消息
*
* @param collection
* @param constraintValidatorContext
* @return
*/
@Override
public boolean isValid(Collection collection, ConstraintValidatorContext constraintValidatorContext) {
if (collection == null || collection.size() == 0) {
return true;
}
try {
ConstraintValidatorContextImpl constraintValidatorContext1 = (ConstraintValidatorContextImpl) constraintValidatorContext;
Class<?>[] groupArray = null;
if (constraintValidatorContext1 != null) {
Set<Class<?>> groupSet = constraintValidatorContext1.getConstraintDescriptor().getGroups();
groupArray = groupSet.toArray(new Class<?>[0]);
}
for (Object bean : collection) {
//groupArray 让验证继续传递分组特性
BeanValidators.validateWithException(validator, bean, groupArray);
}
return true;
} catch (ConstraintViolationException ex) {
//禁用默认约束信息
constraintValidatorContext.disableDefaultConstraintViolation();
//将默认信息与具体对象错误信息合并成新的模板
constraintValidatorContext.buildConstraintViolationWithTemplate(String.format("%s[%s]", constraintValidatorContext.getDefaultConstraintMessageTemplate(), ex.getMessage()))
//必须要使用该方法将消息添加到认证器中
.addConstraintViolation();
return false;
}
}
}
3、测试验证实体类
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Update;
import javax.validation.constraints.NotNull;
public class TestEntity {
@NotNull(message = "nameInsert不能为空", groups = Insert.class)
public String nameInsert;
@NotNull(message = "nameUpdate不能为空", groups = Update.class)
public String nameUpdate;
@NotNull(message = "name不能为空")
public String name;
}
4、测试验证集合类
import com.ruoyi.common.collection.CollectionAny;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Update;
import java.util.List;
public class TestEntityColleection {
@CollectionAny(message = "listInsert字段集合验证不通过", groups = Insert.class)
public List<TestEntity> listInsert;
@CollectionAny(message = "listUpdate字段集合验证不通过", groups = Update.class)
public List<TestEntity> listUpdate;
@CollectionAny(message = "字段集合验证不通过")
public List<TestEntity> list;
}
5、验证方法和参数
//{
// "list": [
// {
// "name": "",
// "nameInsert": null,
// "nameUpdate": null
// }
// ],
// "listInsert": [
// {
// "name": null,
// "nameInsert": null,
// "nameUpdate": null
// }
// ],
// "listUpdate": [
// {
// "name": null,
// "nameInsert": null,
// "nameUpdate": null
// }
// ]
//}
@ApiOperation("没有分组")
@PostMapping("/test2")
public AjaxResult test2(@RequestBody @Validated TestEntityColleection testEntity) {
return AjaxResult.success();
}
//{
// "list": [
// {
// "name": null,
// "nameInsert": null,
// "nameUpdate": null
// }
// ],
// "listInsert": [
// {
// "name": null,
// "nameInsert": "",
// "nameUpdate": null
// }
// ],
// "listUpdate": [
// {
// "name": null,
// "nameInsert": null,
// "nameUpdate": null
// }
// ]
//}
@ApiOperation("Update分组")
@PostMapping("/testUpdate")
public AjaxResult testUpdate(@RequestBody @Validated(Update.class) TestEntityColleection testEntity) {
return AjaxResult.success();
}
//{
// "list": [
// {
// "name": null,
// "nameInsert": null,
// "nameUpdate": null
// }
// ],
// "listInsert": [
// {
// "name": null,
// "nameInsert": null,
// "nameUpdate": null
// }
// ],
// "listUpdate": [
// {
// "name": null,
// "nameInsert": null,
// "nameUpdate": ""
// }
// ]
//}
@ApiOperation("Insert分组")
@PostMapping("/testInsert")
public AjaxResult testInsert(@RequestBody @Validated(Insert.class) TestEntityColleection testEntity) {
return AjaxResult.success();
}