Fundamentally, the question boils down to, "How can one display and process dynamic forms?"
I spent hours on this problem- not just because I'm a nice guy- but because I realized that a similar use case is going to pop up on me soon. I have a Struts/Spring application that uses a service to describe questions that the user must be asked (and a question has multiple fields). There are literally thousands of questions a user might be asked and there is certainly not one Action and JSP for each question; rather there is one generic Action and one generic JSP that basically form a framework for handling any question. I need to rewrite this using Spring MVC/Spring, so it's too my benefit to really nail this down (and help out my fellow Spring user in the process
).
So, here's the example I cooked up. It's pretty dumb, but I think you could quite easily adapt it to what you're doing. Note that I used Spring 2.0 and the spring:bind tag has fallen out of favor. I opted for form:input instead. If you need to use Spring 1.2.x, you can adapt the example to use spring:bind quite easily.
Also, I do not want to give the impression that this is the "correct" way of doing this, but I had as much trouble as you finding a good example of this sort of thing and I feel the final result is very clean and therefore quite acceptable.
Here goes...
First the domain object (which is reused as a command object):
Code:
public class Example {
private Map myMap = new HashMap();
public Map getMyMap() {
return myMap;
}
public void setMyMap(Map myMap) {
this.myMap = myMap;
}
}
Now the controller:
Code:
public class ExampleController extends AbstractFormController {
protected ModelAndView showForm(HttpServletRequest request, HttpServletResponse response, BindException bindException) throws Exception {
ModelAndView mav = new ModelAndView();
// In real life, you'd build this data with a service of some sort
Map myMap = new HashMap();
myMap.put("Captain", "Kirk");
myMap.put("Science Officer", "Spock");
myMap.put("Doctor", "McCoy");
Example example = new Example();
example.setMyMap(myMap);
mav.addObject("example", example);
mav.setViewName("example");
return mav;
}
protected ModelAndView processFormSubmission(HttpServletRequest request, HttpServletResponse response, Object command, BindException bindException) throws Exception {
ModelAndView mav = new ModelAndView();
mav.addObject("example", command);
// Note: I'm lazy, so we're just going to go back to the same view
mav.setViewName("example");
return mav;
}
}
And finally the JSP. Some things to look out for in here: the iteration over the items in the Map is more or less disjoint from what goes on with the form binding tags. I do it pretty much just to get row replication and to get the keys for each element of the map because they're important for constructing the paths (and providing labels).
Code:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<form:form method="POST" commandName="example">
<table>
<c:forEach items="${example.myMap}" var="myItem">
<tr>
<td><form:label path="myMap['${myItem.key}']">${myItem.key}</form:label></td>
<td><form:input path="myMap['${myItem.key}']"/></td>
</tr>
</c:forEach>
<tr>
<td>
<input type="submit"/>
</td>
</tr>
</table>
</form:form>
I hope this helps you a bit. If any of this isn't clear or it doesn't work for some reason, feel free to post a follow-up. As I stated, I have significant interest in this use case.
Cheers.