我在两个实体之间有一个简单的关联-Category
和Email
(NtoM)。我正在尝试创建用于浏览和管理它们的Web界面。为了浏览类别并将电子邮件添加到该类别中,我使用包裹有@RequestMapping
类别ID(UUID)的控制器,因此所有控制器操作始终在使用path指定的类别的上下文中进行。
我@ModelAttribute
用来预加载整个控制器范围的上下文类别。
这种方法非常适合列出和显示表单。但是,它在提交表单时失败-经过一点调试后,我发现表单数据覆盖了我的category@ModelAttribute
参数。
在我的代码中,方法save()
中category
的确不是用addCategory()
方法加载的模型属性,而是用表单数据填充的(email
模型也填充了,这是正确的)。
我在寻找解决方案,使我只能将表单数据绑定到specific @ModelAttribute
。
我在Spring MVC文档中已经读到,参数的顺序很重要,但是我根据示例对它们进行了排序,但仍然无法正常工作。
这是我的控制器:
@Controller
@RequestMapping("/emails/{categoryId}")
public class EmailsController
{
@ModelAttribute("category")
public Category addCategory(@PathVariable UUID categoryId)
{
return this.categoryService.getCategory(categoryId);
}
@InitBinder
public void initBinder(WebDataBinder binder)
{
binder.registerCustomEditor(Set.class, "categories", new CategoriesSetEditor(this.categoryService));
}
@RequestMapping(value = "/create", method = RequestMethod.GET)
public String createForm(@ModelAttribute Category category, Model model)
{
// here everything works, as there is just a single @ModelAttribute
return "emails/form";
}
@RequestMapping(value = "/save", method = RequestMethod.POST)
public String save(
@ModelAttribute @Valid Email email,
BindingResult result,
Model model,
@ModelAttribute("category") Category category
) {
// saving entity, etc
// HERE! problem is, that response is bound BOTH to `email' and `category' model attributes
// and overrides category loaded in `addCategory()' method
return String.format("redirect:/emails/%s/", category.getId().toString());
}
}
以防万一,这里也是表单代码:
<form:form action="${pageContext.request.contextPath}/emails/${category.id}/save" method="post" modelAttribute="email">
<form:hidden path="id"/>
<fieldset>
<label for="emailName"><spring:message code="email.form.label.Name" text="E-mail address"/>:</label>
<form:input path="name" id="emailName" required="required"/>
<form:errors path="name" cssClass="error"/>
<label for="emailRealName"><spring:message code="email.form.label.RealName" text="Recipient display name"/>:</label>
<form:input path="realName" id="emailRealName"/>
<form:errors path="realName" cssClass="error"/>
<label for="emailIsActive"><spring:message code="email.form.label.IsActive" text="Activation status"/>:</label>
<form:checkbox path="active" id="emailIsActive"/>
<form:errors path="active" cssClass="error"/>
<form:checkboxes path="categories" element="div" items="${categories}" itemValue="id" itemLabel="name"/>
<form:errors path="categories" cssClass="error"/>
<button type="submit"><spring:message code="_common.form.Submit" text="Save"/></button>
</fieldset>
</form:form>
注意:我不希望@ModelAttribute
POST包含多个s,而只是想将表单模型与先前生成的属性区分开。
我不确定我是否完全理解问题,但是对我来说,似乎您希望在显示表单时模型中存在类别对象,但不希望通过表单发布对其进行更改?
当您在参数列表中指定@ModelAttribute(“ categories”)时,您基本上会告诉Spring MVC使用参数名称“ categories”将表单数据绑定到带注释的对象。
如果您不希望绑定对象,则将其从参数列表中删除。如果您需要处理程序方法中的原始对象,可以通过调用addCategory并提供与@PathVariable映射的ID来手动获取它:
@RequestMapping(value = "/save", method = RequestMethod.POST)
public String save(
@ModelAttribute @Valid Email email,
BindingResult result,
Model model,
@PathVaribale("categoryId") UUID categoryId
) {
// saving entity, etc
return String.format("redirect:/emails/%s/", categoryId.toString());
//if category object is needed and not just id then fetch it with Category c = addCategory(categoryId).
}
(PS。如果您注册了使用categoryService将Long转换为Category的转换器,则还@PathVariable("categoryId") Category category
可以将Category对象映射到路径变量而不是UUID,如果您愿意的话,请参见7.5.5配置ConversionService)
(编辑:删除了以不同名称命名模型的建议,因为这将无济于事,并添加了示例)
就个人而言,如果我需要这种行为(在显示表单时需要在表单中显示一个对象,但在发布表单时不将其绑定到对象),则我不会使用ModelAttribute注释方法来填充模型。相反,我将在显示表单时手动填充模型。那是更多的代码(实际上,只有一行),但魔术性较小,更易于理解。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句