1

サーバーが入力済みチェックボックスのリストを認識しないのはなぜですか?

この質問は何度もここで聞かれているようですが、依頼者ごとに詳細が異なるため、毎回異なる回答が必要なようです。これが私の話です。

これらは私のデータベアリングクラスです。オファーには、filter 属性の Filter オブジェクトのリストが含まれています。

public class Offer implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="id")
    private Long id = null;

    @Column(name="title")
    private String title = null;
    [snip]

    @ManyToMany(fetch=FetchType.EAGER)
    @JoinTable(name = "offer_filter", 
        joinColumns = { @JoinColumn(name = "offer_id", nullable = false, updatable = false) }, 
        inverseJoinColumns = { @JoinColumn(name = "filter_id", nullable = false, updatable = false) })
    private List<Filter> filters;

    [snip]
}

public class Filter implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="id")
    private Long id;

    @NotBlank
    @Length(max=100)
    @Column(name="text")
    private String text;

    [snip]

    @Transient
    private boolean owned = false;

    [snip]
}

単純なコントローラーは、完全に入力されたオファー オブジェクトを含む offerEdit.jsp ページを送信します。オブジェクトには、フィルターのリストが含まれています。属性が所有されているため、3 つのフィルターのうち 1 つだけが事前にチェックされます。これは、フィルターのリストが宇宙全体であり、オファーが所有するものがサブセットである、私の最終的な計画をシミュレートします。

注釈に注意してください。オファーには Web ページに送信されるフィルター リストがありますが、それが戻ってくることはありません。

public class OfferController {
    [snip]

    @RequestMapping(value = "/edit", method = RequestMethod.GET)
    public String getEdit(@RequestParam("id") Long id, Model model, HttpSession session) {
        Offer offerAttribute = offerService.get(id);

        // At this point, offerAttribute.filters has three elements.
        // Mockup -- tells web page that only the middle one of the three Filters should be checked.
        List<Filter> filters = offer.getFilters();
        Filter filter = filters.get(1);
        filter.setOwned(true);

        model.addAttribute("offerAttribute", offerAttribute);

        return "offer/offerEdit";
    }

    @RequestMapping(value = "/edit", method = RequestMethod.POST)
    public String postEdit(@RequestParam("id") Long id, @Valid @ModelAttribute("offerAttribute") Offer offerAttribute, BindingResult result, HttpSession session, Model model) {

        // At this point, offerAttribute.filters is null.
        if(result.hasErrors()) {
            result.reject("offer.invalidFields");

            return "offer/offerEdit";
        }

        offerAttribute.setId(id);
        offerService.edit(offerAttribute);

        return "redirect:/offer/list";
    }

    [snip]
}

Web ページには、チェックボックス セクションにこれがあります。テーブルを使用したいので、form:checkboxes よりも form:checkbox を使用します。

[snip]
<form:form modelAttribute="offerAttribute" method="POST" action="${saveUrl}">
    <table>
        <tr>
            <td></td>
            <td><form:hidden path="id" /></td>
        </tr>

        <tr>
            <td><form:label path="title">Title:</form:label></td>
            <td><form:input path="title" size="80" /></td>
            <td><form:errors path="title" cssClass="error" /></td>
        </tr>

    [snip]
    </table>

    <table>
    </table>

    <table>
        <c:forEach items="${offerAttribute.filters}" var="filter">
            <tr>
                <td><form:checkbox 
                        path="filters" 
                        label="${filter.text}" 
                        value="${filter.id}" 
                        checked="${filter.owned ? 'true' : ''}" />
                </td>
            </tr>
        </c:forEach>
    </table>
    [snip]

表示された Web ページには 3 つのフィルター チェックボックスが表示され、真ん中のチェックボックスだけが入力されています。

ここに画像の説明を入力

返されたリストについては、サーバーが中央のチェックボックスのみを取得することを期待しています。これはまさに私が望むものです。

生成されたチェックボックスのソースは次のようになります。

<table style="border: 1px solid; width: 100%; text-align:left;">
        <tr>
            <td>
                <input id="filters1" name="filters" type="checkbox" value="1"/>
                <label for="filters1">Adults (18+) desired, please</label>
                <input type="hidden" name="_filters" value="on"/>
            </td>
        </tr>
        <tr>
            <td>
                <input id="filters2" name="filters" checked="true" type="checkbox" value="2"/>
                <label for="filters2">Quiet audiences, please</label>
                <input type="hidden" name="_filters" value="on"/>
            </td>
        </tr>
        <tr>
            <td>
                <input id="filters3" name="filters" type="checkbox" value="4"/>
                <label for="filters3">Filter Text First</label>
                <input type="hidden" name="_filters" value="on"/>
            </td>
        </tr>
</table>

私のチェックボックスが設定され、HTMLに含まれています。私の質問を言い換えると、

コントローラーの POST ハンドラーでチェックボックスの値が表示されないのはなぜですか?

回答ありがとうございます。

ジェローム。

4

2 に答える 2

0

多くの Web 調査とさまざまなデバッグ セッションを経て、問題なく使用できる構成にたどり着きました。

私のコントローラーでは、リストを含む「filterList」のモデル属性を提供します。「offerAttribute」は、リスト フィルターを含むオファー オブジェクトです。

ビューには次のシーケンスがあります。

<table>
    <c:forEach items="${filterList}" var="filter" varStatus="status">
        <tr>
            <td><input type="checkbox" name="filters[${status.index}].id" 
                 value="${filter.id}"  
                 ${filter.owned ? 'checked' : ''} /> ${filter.text}
            </td>
        </tr>
    </c:forEach>
</table>

POST が完了すると、ownerAttribute.filters リストは、チェックボックスを作成した元の filterList オブジェクトと同じ長さになります。チェックされたものには Filter.id 値が含まれています。チェックされていないものにはヌルが含まれています。(つまり、返されたフィルター リストは「まばら」です。) ユーザーがいくつかのチェックボックスをクリックした場合、返されたリストを解析して、選択されたものを見つける必要があります。

チェックオンされたフィルターの ID 値がわかったら、Hibernate を介してそれぞれをフェッチし、再構築した Offer オブジェクトに入れ、データベースに永続化します。

私は(現在)フォーム:チェックボックスを使用していないことに気付きました。しかし、それは機能し、私はここで時間が迫っています。おそらく、後でまた戻ってきて、form:checkbox で何ができるか見てみましょう。

于 2013-02-14T21:44:56.243 に答える