简体   繁体   中英

How can I write a Spring MVC controller method with variable number of form fields and files?

I am developing a Spring MVC 3.1 app (using controller annotations) and I've encountered an issue I'm not sure how to resolve. I have a page that, depending on data, builds a form for a user to POST back. The form can contain a variable number of fields, and any number of files. I haven't been able to find an example of how to write the controller method to handle this.

Most of the examples I've seen use static forms, so the developer can write an object to bind to the form data. In my case, however, since the form length varies, I don't really have that option (I think).

Is this even possible using Spring?

Here is an example from an old project.

  1. A form. Pay attention to the modelAttribute attribute on the form:form tag. This is what tells Spring to bind the backing object to the form and vice versa. I removed a lot of the fields for conciseness. Only regions (multivalued) and price are left.

     <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. The Controller has a GET and POST method for this form. In the GET method we add the bindableCourse to the model. Note that the name "bindableCourse" corresponds to the modelAttribute attribute in the JSP form. In the POST method we capture what the user submitted for this 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. And finally the form object "BindableCourse". This is just a simple Java object that transports data to and from the form.

     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 } 

In the JSP form that I use you can see that the multivalued regions are provided by the backend. I am iterating over a "allRegions" collection. These are added in the controller to the model in the addDataToModel() method (not shown here). In your scenario you will be adding new fields to your form in the frontend using Javascript, but the idea is the same.

Use a wrapper to encapsulate your forms data.

for example:

public class WrapperForm {

    private List<String> Fields;

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

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

then you can put x fields in it ( via the controller method):

 @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";
}

last step: your jsp.

you just need the core JSTL library to put inside your form balises, for example:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM