Populating collection from request via Spring?
I've got a page where a purchase can be entered, along with all of the foos bought. I've got three elements in a html document that are parsed into a comma-separated format.
function submitStuff()
{
//grab each cells value from dynamically built table based on user entries
//appending comma
document.form.ids.value=Ids;
document.form.price.value=prices;
document.form.qtys.value=qtys;
document.form.submit();
}
Once broken up,each id/price/qty should populate into an an object...
public class foo{
private int id;
private BigDecimal price;
private int qty;
//set&get;
}
which can belong as a collection to another object...
public class purchase{
private Date date;
private int buyId;
private List<foo> purchases;
//set&get;
}
I know I can j开发者_如何学编程ust grab the request parameters and build the foo objects one by one. I figured there is a better way to populate that list while the data binding is performed on the purchase object, since it populates all other properties correctly.
Apart from concatenating the thing into a single commaseparated parameter and splitting it in the server side (which is a pretty nasty approach to be honest), you could also just send multiple parameter values along the same parameter name. It would then be available as a String[]
array by HttpServletRequest#getParameterValues()
on the parameter name.
I don't do Spring, so here's a plain vanilla HTML/Servlet example to give the idea:
<table>
<tr>
<td>ID: 12<input type="hidden" name="id" value="12"></td>
<td>Qty: <input type="text" name="qty"></td>
<td>Price: $100.00<input type="hidden" name="price" value="100.00"></td>
</tr>
<tr>
<td>ID: 54<input type="hidden" name="id" value="54"></td>
<td>Qty: <input type="text" name="qty"></td>
<td>Price: $200.00<input type="hidden" name="price" value="200.00"></td>
</tr>
<tr>
<td>ID: 8<input type="hidden" name="id" value="8"></td>
<td>Qty: <input type="text" name="qty"></td>
<td>Price: $500.00<input type="hidden" name="price" value="500.00"></td>
</tr>
</table>
Servlet:
String[] ids = request.getParameterValues("id");
String[] qtys = request.getParameterValues("qty");
String[] prices = request.getParameterValues("price");
for (int i = 0; i < ids.length; i++) {
Long id = Long.parseLong(ids[i]);
Integer qty = Integer.parseInt(qtys[i]);
BigDecimal price = new BigDecimal(prices[i]);
// ...
}
I however highly question the need to send the price from client to server as well. I'd rather (re)calculate the price at the server side since the client has full control over the request parameters it sends and is thus able to change the parameter values outside the control of your form.
You need to create a List. Then create a purchase and make sure you use the setter method to set the foo list in the purchase before binding it to the form or adding it to the model map (depending on whether you are using simpleform or annotation controller).
You could use Spring's "native" binding mechanism.
Sample controller:
@Controller
public class OrderController {
@ModelAttribute("purchase")
public Purchase getPurchase(@RequestParam("purchase-id") int purchaseId) {
// create purchase object
}
@RequestMapping(...)
public void processPosting(@ModelAttribute("purchase") Purchase purchase) {
// process order
}
}
Sample HTML:
<spring:form commandName="purchase">
<table>
<c:forEach var="item" items="${purchase.items}" varStatus="status">
<spring:nestedPath path="purchase.items[${status.index}]">
<tr>
<td>ID: 8 <form:hidden path="id" />
<td>Quantity: 8 <form:text path="quantity" />
</tr>
</spring:nestedPath>
</c:forEach>
</table>
<input type="submit" />
</spring:form>
The method getPurchase()
will be called on every request and provides the default purchase which will then be populated with values from the request. This method accepts regular annotations like the demonstrated @RequestParam
which will help you create the right purchase object.
The purchase will be available as a request attribute with the name purchase
.
The form iterates over all purchease items and creates a nested path using index access to the list of purchased items, so make sure that the order of items is always the same!
The request parameters will then be named like purchase.items[0].quantity
for the first item and so on. Spring will bind these parameter names to the model attribute purchase
, property items
, index 0, property quantity
, just like a regular property path.
Hope this helps you with your task.
精彩评论