Spring MVC:POST时未返回给控制器的复选框列表

时间:2013-02-12 04:36:51

标签: spring spring-mvc checkbox controller

为什么服务器没有看到我填写的复选框列表?

这个问题似乎在这里被多次询问,但每个请求者的细节都是如此不同,以至于每次都需要一个不同的答案。这是我的故事。

这些是我的数据承载课程。 Offer包含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]
}

简单控制器使用完全填充的Offer对象发送offerEdit.jsp页面。该对象包含过滤器列表。由于拥有属性,因此只预先检查三个过滤器中的一个。这模拟了我的最终计划,其中过滤器列表是整个Universe,并且Offer拥有的是子集。

请注意,该商品会将过滤器列表发送到网页,但不会看到它回来。

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]
}

网页上有其复选框部分。我使用form:checkbox over form:checkboxes因为我想使用表格,

[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]

显示的网页显示三个过滤器复选框,只填写中间复选框。

enter image description here

对于返回的列表,我希望服务器只获得中间复选框,这正是我想要的。

以下是生成的复选框的来源:

<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处理程序中看不到复选框值?

感谢您的回答,

杰罗姆。

2 个答案:

答案 0 :(得分:0)

复选框的值无法直接绑定到List。

要实现这一点,您需要创建一个简单的pojo数据库,它将在jsp中保存表单字段的值。在该databean中绑定值,您需要声明int[] filterId,并且复选框的值将绑定在该数组中。

希望这会对你有所帮助。

答案 1 :(得分:0)

经过大量的网络研究和不同的调试会议,我想出了一个我可以忍受的配置。

在我的控制器中,我提供了一个包含List的“filterList”的模型属性。 “offerAttribute”是一个Offer对象,包含List过滤器。

视图具有以下顺序:

<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值。未经检查的包含null。 (也就是说,返回的过滤器列表是“稀疏的”。)如果用户只点击几个复选框,那么我必须解析返回的列表以找到所选的那些。

一旦我知道了已检查过滤器的ID值,我就通过Hibernate获取它们,将它们放入我重建的Offer对象中,然后将它们保存到数据库中。

我意识到我(目前)没有使用表单:复选框。但它有效,我在这里时间紧迫。我可能会稍后再回来看看是什么形式:复选框可以为我做。