處理「一對多」表單(如人員-家屬信息)的批量增刪改查是企業級應用高頻場景。本文提供完整棧方案:前端 JSP + jQuery 動態增減行、表單序列化為 JSON、後端 List<Entity> 自動綁定、Service 層邏輯刪除+版本號樂觀鎖,附 Oracle 適配代碼與 $(document).ready vs window.onload 避坑指南。
SGuid、版本字段。addNewRow() 動態拼接 HTML,索引 personFamilyInfoList[${index}] 確保後端 List 按序綁定。delInsuranceInfo() 僅前端移除行,真實刪除交由後端邏輯判斷。$.serializeArray() 一鍵序列化整個表單,AJAX 提交至 Action。public boolean addPersonFamilyInfo(List<PersonFamilyInfo> list) {
for (PersonFamilyInfo info : list) {
if (info == null) continue;
info.setSGuid(UUIDHexGenerator.getUUID());
info.setSUnitGuid("11111111");
info.setSPersonGuid("0000000");
info.setIsEnable(0); // 0-有效
info.setDOperateDate(new Date());
info.setDDentifySucessDate(new Date());
info.setDDentifyLostDate(null); // 失效時間為空
personFamilyInfoService.saveNeedPk(info);
}
return true;
}
oldList。oldList.get(i) vs newList.get(i),任一字段變更標記 changed=true。IsEnable=1(歷史),DDentifyLostDate=now,save()。IsEnable=0,DDentifySucessDate=now,DDentifyLostDate=null,merge()。if (changed) {
PersonFamilyInfo history = new PersonFamilyInfo();
BeanUtils.copyProperties(old, history);
history.setSGuid(UUIDHexGenerator.getUUID());
history.setIsEnable(1);
history.setDDentifyLostDate(new Date());
service.save(history); // 歸檔
newInfo.setIsEnable(0);
newInfo.setDDentifySucessDate(new Date());
newInfo.setDDentifyLostDate(null);
service.merge(newInfo); // 激活
}
// 推薦:DOM 就緒即執行,不阻塞圖片等資源
$(function(){ loadCheck(); }); // 等價 $(document).ready()
// 不推薦:需等所有資源加載完
window.onload = function(){ loadCheck(); }
方案已在千萬級用戶系統穩定運行,核心優勢:前後端索引一致性保證、邏輯刪除保留全歷史、版本字段防併發覆蓋、動態行操作零侵入式擴展。