頁面需批量提交多個對象(如訂單明細行),傳統做法在 Action 聲明 String[] ids 接收主鍵數組,現希望直接接收 List<OrderItem> 對象集合。
public class Order {
private List items = new ArrayList<>(); // 必須初始化
// getter/setter
}
public class OrderItem {
private Long productId;
private Integer quantity;
private BigDecimal price;
// getter/setter
}
<c:forEach items="${order.items}" varStatus="vs">
<input name="items[${vs.index}].productId" value="${item.productId}" />
<input name="items[${vs.index}].quantity" value="${item.quantity}" />
<input name="items[${vs.index}].price" value="${item.price}" />
</c:forEach>
關鍵點:name="items[0].productId"、name="items[1].productId"… OGNL 會自動按索引實例化 OrderItem 並注入屬性。
public class OrderAction extends ActionSupport {
private Order order = new Order(); // 必須初始化
// getter/setter
public String save() {
// order.getItems() 已自動封裝好 List
orderService.save(order);
return SUCCESS;
}
}
let idx = ${fn:length(order.items)}; // 初始索引
$('#addRow').click(() => {
const html = `
<tr>
<td><input name="items[${idx}].productId" /></td>
<td><input name="items[${idx}].quantity" type="number" /></td>
<td><input name="items[${idx}].price" type="number" step="0.01" /></td>
</tr>`;
$('#itemTable tbody').append(html);
idx++;
});
| 現象 | 原因 | 解決 |
|---|---|---|
| List 為 null | 實體類未初始化集合 | private List<T> list = new ArrayList<>(); |
| 索引不連續導致漏數據 | 刪除行後索引斷層 | 提交前 JS 重排索引或用 items[${vs.index}] 由 JSTL 生成 |
| 類型轉換失敗 | 前端傳 "abc" 給 Integer | 配置 TypeConverter 或前端校驗 |
name 遵循 listName[index].property 規範Map<Integer, T> 兼容稀疏索引Struts2 強大的 OGNL 表達式引擎讓「對象集合自動封裝」變得極其簡單:實體類聲明 List + 頁面按索引命名,框架其餘自動完成。掌握此模式,徹底告別手動解析數組、逐個 set 的樣板代碼。