【问题标题】:Spring validation: getting "Invalid target for Validator" when using two validatorsSpring验证:使用两个验证器时获取“验证器的无效目标”
【发布时间】:2018-08-13 21:03:02
【问题描述】:

我在使用 @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)

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

【问题讨论】:

    标签: spring spring-mvc spring-boot custom-validators


    【解决方案1】:

    您绑定了两个验证器,但每个参数只支持一个验证器。
    SessionValidator 支持Session 参数但不支持Channel 参数,反之ChannelValidator 支持Channel 参数,但不支持Session 参数。
    而例外。

    作为第一种选择,您可以在每个 Spring Validator 子类中同时支持这两种参数类型。这有点笨拙,但应该可以:

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

    您当然应该检查validate() 中的类型并仅在它与验证器类匹配时执行验证。

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

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

    【讨论】:

    • Spring 应该使用更聪明的方法!我不明白在 support(Class aClass) 方法中检查类型的目的(它没有用于匹配正确的验证器)或在活页夹中添加多个验证器(当只有一个应该工作时)。
    • 如您所说,第一种方法看起来很笨拙,当您无法修改 Session 或 Channel 类时,第二种和第三种方法是不可能的:(
    • 第二种方式不需要修改Session和Channel。您将有两个实现 javax.validation.ConstraintValidator 的类,它们指定如何验证它们,并且您将在控制器中显式调用。
    【解决方案2】:

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

    @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);
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-07-25
      • 2021-03-18
      • 1970-01-01
      • 1970-01-01
      • 2018-09-08
      • 1970-01-01
      • 1970-01-01
      • 2019-07-17
      • 2015-02-12
      相关资源
      最近更新 更多