简体   繁体   English

Spring MVC和JSR 303 - 手动验证

[英]Spring MVC and JSR 303 - Manual Validation

I'm using Spring MVC 3 and JSR 303. I have a form backing object that has beans of different types in it. 我正在使用Spring MVC 3和JSR 303.我有一个表单支持对象,其中包含不同类型的bean。 Depending on a request parameter value, I'll have to choose a bean to validate and save. 根据请求参数值,我必须选择一个bean来验证和保存。 I can't use @Valid for validation since the bean to validate is not known until the runtime. 我无法使用@Valid进行验证,因为要运行时才知道要验证的bean。

I was able to inject a javax.validation.Validator to the controller, but I'm not sure how to validate a bean with it and store any errors in a BindingResult/Error in a "Spring way". 我能够向控制器注入一个javax.validation.Validator ,但我不知道如何用它来验证bean并在“Spring方式” BindingResult/Error任何错误存储在BindingResult/Error中。

I need to do it in the handler method, rather than an initBinder method, because of request mapping. 由于请求映射,我需要在处理程序方法而不是initBinder方法中执行此操作。

[edit] [编辑]

The problem I'm having with validate(Object, Errors) is that it doesn't recognize nested beans. 我在validate(Object, Errors)遇到的问题是它无法识别嵌套bean。 The bean to validate is accessed through foo.getBar().getBean(), where the foo is the form backing object. 要验证的bean是通过foo.getBar()。getBean()访问的,其中foo是表单后备对象。 When I do validate(foo.getBar().getBean(), errors) , I get the following error message. 当我validate(foo.getBar().getBean(), errors) ,我收到以下错误消息。

JSR-303 validated property 'property-name' does not have a corresponding accessor for Spring data binding

Has anyone done something like this before? 以前有人做过这样的事吗? Thanks. 谢谢。

Yup, the magic class you're looking for is org.springframework.validation.beanvalidation.SpringValidatorAdapter 是的,你正在寻找的魔法类是org.springframework.validation.beanvalidation.SpringValidatorAdapter

This class gets a javax.validation.Validator injected into it and contains the code for, as its name implies, 'adapting' the output back into the familiar Errors object. 该类获取一个注入其中的javax.validation.Validator,并包含代码,顾名思义,将输出“调整”回熟悉的Errors对象。 It's what's being used internally to do the processing when you put @Valid on a method parameter. 当你将@Valid放在方法参数上时,它就是在内部用来进行处理的。

You can get them directly by adding an explicit LocalValidatorFactoryBean in your dispatcher servlet. 您可以通过在调度程序servlet中添加显式LocalValidatorFactoryBean来直接获取它们。 Just inject an instance of that as an instance of the standard Spring Validator interface and use it like you would any 'pre jsr-303' spring validation provider. 只需注入一个实例作为标准Spring Validator接口的实例,并像使用任何'pre jsr-303'弹簧验证提供程序一样使用它。

Just a guess, but have you tried 只是一个猜测,但你有没有尝试过

 errors.pushNestedPath("bar.bean"); // Path to the nested bean
 validate(foo.getBar().getBean(), errors)
 errors.popNestedPath();

That's how BindingResult is usually used for validation of the nested beans. 这就是BindingResult通常用于验证嵌套bean的方式。

The way the I've seen this done is to use a standard JSR-303 validator (whatever you're already injecting in) to get the violations (ie Set<ConstraintViolaion<T>> ) 我看到这样做的方式是使用标准的JSR-303验证器(无论你注入的是什么)来获取违规(即Set<ConstraintViolaion<T>>

Then use code similar to that inside LocalValidatorFactoryBean to convert between those violations and Spring Errors: 然后使用类似于LocalValidatorFactoryBean内部的代码来转换这些违规和Spring错误:

public static <T> void convert(Errors errors, Collection<ConstraintViolation<T>> violations) {
        for (ConstraintViolation<?> violation : violations) {
            String field = violation.getPropertyPath().toString();
            FieldError fieldError = errors.getFieldError(field);
            if (fieldError == null || !fieldError.isBindingFailure()) {
                errors.rejectValue(field, violation.getConstraintDescriptor().getAnnotation().annotationType()
                        .getSimpleName(), getArgumentsForConstraint(errors.getObjectName(), field, violation
                        .getConstraintDescriptor()), violation.getMessage());
            }
        }
    }

    private static Object[] getArgumentsForConstraint(String objectName, String field,
            ConstraintDescriptor<?> descriptor) {
        List<Object> arguments = new LinkedList<Object>();
        String[] codes = new String[] { objectName + Errors.NESTED_PATH_SEPARATOR + field, field };
        arguments.add(new DefaultMessageSourceResolvable(codes, field));
        arguments.addAll(descriptor.getAttributes().values());
        return arguments.toArray(new Object[arguments.size()]);
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM