7

コンテキスト

Category2 つのエンティティーとEmail(NtoM)の間に単純な関連付けがあります。それらを閲覧および管理するためのWebインターフェイスを作成しようとしています。カテゴリを参照し、そのカテゴリに電子メールを追加するには@RequestMapping、カテゴリ ID (UUID) でラップされたコントローラーを使用するため、すべてのコントローラー アクションは、パスで指定されたカテゴリのコンテキストで常に実行されます。

@ModelAttributeコントローラースコープ全体のコンテキストカテゴリをプリロードするために使用します。

問題

このアプローチは、リストとフォームの表示に適していました。ただし、フォームの送信では失敗します。少しデバッグした後、フォーム データがカテゴリ@ModelAttributeパラメータをオーバーライドすることがわかりました。

私のコードでは、メソッドsave()は実際にはメソッドでcategoryロードされたモデル属性ではありませんがaddCategory()、フォームデータが入力されています(emailモデルも入力されており、それは正しいです)。

フォーム データを特定の .xml にのみバインドできるようにするソリューションを探しています@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>

注:複数の が POST から取得されるのは望ましくありません@ModelAttribute。フォーム モデルと以前に生成された属性を何らかの形で区別したいだけです。

4

1 に答える 1

4

問題を完全に理解しているかどうかはわかりませんが、フォームを表示するときにモデルにカテゴリオブジェクトが存在するように見えますが、フォームポストで変更したくないですか?

引数リストで @ModelAttribute("categories") を指定すると、基本的に、パラメーター名 "categories" を使用してフォーム データを注釈付きオブジェクトにバインドするように Spring MVC に指示します。

オブジェクトをバインドしたくない場合は、パラメーター リストから除外してください。ハンドラー メソッドで元のオブジェクトが必要な場合は、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、UUIDの代わりにCategoryオブジェクトをパス変数にマップすることもできます。必要に応じて、7.5.5 ConversionServiceの構成を参照してください)

(編集:コメントに記載されているように役に立たないため、モデルに別の名前を付ける提案を削除し、例を追加しました)

個人的には、この種の動作 (フォームを表示するときにフォームに存在する必要があるが、フォームが投稿されたときにフォームにバインドされないオブジェクト) が必要な場合、ModelAttribute 注釈付きメソッドを使用してモデルを設定しません。代わりに、フォームを表示するときにモデルを手動で入力します。これはもう少しコードが長くなります (実際には 1 行です) が、魔法のようなものではなく、理解しやすいものです。

于 2013-10-08T10:29:22.883 に答える