为什么BindingResult必须跟在@Valid后面呢?

Why does BindingResult have to follow @Valid?

当我遇到错误时,我正在努力将 Spring MVC 验证 return 到页面提交页面。我终于解决了这个问题,因为我注意到 BindingResult 需要紧挨着我正在验证的表单参数。

例如,如果我将 spring.io 教程 (http://spring.io/guides/gs/validating-form-input/) 中的 checkPersonInfo 方法修改为 -

@RequestMapping(value="/", method=RequestMethod.POST)
public String checkPersonInfo(@Valid Person person, BindingResult bindingResult, Model model) {
    if (bindingResult.hasErrors()) {
        return "form";
    }
    return "redirect:/results";
}

然后它将工作并重定向到表单页面,但如果我将其更改为 -

@RequestMapping(value="/", method=RequestMethod.POST)
public String checkPersonInfo(@Valid Person person, Model model, BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        return "form";
    }
    return "redirect:/results";
}

然后重定向到/errors

这是什么原因?

BindingResult 必须跟随绑定的对象。原因是,如果你有更多的对象被绑定,你必须知道哪个 BindingResult 属于哪个对象。

您的请求处理程序中可能有多个模型属性,每个属性都有自己的绑定结果。为了适应这一点,Spring 决定将绑定结果参数绑定到前一个参数。

是啊,今天我花了很长时间检查为什么不能返回提交的页面而是转到默认的可白化错误页面。

调试后得到源码

// org.springframework.web.method.annotation.ModelAttributeMethodProcessor#resolveArgument
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
    throw new BindException(binder.getBindingResult());
}

如果BindingResult不跟@Valid,导致isBindExceptionRequired(binder, parameter) return为真,然后直接抛出异常,无法执行controller方法中的代码。

// org.springframework.web.method.annotation.ModelAttributeMethodProcessor#isBindExceptionRequired 
protected boolean isBindExceptionRequired(WebDataBinder binder, MethodParameter methodParam) {
    int i = methodParam.getParameterIndex();
    Class<?>[] paramTypes = methodParam.getMethod().getParameterTypes();
    boolean hasBindingResult = (paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1]));
    return !hasBindingResult;
}