如何编写具有可变数量的表单字段和文件的Spring MVC控制器方法?

时间:2014-09-12 13:33:57

标签: java spring spring-mvc

我正在开发一个Spring MVC 3.1应用程序(使用控制器注释),我遇到了一个问题,我不确定如何解决。我有一个页面,根据数据,为用户构建一个表单以进行POST。表单可以包含可变数量的字段和任意数量的文件。我还没有找到一个如何编写控制器方法来处理这个问题的例子。

我见过的大多数示例都使用静态表单,因此开发人员可以编写一个对象来绑定表单数据。然而,在我的情况下,由于表格长度不同,我不会真的有这个选择(我认为)。

使用Spring可以实现这一点吗?

2 个答案:

答案 0 :(得分:1)

以下是旧项目的示例。

  1. 表格。注意form:form标签上的modelAttribute属性。这就是告诉Spring将支持对象绑定到表单,反之亦然。为了简洁,我删除了很多字段。只剩下地区(多值)和价格。

    <form:form method="post" modelAttribute="bindableCourse" id="courseForm">
    
    <%-- regions --%>
    <div class="default-block">
        <form:label path="regions">
            Regions
        </form:label>
        <c:forEach items="${allRegions}" var="region">
            <span class="inlineCheckBox"><form:checkbox path="regions" value="${region.id}" label="${region.name}"/></span>
        </c:forEach>
        <div><br><a href="#" id="selectAllRegions"><spring:message code="course.form.regions.selectall.linktext"/></a><br><br></div>
        <form:errors path="regions" cssClass="form-error"/>
    </div>
    
    <%-- price (formatted) --%>
    <div class="default-block">
        Price</form:label>
        <form:input path="formattedPrice" cssErrorClass="form-input-error" size="10"/>
        <spring:message code="course.form.currencysymbol"/> <spring:message code="course.form.price.perperson"/>
        <form:errors path="formattedPrice" cssClass="form-error"/>
    </div>
    
    
    </form:form>
    
  2. Controller具有此表单的GET和POST方法。在GET方法中,我们将bindableCourse添加到模型中。注意名称&#34; bindableCourse&#34;对应于JSP表单中的modelAttribute属性。在POST方法中,我们捕获用户为此BindableCourse提交的内容。

    @Controller
    public class CourseController {
    
    
    // This is called when accessing the form for the first time
    @RequestMapping(value = "/admin/course/add", method = RequestMethod.GET)
    public String newCourse(Model model, Locale locale) {
    
        BindableCourse bindableCourse = new BindableCourse();
        model.addAttribute("bindableCourse", bindableCourse);
        model.addAttribute("mainContent", "forms/editCourse");
        addDataToModel(model, locale, companyService.getCurrentlyLoggedInCompany());
    
        return "adminMain";
    }
    
    // This is called when submitting the form. 
    // Note that Spring created a BindableCourse for us, 
    // filled with the user entered values. This is Spring binding in action.
    // Happens behind the scenes.
    @RequestMapping(value = "/admin/course/add", method = RequestMethod.POST)
    public String addCourse(@ModelAttribute("bindableCourse") BindableCourse bindableCourse, BindingResult result,
                            RedirectAttributes redirectAttributes, Model model, Locale locale) {
    
        validator.validate(bindableCourse, result);
    
        if (!result.hasErrors()) {
            Course course = courseService.save(bindableCourse);
            bindableCourse.setPublishable(true);
            redirectAttributes.addFlashAttribute("valid", "true");
            return "redirect:/admin/course/" + course.getId();
        }
    
        addDataToModel(model, locale, companyService.getCurrentlyLoggedInCompany());
        model.addAttribute("valid", "false");
        model.addAttribute("mainContent", "forms/editCourse");
        return "adminMain";
    }
    

    }

  3. 最后是表单对象&#34; BindableCourse&#34;。这只是一个简单的Java对象,可以在表单之间传输数据。

    public class BindableCourse {
    
    private Long id;
    private String name;
    private String shortDescription;
    private String longDescription;
    private String certificateText;
    private String duration;
    // A multivalued property. The user can select multiple regions with multiple checkboxes
    // But you can also use multiple fields with the same name like address[0], address[1], etc
    private List<Long> regions = new ArrayList<Long>();
    private long category;
    private List<String> tags = new ArrayList<String>();
    private String formattedPrice;
    private boolean certificate;
    private String certificateName;
    private List<Long> times = new ArrayList<Long>();
    private List<String> dates = new ArrayList<String>();
    private List<Long> options = new ArrayList<Long>();
    private Calendar firstPublished;
    private boolean published;
    private boolean publishable;
    private String linkToSite;
    
    // getters and setters ommitted
    
    
    }
    
  4. 在我使用的JSP表单中,您可以看到后端提供了多值区域。我正在迭代一个&#34; allRegions&#34;采集。这些在控制器中添加到addDataToModel()方法中的模型中(此处未显示)。在您的场景中,您将使用Javascript在前端向表单添加新字段,但想法是一样的。

答案 1 :(得分:0)

使用包装器封装表单数据。

例如:

public class WrapperForm {

    private List<String> Fields;

    public List<String> getFields() {
        return Fields;
    }

    public void setFields(List<String> fields) {
        Fields = fields;
    }
}

然后你可以在其中放入x字段(通过控制器方法):

 @RequestMapping(method = RequestMethod.POST)
protected String processFinish(ModelMap model) {

    //process request -> need x fields in form


    WrapperForm formFields = new WrapperForm();
    formFields.setFields(new ArrayList<String>());
    for (int i = 0; i<x;i++){
        formFields.getFields().add("anyDefaultValue");
    }

    model.addAttribute("formFields", formFields);
    return "youJsp";
}

最后一步:你的jsp。

您只需要将核心JSTL库放入表单应答器中,例如:

<c:forEach items="${formFields.fields}" varStatus="i">
            <form:input path="fields[${i.index}]"/>
</c:forEach>