【问题标题】:Spring MVC controller returning null modelAttribute when @Valid fails当@Valid 失败时,Spring MVC 控制器返回 null modelAttribute
【发布时间】:2017-10-15 18:42:45
【问题描述】:

我已经为这个挠头很久了。我正在开发一个拥有 20 多个控制器的网络应用程序,而我只有一个控制器遇到了这个奇怪的问题。无论我与工作人员比较多长时间,我似乎都找不到任何差异。基本上,只要验证不失败,我就可以毫无问题地添加接口实体。如果我尝试保存一个完全空的对象(例如,或者将其中一个必填字段留空),我会收到此错误:

java.lang.IllegalStateException: Bean 名称“intface”的 BindingResult 和普通目标对象都不能用作请求属性

这里是相关代码:

查看:

<form:form method="POST" modelAttribute="intface" class="form-style-7">
            <form:input type="hidden" path="id" id="id"/>
            <table>
                <tr>
                    <td><label for="name">Name: </label> </td>
                    <td><form:input path="name" id="name"/></td>
                    <td><form:errors path="name" cssClass="error"/></td>
                </tr>
                <tr>
                    <td><label for="type">Type: </label> </td>
                    <td><form:input path="type" id="type"/></td>
                    <td><form:errors path="type" cssClass="error"/></td>
                </tr>
                <tr>
                    <td><label for="ip">IP: </label> </td>
                    <td><form:input path="ip" id="ip"/></td>
                    <td><form:errors path="ip" cssClass="error"/></td>
                </tr>
                <tr>
                    <td><label for="port">Port: </label> </td>
                    <td><form:input path="port" id="port"/></td>
                    <td><form:errors path="port" cssClass="error"/></td>
                </tr>
                <tr>
                    <td><label for="test">Test: </label> </td>
                    <td><form:checkbox path="test" id="test"/></td>
                    <td><form:errors path="test" cssClass="error"/></td>
                </tr>
                <tr>
                    <td colspan="3">
                        <c:choose>
                            <c:when test="${edit}">
                                <input type="submit" value="Update Interface"/>
                            </c:when>
                            <c:otherwise>
                                <input type="submit" value="Add Interface"/>
                            </c:otherwise>
                        </c:choose>
                    </td>
                </tr>
            </table>
        </form:form>

控制器:

@RequestMapping(value = {"/newInterface"}, method = RequestMethod.POST)
public String saveInterface(@Valid Interface intface, BindingResult result, ModelMap model) 
{
    if (result.hasErrors()) 
    {
        return "interfaceDataAccess";
    }
    interfaceService.saveInterface(intface);
    return "redirect:/interfaces/list";
}

实体:

 @RequestMapping(value = {"/newInterface"}, method = RequestMethod.POST)
public String saveInterface(@Valid Interface intface, BindingResult result, ModelMap model) 
{
    if (result.hasErrors()) 
    {
        return "interfaceDataAccess";
    }
    interfaceService.saveInterface(intface);
    return "redirect:/interfaces/list";
}

你会注意到这个 @Unique 注释,这是我构建的。本质上,它允许我检查用户输入的值之一是否已经存在,并且在我的其他实体上工作得很好。我尝试完全删除它,但一旦验证失败,我仍然会收到此异常。我确实有 20 多个控制器,它们的工作方式完全相同,逐行运行,而且工作正常。这完全让我感到困惑,我敢肯定这真的很愚蠢。如果需要,我可以提供工作实体的 MVC 代码进行比较。

谢谢

* 编辑 *

这是我的 heightUnit 类的一些工作代码:

控制器:

@RequestMapping(value = {"/newHeightUnit"}, method = RequestMethod.GET)
public String newHeightUnit(ModelMap model) 
{
    HeightUnit heightUnit = new HeightUnit();
    model.addAttribute("heightUnit", heightUnit);
    model.addAttribute("edit", false);
    return "heightUnitDataAccess";
}

@RequestMapping(value = {"/newHeightUnit"}, method = RequestMethod.POST)
public String saveHeightUnit(@Valid HeightUnit heightUnit, BindingResult result, ModelMap model) 
{
    if (result.hasErrors()) 
    {
        return "heightUnitDataAccess";
    }
    heightUnitService.saveHeightUnit(heightUnit);
    return "redirect:/heightUnits/list";
}

查看:

<form:form method="POST" modelAttribute="heightUnit" class="form-style-7">
            <form:input type="hidden" path="id" id="id"/>
            <ul>
                <li>
                    <label for="name">Name: </label>
                    <form:input path="name" id="name"/>
                    <span><form:errors path="name" cssClass="error"/></span>
                </li>
                <c:choose>
                    <c:when test="${edit}">
                        <input type="submit" value="Update Height Unit"/>
                    </c:when>
                    <c:otherwise>
                        <input type="submit" value="Add Height Unit"/>
                    </c:otherwise>
                </c:choose>
            </ul>
        </form:form>

实体:

private int id;
private String name;

@Id
@GeneratedValue
public int getId() 
{
    return id;
}

public void setId(int id) 
{
    this.id = id;
}

@Size(min = 1, max = 15, message = "Name must be between 1 and 15 characters long")
@Unique(entityType = "heightUnit", field = "name", message = "The name needs to be unique!")
@Column(nullable = false, unique = true, length = 15)
public String getName() 
{
    return name;
}

public void setName(String name) 
{
    this.name = name;
}

@Override
public boolean equals(Object obj) 
{
    if (obj instanceof HeightUnit)
    {
        HeightUnit heightUnit = (HeightUnit)obj;
        if (id == heightUnit.getId())
        {
            return true;
        }
    }
    return false;
}

@Override
public int hashCode() 
{
    int hash = 7;
    hash = 37 * hash + this.id;
    hash = 37 * hash + Objects.hashCode(this.name);
    return hash;
}

这很好用,当我试图打破验证规则时,我会在表单上返回错误。

【问题讨论】:

  • 我将我的 modelAttribute intface 称为测试,认为当它被称为接口时它不喜欢它,没有运气。
  • 另外,如果我在 hasErrors() 行之后将此代码添加到控制器,我可以防止错误:model.addAttribute("intface", intface);但它所做的是重定向到表单上没有错误的页面。我迷路了
  • 它实际上就像@Valid 机制在将我的 intface 对象在内部传递回视图以显示错误之前使我的 intface 对象无效

标签: java spring spring-mvc model-view-controller


【解决方案1】:

您的问题是您正在前往表单页面,并且它正在寻找 aIt 不可用的预实例化模型。你要做的就是添加Interface对象作为模型的属性:

model.addAttribute("intface", new Interface());

记得将它添加到 @RequestMapping 带注释的方法中,该方法会将您带到表单页面,如下所示:

@RequestMapping(value = "/", method = RequestMethod.GET) 
public String displayNewInterfaceLogin(Model model) { 
    model.addAttribute("intface", new Interface()); 
    return "newInterface"; 
}

【讨论】:

  • 我确实这样做了,但这消除了通常会在表单错误字段中显示的任何错误,它使页面就像我第一次打开它并且我没有输入任何数据一样这不是我想要的行为。我将为另一个可以正常工作的实体添加一些工作代码到我的原始帖子中。 Spring 能够以某种方式在内部自行返回这个无效对象,并显示在验证期间抛出的相关错误,并且由于某种原因,这个实体没有发生。
  • 还有其他想法吗?
【解决方案2】:

我终于想通了。不管出于什么原因,我不得不将控制器的 saveInterface 方法的签名更改为:

public String saveInterface(@Valid @ModelAttribute("intface") Interface intface, BindingResult result, ModelMap model) 

我不知道为什么当我的所有实体类型的 CRUD 操作都以完全相同的方式构建时只有这个实体会抱怨这一点,但是你去吧!

希望这最终能对某人有所帮助!

【讨论】:

    猜你喜欢
    • 2014-11-03
    • 2015-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-15
    • 2013-05-28
    • 2015-01-15
    • 1970-01-01
    相关资源
    最近更新 更多