【问题标题】:Validate a list of nested objects with Spring validator?使用 Spring 验证器验证嵌套对象列表?
【发布时间】:2012-09-22 17:48:51
【问题描述】:

我想知道如何在 Spring MVC 应用程序中使用 Spring Validator(不是注释)来验证我的表单中的嵌套对象列表。

class MyForm() {
    String myName;
    List<TypeA> listObjects;
}
class TypeA() {
    String number;
    String value;
}

如何创建 MyFormValidator 来验证 listObjects 并为 TypeA 的数量和值添加错误消息。

【问题讨论】:

    标签: java list spring-mvc nested validation


    【解决方案1】:

    对于嵌套验证,您可以执行以下操作:

    public class MyFormValidator implements Validator {
    
        private TypeAValidator typeAValidator;
    
        @Override
        public boolean supports(Class clazz) {
            return MyForm.class.equals(clazz);
        }
    
        @Override
        public void validate(Object target, Errors errors) {
            MyForm myForm = (MyForm) target;
            typeAValidator = new TypeAValidator();
    
            int idx = 0;
            for (TypeA item : myForm.getListObjects()) {
    
                errors.pushNestedPath("listObjects[" + idx + "]");
                ValidationUtils.invokeValidator(this.typeAValidator, item, errors);
                errors.popNestedPath();
                idx++;
    
                ...
            }
    
            ...
        }
    }
    
    public class TypeAValidator implements Validator{
    
        @Override
        public boolean supports(Class<?> clazz) {
            return TypeA.class.isAssignableFrom(clazz);
        }
    
        @Override
        public void validate(Object target, Errors errors) {
            TypeA objTypeA = (TypeA)target;
    
            ValidationUtils.rejectIfEmpty(errors, "number", "number.notEmpty");
        }
    }
    

    希望这会有所帮助。

    【讨论】:

    • 我会推荐这个解决方案。刚刚在我正在进行的项目中遇到了类似的问题。此解决方案允许您保持代码模块化,如果需要,将您的验证拆分为多个不同的验证器。
    • 很高兴它有帮助。我发布此内容的目的是因为它是模块化且易于维护的。
    • 知道如何报告哪一行有错误吗?
    • TypeA 有一个属性List&lt;TypeA&gt;(嵌套)时,这会起作用吗?如果我有一个类是 RuleCondition... 我可能有一个嵌套的 List&lt;RuleCondition&gt; 字段。我想知道这是否也适用于这种情况
    • ^ 请忽略我的问题,我试过了,它适用于我给定的场景。谢谢!
    【解决方案2】:
    public class MyFormValidator implements Validator {
    
        @Override
        public boolean supports(Class clazz) {
            return MyForm.class.equals(clazz);
        }
    
        @Override
        public void validate(Object target, Errors errors) {
            MyForm myForm = (MyForm) target;
    
            for (int i = 0; i < myForm.getListObjects().size(); i++) {
                TypeA typeA = myForm.getListObjects().get(i);
    
                if(typeAHasAnErrorOnNumber) {
                    errors.rejectValue("listObjects[" + i + "].number", "your_error_code");
                }
    
                ...
            }
    
            ...
        }
    
    }
    

    有趣的链接:

    【讨论】:

    • 谢谢,杰罗姆。如果 TypeA 有自己的验证器,如何在 MyFormValidator 中使用验证器?如果有多个错误,如何在表单页面上只显示一条错误消息?
    【解决方案3】:

    我使用的一个方便的辅助类 -

    public final class ValidationHelper {
    
        public static <TEntity> void invokeNestedValidator(Validator validator, TEntity entity, Errors errors, String subPath) {
            try {
                errors.pushNestedPath(subPath);
                ValidationUtils.invokeValidator(validator, entity, errors);
            } finally {
                errors.popNestedPath();
            }
        }
    
        public static <TEntity> void invokeNestedValidatorForList(Validator validator, List<TEntity> entities, Errors errors, String subPathRoot) {
            for (int index = 0; index < entities.size(); index++) {
                invokeNestedValidator(validator, entities.get(index), errors, subPathRoot + "[" + index + "]");
            }
        }
    
        private ValidationHelper() {}
    }
    

    【讨论】:

    • 如何使用ValidationHelper类?
    【解决方案4】:

    你可以在项目的任何地方使用它

    import org.springframework.validation.ValidationUtils;
    import org.apache.commons.beanutils.PropertyUtils;
    import org.apache.commons.collections.CollectionUtils;
    
        public static void invokeValidatorForNestedCollection(Validator validator,
                                                          Object obj,
                                                          String collectionPath,
                                                          Errors errors) {
    
        Collection collection;
        try {
            collection = (Collection) PropertyUtils.getProperty(obj, collectionPath);
        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    
        if (CollectionUtils.isEmpty(collection)) return;
        int counter = 0;
        for (Object elem : collection) {
            errors.pushNestedPath(String.format(collectionPath + "[%d]", counter));
            ValidationUtils.invokeValidator(validator, elem, errors);
            errors.popNestedPath();
            counter++;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-05-16
      • 2021-04-22
      • 2021-08-18
      • 2018-02-27
      • 2019-05-08
      • 1970-01-01
      • 2020-12-02
      相关资源
      最近更新 更多