Spring 验证:使用两个验证器时得到 "Invalid target for Validator"

Spring validation: getting "Invalid target for Validator" when using two validators

我在使用@InitBinder 注释实现两个验证器时遇到问题。

控制器代码:

@Autowired
private SessionValidator sessionValidator;

@Autowired
private ChannelValidator channelValidator;

@InitBinder
public void initBinder(WebDataBinder binder){
    binder.addValidators(sessionValidator, channelValidator);
}

@RequestMapping(method = RequestMethod.GET)
public UserInfo findBySession(
        @Valid @ModelAttribute Session session,
        @Valid @ModelAttribute Channel channel){
    //...
}

会话验证器:

@Component
public class SessionValidator implements Validator {

    @Override
    public boolean supports(Class<?> aClass){
        return Session.class.equals(aClass);
    }

    @Override
    public void validate(Object o, Errors errors){
        //...
    }
}

频道验证器:

@Component
public class ChannelValidator implements Validator {

    @Override
    public boolean supports(Class<?> aClass){
        return Channel.class.equals(aClass);
    }

    @Override
    public void validate(Object o, Errors errors){
        //...
    }
}

我在调用控制器时收到以下异常:

Caused by: java.lang.IllegalStateException: Invalid target for Validator [com.almundo.p13n.dna.validators.ChannelValidator@4e642ee1]: Session(null, null)

有人知道怎么解决吗?提前致谢!

您绑定了两个验证器,但对于每个用于验证的参数,将只支持其中一个。
SessionValidator支持Session参数但不支持Channel参数反之ChannelValidator支持Channel参数但不支持Session参数。
而异常。

作为第一种选择,您可以在每个 Spring 验证器子 class 中支持两种参数类型。它有点笨拙,但应该可以工作:

@Override
public boolean supports(Class<?> aClass){
    return Channel.class.equals(aClass) ||  Session.class.equals(aClass);
}

你当然应该检查 validate() 中的类型,只有当它与验证器 class 匹配时才执行验证。

作为第二种选择,使用标准验证 API 通过为每个 class 实现 javax.validation.ConstraintValidator 来验证并在控制器中显式验证参数。

作为第三种选择,如果有意义,您可以直接在 SessionChannel class 上注释约束。因此,您仍然可以在参数声明中使用 @Valid 来保持自动验证。

您只能添加受支持的验证器:

@InitBinder
protected void initBinder(WebDataBinder binder) {
    if (binder.getTarget() == null) return;
    final ImmutableList<Validator> validatorsList = ImmutableList.of(
        new CunsomValidator1(),
        new CunsomValidator2()
    );

    for (Validator validator : validatorsList) {
        if (validator.supports(binder.getTarget().getClass())) {
            binder.addValidators(validator);
        }
    }
}