如何使用Spring将列表中的输入值绑定到bean属性

时间:2015-09-11 12:51:02

标签: java spring jsp spring-mvc

我需要将一个对象列表作为属性绑定。它是一个静态列表,它在Controller中创建并部分填充。它在视图中正确显示,但是在将表单发送到控制器时,未设置输入字段中的值。我做了一些研究,发现了几个类似的问题,但是所提出的解决方案都没有对我有用。

edit.jsp文件

<c:forEach items="${priceConfigurationForm.priceList}" var="price" varStatus="priceStatus">
                    <tr>
                        <td>
                            <spring:bind path="priceConfigurationForm.priceList[${priceStatus.index}].country">
                                ${price.country}
                                <input type="hidden" name="<c:out value="${status.expression}"/>"
                                       id="<c:out value="${status.expression}"/>"
                                       value="<c:out value="${status.value}"/>"/>
                            </spring:bind>
                        </td>

                        <td>
                            <spring:bind path="priceConfigurationForm.priceList[${priceStatus.index}].amount">
                                <input type="text" name="price" value="${price.amount}"/>
                                <input type="hidden"
                                       name="<c:out value="${status.expression}"/>"
                                       id="<c:out value="${status.expression}"/>"
                                       value="<c:out value="${status.value}"/>"/>
                            </spring:bind>
                        </td>

                        <td>
                            <spring:bind path="priceConfigurationForm.priceList[${priceStatus.index}].currency">
                                ${price.currency}
                                <input type="hidden" name="<c:out value="${status.expression}"/>"
                                       id="<c:out value="${status.expression}"/>"
                                       value="<c:out value="${status.value}"/>"/>
                            </spring:bind>
                        </td>
                    </tr>
                </c:forEach>

摘要来自Controller填充列表:

@RequestMapping(value = "/price/create", method = RequestMethod.GET)
    public String toCreatePriceConfiguratioView(Model model) {

        log.info("::createPriceConfiguration: {}");

        final PriceConfigurationForm priceConfigurationForm = new PriceConfigurationForm();

        final List<PriceConfigurationForm.Price> prices = new ArrayList<>();
        for (Country country : Country.values()) {
            PriceConfigurationForm.Price price = new PriceConfigurationForm.Price();
            price.setAmount(100);
            price.setCountry(country.getCountryCode());
            price.setCurrency(country.getCurrency());
            prices.add(price);
        }

        priceConfigurationForm.setPriceList(prices);

        model.addAttribute("priceConfigurationForm", priceConfigurationForm);

        return "/secured/sources/onboarding/price/edit";
    }

来自Controller的摘要用于存储列表:

@RequestMapping(value = "/price/create", method = RequestMethod.POST)
    public String createPriceConfiguration(Model model, @ModelAttribute("priceConfigurationForm") @Valid PriceConfigurationForm priceConfigurationForm, BindingResult bindingResult, RedirectAttributes attributes) {

        log.info("::createPriceConfiguration {}", priceConfigurationForm);
        // TODO: Validate, before create

        /* transform form to domain object */
        PriceConfiguration configuration = PriceConfigurationForm.toPriceConfiguration(priceConfigurationForm);
        onboardingApi.createPriceConfiguration(configuration);

        attributes.addFlashAttribute("message", success("price configuration saved", priceConfigurationForm.getName()));
        return "/secured/sources/onboarding/price/index";
    }

对象:

@Data
public class PriceConfigurationForm {

    private String name;

    private String description;

    private List<Price> priceList;

    private Map<String, Long> countryToPriceMap;

    public static PriceConfiguration toPriceConfiguration(PriceConfigurationForm form) {
        final PriceConfiguration pc = new PriceConfiguration();
        pc.setName(form.getName());
        pc.setDescription(form.getDescription());
        final Map<String, Long> prices = form.getPriceList().stream().collect(toMap(Price::getCountry, Price::getAmount));
        pc.setCountryToPriceMap(prices);
        return pc;
    }

    @Data
    public static class Price {
        private String country;
        private long amount;
        private String currency;
    }
}

1 个答案:

答案 0 :(得分:0)

这是我在一个项目中成功解析嵌套对象的示例:

<c:forEach var="block" items="${newplaceform.blocks}" varStatus="counter">
        <fieldset data-block-order="${counter.index}" data-block-index="${counter.index}">
<c:if test='${block.type=="quizSingleAnswer"}'>
            <legend><s:message code='blocks.type.quizSingleAnswer'/> <a class="glyphicon glyphicon-move move-block pull-right" href="#"></a><a data-remove="block" class="glyphicon glyphicon-remove pull-right" href="#"></a><a data-reordering="up" class="glyphicon glyphicon-chevron-up pull-right" href="#"></a><a data-reordering="down" class="glyphicon glyphicon-chevron-down pull-right" href="#"></a></legend>
            <div class="form-group production-hide">
                <label class="col-sm-3 control-label">id:</label>
                <div class="col-sm-9"><input type="text" name="blocks[${counter.index}].id" value="${block.id}" data-row="blockId" data-disabled class="form-control"/></div>
            </div>
            <div class="form-group production-hide">
                <label class="col-sm-3 control-label">type:</label>
                <div class="col-sm-9"><input type="text" name="blocks[${counter.index}].type" value="${block.type}" data-disabled class="form-control"/></div>
            </div>
            <div class="form-group">
                <label class="col-sm-3 control-label"><s:message code='blocks.description'/>:</label>
                <div class="col-sm-9"><textarea class="form-control" name="blocks[${counter.index}].description" data-description rows="3">${block.description}</textarea></div>
            </div>
            <div class="row">
                <div class="col-sm-6">
                    <div class="col-sm-6 control-label">
                        <label class="inner-header"><s:message code='blocks.answers'/>:</label>
                    </div>
                    <div class="col-sm-6">
                        <div class="btn-group m-t-9">
                            <a class="btn btn-primary btn-xs" href="#" data-add-answer data-add-answer-block-index="${counter.index}"><i class="glyphicon glyphicon-plus"></i> <s:message code="blocks.add-answer" /></a>
                        </div>
                    </div>
                </div>
            </div>
            <div class="row quiz-answers" data-count-answer="${block.answers.size()}">
                <c:forEach var="answer" items="${block.answers}" varStatus="counterInner">
                    <div class="col-sm-6">
                        <fieldset>
                            <legend>
                                <div class="bootstrap-center">
                                    <span><s:message code="blocks.answerNo"/> ${counterInner.index+1}</span>
                                    <a data-remove="answer" class="glyphicon glyphicon-remove pull-right" href="#"></a>
                                </div>
                            </legend>
                            <div class="form-group production-hide">
                                <label class="col-sm-6 control-label">id:</label>
                                <div class="col-sm-6"><input type="text" name="blocks[${counter.index}].answers[${counterInner.index}].id" value="${answer.id}" data-row="answerId" data-disabled class="form-control"/></div>
                            </div>
                            <div class="form-group">
                                <label class="col-sm-6 control-label"><s:message code="blocks.answer"/>:</label>
                                <div class="col-sm-6"><input type="text" name="blocks[${counter.index}].answers[${counterInner.index}].text" value="${answer.text}" class="form-control"/></div>
                            </div>
                            <div class="form-group">
                                <div class="col-sm-6 col-sm-offset-6">
                                    <div class="checkbox">
                                        <label>
                                            <input type="checkbox" name="blocks[${counter.index}].answers[${counterInner.index}].right" value="true" ${answer.checked()}/>
                                            <s:message code="blocks.right"/>
                                        </label>
                                    </div>
                                </div>
                            </div>
                        </fieldset>
                    </div>
                </c:forEach>
            </div>