本文記錄一次真實項目實踐:基於 Spring + Hibernate + Spring MVC + EasyUI + MySQL 技術棧,結合 zTree、POI 等組件,從框架分析到功能落地,完整呈現企業級後台管理系統核心模塊開發全過程。
接手項目前 3/4 時間投入於:
核心心法:做項目絕不能盲目開始,必須先掌握基礎理論,再在框架約束下編碼。
需求:城市 → 設備類型 → 設備型號 → 設備名 四級分類展示。
數據結構:平台提供 zTree 實體 Bean,屬性與插件一一對應 (id、pId、name、url、target 等)。
關鍵技術點:
@ResponseBody + List<ZTreeNode> 自動序列化target="_self" 或自定義 onClick 防止新窗口打開// 核心邏輯:一次查詢所有設備 -> 按城市分組 -> 遞歸構建子節點 ListallDevices = deviceService.findAll(); Map > cityMap = allDevices.stream().collect(Collectors.groupingBy(Device::getCity)); cityMap.forEach((city, devices) -> { ZTreeNode cityNode = new ZTreeNode(city, "0", city, true); // 遞歸構建類型、型號、設備節點... rootNodes.add(cityNode); });
前端:EasyUI Datagrid + Toolbar (搜索框、下拉、日期框) + Pagination。
關鍵難點:分頁時保持查詢條件。
解決方案:隱藏表單存儲查詢參數,查詢按鈕觸發:隱藏表單賦值 → 觸發 datagrid reload。分頁事件讀取隱藏表單參數發送後台。
// JS 關鍵邏輯
$("#searchBtn").click(function() {
// 1. 將搜索表單數據同步到隱藏表單
$("#hiddenForm").form("load", $("#searchForm").serializeObject());
// 2. 觸發分頁查詢 (第1頁)
$("#dg").datagrid("load", $("#hiddenForm").serializeObject());
});
// 分頁事件自動攜帶隱藏表單參數
$("#dg").datagrid({
onBeforeLoad: function(param) {
$.extend(param, $("#hiddenForm").serializeObject());
}
});
EasyUI 取值技巧:$("#id").combobox('getValue')、$("#id").datebox('getValue'),而非通用 .val()。
後端:Hibernate saveOrUpdate(entity) — ID 為 null 則 insert,非 null 則 update。JSP 取到空字符串 "" 需轉 null。
前端:同一彈窗,按鈕區分:
提交:AJAX 序列化表單提交,成功刷新列表、關閉彈窗。
上傳配置:CommonsMultipartResolver,maxUploadSize 限制。注意 URL 結尾斜槿。
POI 讀取流程:
Workbook (HSSFWorkbook .xls / XSSFWorkbook .xlsx / SXSSFWorkbook 大數據)Sheet → Row → Cell核心思路:構建 Workbook → 寫入 ByteArrayOutputStream → 設置響應頭 → 輸出 byte[]。
@RequestMapping("/export")
public void export(HttpServletResponse response) throws Exception {
// 1. 構建 Excel
SXSSFWorkbook wb = new SXSSFWorkbook(); // 大數據優化
Sheet sheet = wb.createSheet("設備數據");
// ... 寫入標題行、數據行 ...
// 2. 輸出
ByteArrayOutputStream baos = new ByteArrayOutputStream();
wb.write(baos);
byte[] content = baos.toByteArray();
// 3. 響應頭
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("設備數據.xlsx", "UTF-8"));
response.setContentLength(content.length);
// 4. 輸出流
response.getOutputStream().write(content);
response.getOutputStream().flush();
}
前端下載:window.open("export?params=" + encodeURIComponent(JSON.stringify(params))),中文參數雙端編解碼。
| 類 | 格式 | 後綴 | 適用場景 | 性能/內存 |
|---|---|---|---|---|
| HSSFWorkbook | BIFF8 | .xls | Excel 2003 兼容、小數據量 | 全內存、較慢 |
| XSSFWorkbook | OOXML | .xlsx | Excel 2007+、中等數據量 | 全內存、較慢 |
| SXSSFWorkbook | OOXML | .xlsx | 大數據量導出 (萬行+) | 滾動窗口寫磁盤、低內存、高性能 |
required、validType="remote['url','param']" (遠程驗證 ID 唯一)、動態啟用/禁用 (validatebox('remove'/'reduce'))@NotNull、@Size 等) + Controller 統一異常處理Eclipse Class Decompiler:反編譯 Class 文件查看源碼,排查 Jar 包版本衝突、方法簽名變更等疑難雜症利器。
saveOrUpdate 封裝持久化邏輯,Controller 薄而專注調度這個項目從框架分析到功能交付,完整踐行了「理論先行、約束中創新、工具賦能、分層解耦」的工程化開發哲學。