Spring MVC:表单处理操作中具有多个@ModelAttribute [英] Spring MVC: Having multiple @ModelAttribute in form handling action

查看:80
本文介绍了Spring MVC:表单处理操作中具有多个@ModelAttribute的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在两个实体-类别电子邮件(NtoM)之间建立了简单的关联.我正在尝试创建用于浏览和管理它们的Web界面.为了浏览类别并将电子邮件添加到该类别中,我使用包裹有 @RequestMapping 和类别ID(UUID)的控制器,因此所有控制器操作始终在使用path指定的类别的上下文中进行.

I have a simple association between two entities - Category and Email (NtoM). I'm trying to create web interface for browsing and managing them. To browse the category and to add e-mails into that category I use controller wrapped with @RequestMapping with category ID (UUID), so all controller actions are always taking place in context of category specified with path.

我使用 @ModelAttribute 预先为整个控制器范围加载上下文类别.

I use @ModelAttribute to pre-load context category for entire controller scope.

此方法非常适合列出和显示表单.但是,它在提交表单时失败-经过一些调试后,我发现表单数据会覆盖我的类别 @ModelAttribute 参数.

This approach worked well for listing and for displaying the forms. However it fails on form submission - after debugging a little, I found out that form data overrides my category @ModelAttribute parameter.

在我的代码中,在方法 save()中,类别并不是真正由 addCategory()方法加载的模型属性,而是填充了表单数据(也填充了 email 模型,这是正确的).

In my code, in method save() the category is not really the model attribute loaded with addCategory() method, but is populated with form data (email model is also populated, and that is correct).

我正在寻找一种解决方案,该解决方案将允许我仅将表单数据绑定到特定的 @ModelAttribute .

I'm looking for the solution that will allow me to bind form data only to specific @ModelAttribute.

我已经在Spring MVC文档中阅读了参数的顺序很重要,但是我根据示例对它们进行了排序,但仍然无法按预期工作.

I've read in Spring MVC documentation that order of arguments matters, but I ordered them accordingly to examples and still it doesn't work like expected.

这是我的控制人:

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

以防万一,这里也是表单代码:

Just in case here is also the form code:

<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,只是希望以某种方式将表单模型与先前生成的属性区分开.

Note: I don't want multiple @ModelAttributes to come from POST, just want to distinguish somehow form model from previously generated attribute(s).

推荐答案

我不确定我是否完全理解问题,但对我来说,似乎您希望在显示表单时模型中存在类别对象,但不要不想通过表单发布对其进行更改?

I'm not sure I understand the problem entirely, but to me, it seems you want category object present in the model when you display the form, but don't want it to be changed with form post?

当您在参数列表中指定@ModelAttribute("categories")时,您基本上告诉spring MVC使用参数名称"categories"将表单数据绑定到带注释的对象.

When you specify @ModelAttribute("categories") in argument list you basically tell spring MVC to bind form data to the annotated object using the parameter name "categories".

如果您不希望绑定对象,则将其从参数列表中删除.如果您需要处理程序方法中的原始对象,则可以通过调用addCategory并提供与@PathVariable映射的ID来手动获取它:

If you don't want the object to be bound just leave it out from the parameters list. If you need the original object in the handler method fetch it manually by calling addCategory and providing id mapped with @PathVariable:

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

(PS. If you register a converter that converts Long to Category using categoryService you can also put @PathVariable("categoryId") Category category to map Category object to path variable instead of UUID, if you'd like that take look at 7.5.5 Configuring a ConversionService)

(删除了以不同的方式命名模型的建议,因为这将无济于事,并添加了示例)

( removed suggestion to name model differently as that will not help as noted in comments, and added example)

就个人而言,如果我需要这种行为(在显示表单时需要在表单中存在一个对象,但在发布表单时不将其绑定到对象),我不会使用带注解的ModelAttribute方法来填充模型.相反,我将在显示表单时手动填充模型.这是更多的代码(嗯,实际上是一行),但魔术性较低,更易于理解.

Personally, if I needed this kind of behavior (an object that needs to be present in the form when displaying the form, but not bound to it when form is posted) I would not use ModelAttribute annotated method to populate the model. Instead, I'd populate the model manually when displaying the form. That is a bit more code (well, one line actually) but is less magical and easier to understand.

这篇关于Spring MVC:表单处理操作中具有多个@ModelAttribute的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆