为啥 BindingResult 必须遵循 @Valid?

Posted

技术标签:

【中文标题】为啥 BindingResult 必须遵循 @Valid?【英文标题】:Why does BindingResult have to follow @Valid?为什么 BindingResult 必须遵循 @Valid? 【发布时间】:2015-05-07 09:48:06 【问题描述】:

当我遇到错误时,我正在努力让我的 Spring MVC 验证返回到页面提交页面。我终于通过注意到 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

这是什么原因?

【问题讨论】:

【参考方案1】:

BindingResult 必须跟随绑定的对象。原因是如果绑定的对象比较多,就必须知道哪个BindingResult属于哪个对象。

【讨论】:

在这种情况下,如果我有多个要验证的对象,那么我是否必须添加多个 @Valid? 是的,Valid注解属于指定的参数。【参考方案2】:

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

【讨论】:

【参考方案3】:

是啊,今天查了好久,为什么不能返回提交的页面,而是进入一个默认的whitelable错误页面。

调试后得到源代码

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

如果BindingResult不跟随@Valid,导致isBindExceptionRequired(binder, parameter)返回true,然后直接抛出异常,因此无法在控制器方法中执行代码。

// 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;
  

【讨论】:

我的调试问题完全相同。错误消息根本没有信息!

以上是关于为啥 BindingResult 必须遵循 @Valid?的主要内容,如果未能解决你的问题,请参考以下文章

使用aop和BindingResult进行参数验证

使用@Valid+BindingResult进行controller参数校验

Java使用@Valid+BindingResult进行controller参数校验

如果 TCP 是面向连接的,为啥数据包遵循不同的路径?

为啥文本 I/O 必须在 python 3 中缓冲?

BindingResult不能获取错误对象