基于Java POI實(shí)現(xiàn)動(dòng)態(tài)列Excel導(dǎo)出的通用方法
一、核心功能特性
1. 動(dòng)態(tài)列處理
- 支持從前端接收?
?List<String>???類(lèi)型的列名集合(??cellList???),結(jié)合固定列數(shù)組(??strCloumnAry??)動(dòng)態(tài)拼接最終列集合 - 使用?
?LinkedHashMap??維護(hù)列順序,確保導(dǎo)出列與傳入順序一致
2. 多級(jí)表頭支持
- 通過(guò)?
?headerNum??參數(shù)控制表頭層級(jí)(1-3 級(jí)) - 表頭名稱(chēng)通過(guò)?
?||???分隔(如??"船舶信息||完船日期||噸位"??),自動(dòng)解析為多級(jí)結(jié)構(gòu)
3. 數(shù)據(jù)統(tǒng)計(jì)功能
- 自動(dòng)識(shí)別數(shù)值型列(?
?Number???類(lèi)型),生成??totalMap??存儲(chǔ)列求和結(jié)果 - 支持在導(dǎo)出數(shù)據(jù)末尾添加 "合計(jì)" 行,并合并單元格顯示
4. 樣式與布局優(yōu)化
- 統(tǒng)一設(shè)置單元格邊框、居中對(duì)齊、字體大小
- 自動(dòng)調(diào)整列寬適應(yīng)內(nèi)容
- 多級(jí)表頭行合并相同標(biāo)題單元格,提升可讀性
二、關(guān)鍵代碼解析
1. 列集合初始化
LinkedHashMap<String, Integer> allColumn = new LinkedHashMap<>();
// 先添加固定列
for (int i = 0; i < strCloumnAry.length; i++) {
allColumn.putIfAbsent(strCloumnAry[i], i);
}
// 再添加動(dòng)態(tài)列(避免重復(fù))
int i = strCloumnAry.length;
for (String key : cellList) {
if (!allColumn.containsKey(key)) {
allColumn.put(key, i++);
}
}
- 使用?
?LinkedHashMap??保持順序,固定列在前,動(dòng)態(tài)列在后 - 通過(guò)?
?putIfAbsent??避免重復(fù)列名導(dǎo)致的索引沖突
2. 多級(jí)表頭生成
if (headerNum == 2) { // 二級(jí)表頭處理
for (String key : allColumn.keySet()) {
String[] parts = key.split("\|\|"); // 按||拆分
if (parts.length == 2) {
// 一級(jí)表頭行
Cell cell1 = headerRow1.createCell(allColumn.get(key));
cell1.setCellValue(parts[0]);
// 二級(jí)表頭行
Cell cell2 = headerRow2.createCell(allColumn.get(key));
cell2.setCellValue(parts[1]);
}
}
}
- 通過(guò)?
?split("\|\|")??解析多級(jí)表頭名稱(chēng) - 根據(jù)?
?headerNum??創(chuàng)建對(duì)應(yīng)行數(shù)的表頭行(1-3 級(jí)) - 同一列的多級(jí)表頭單元格共享相同列索引
3. 數(shù)據(jù)行與合計(jì)行
// 寫(xiě)入數(shù)據(jù)行
int row = headerNum; // 表頭行下方開(kāi)始寫(xiě)數(shù)據(jù)
for (Map<String, Object> data : datas) {
Row dataRow = sheet.createRow(row++);
for (Map.Entry<String, Integer> entry : allColumn.entrySet()) {
Cell cell = dataRow.createCell(entry.getValue());
cell.setCellValue(data.get(entry.getKey()) != null ? data.get(entry.getKey()).toString() : "");
}
}
// 寫(xiě)入合計(jì)行
Row totalRow = sheet.createRow(row);
totalRow.createCell(0).setCellValue("合計(jì)");
for (Map.Entry<String, Object> entry : totalMap.entrySet()) {
int colIndex = allColumn.get(entry.getKey());
Cell cell = totalRow.createCell(colIndex);
cell.setCellValue(entry.getValue() != null ? entry.getValue().toString() : "");
}
// 合并合計(jì)行標(biāo)題單元格
sheet.addMergedRegion(new CellRangeAddress(row, row, 0, maxSp));
- ?
?totalMap??通過(guò)遍歷數(shù)據(jù)行自動(dòng)計(jì)算數(shù)值列總和 - 合計(jì)行標(biāo)題 "合計(jì)" 通過(guò)?
?CellRangeAddress??合并多個(gè)列單元格 - ?
?maxSp??變量動(dòng)態(tài)計(jì)算需要合并的列范圍
4. 單元格樣式設(shè)置
// 創(chuàng)建通用樣式 CellStyle cellStyle = workbook.createCellStyle(); cellStyle.setAlignment(HorizontalAlignment.CENTER); cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); cellStyle.setBorderTop(BorderStyle.THIN); cellStyle.setBorderBottom(BorderStyle.THIN); cellStyle.setBorderLeft(BorderStyle.THIN); cellStyle.setBorderRight(BorderStyle.THIN); // 表頭字體設(shè)置 Font headerFont = workbook.createFont(); headerFont.setFontHeightInPoints((short) 10); cellStyle.setFont(headerFont);
- 統(tǒng)一設(shè)置水平 / 垂直居中對(duì)齊
- 添加細(xì)邊框樣式
- 表頭使用 10 號(hào)字體
三、使用示例
1. 方法參數(shù)說(shuō)明
| 參數(shù)名 | 類(lèi)型 | 說(shuō)明 |
|---|---|---|
| response | HttpServletResponse | Servlet 響應(yīng)對(duì)象,用于輸出文件流 |
| datas | List<Map<String,Object>> | 導(dǎo)出數(shù)據(jù)集合,每個(gè) Map 代表一行數(shù)據(jù) |
| cellList | List | 動(dòng)態(tài)列名集合(如前端勾選的列) |
| baseFileName | String | 基礎(chǔ)文件名(不含時(shí)間戳) |
| strAry | String[] | 固定列顯示名稱(chēng)數(shù)組(與 strCloumnAry 對(duì)應(yīng)) |
| strCloumnAry | String[] | 固定列字段名數(shù)組(如數(shù)據(jù)庫(kù)字段名) |
| headerNum | int | 表頭層級(jí)(1-3 級(jí)) |
2. 調(diào)用示例
// 假設(shè)前端傳入動(dòng)態(tài)列名為["price","quantity"]
List<String> cellList = Arrays.asList("price", "quantity");
// 固定列字段名與顯示名
String[] strCloumnAry = {"name", "date"};
String[] strAry = {"商品名稱(chēng)", "日期"};
// 構(gòu)造模擬數(shù)據(jù)
List<Map<String, Object>> datas = new ArrayList<>();
Map<String, Object> data1 = new HashMap<>();
data1.put("name", "蘋(píng)果");
data1.put("date", "2023-10-01");
data1.put("price", 5.99);
data1.put("quantity", 100);
datas.add(data1);
// 調(diào)用導(dǎo)出方法(二級(jí)表頭示例)
exportDynamicExcel(response, datas, cellList, "商品銷(xiāo)售報(bào)表", strAry, strCloumnAry, 2);
3. 表頭命名規(guī)范
多級(jí)表頭通過(guò)??||??分隔,如:
- 一級(jí)表頭:?
?"銷(xiāo)售額"?? - 二級(jí)表頭:?
?"季度數(shù)據(jù)||銷(xiāo)售額"?? - 三級(jí)表頭:?
?"年度匯總||季度數(shù)據(jù)||銷(xiāo)售額"??
四、優(yōu)化與擴(kuò)展建議
1. 類(lèi)型適配優(yōu)化
當(dāng)前代碼僅處理??Number??類(lèi)型數(shù)值求和,可擴(kuò)展支持:
- ?
?String??類(lèi)型數(shù)值轉(zhuǎn)換(需校驗(yàn)格式) - ?
?LocalDate???/??LocalDateTime??類(lèi)型日期格式化顯示
2. 樣式擴(kuò)展
- 添加條件格式(如數(shù)值超過(guò)閾值時(shí)標(biāo)紅)
- 支持不同背景色區(qū)分奇偶行
- 表頭行添加自動(dòng)篩選功能
3. 性能優(yōu)化
- 大數(shù)據(jù)量場(chǎng)景可改用?
?SXSSFWorkbook??(基于磁盤(pán)緩存的流式處理) - 合并單元格操作可批量處理,減少?
?sheet.addMergedRegion??調(diào)用次數(shù)
4. 錯(cuò)誤處理增強(qiáng)
- 添加參數(shù)校驗(yàn)(如?
?cellList???與??strCloumnAry??重復(fù)校驗(yàn)) - 提供更友好的異常提示信息(如字段名不存在)
五、總結(jié)
本文提供的動(dòng)態(tài)列 Excel 導(dǎo)出方法通過(guò)靈活的參數(shù)設(shè)計(jì),實(shí)現(xiàn)了:
- 動(dòng)態(tài)列與固定列的混合展示
- 1-3 級(jí)多級(jí)表頭的自動(dòng)解析
- 數(shù)值列自動(dòng)求和與合計(jì)行生成
- 統(tǒng)一的單元格樣式與布局優(yōu)化
適用于需要根據(jù)用戶(hù)選擇動(dòng)態(tài)展示列的管理系統(tǒng)(如數(shù)據(jù)報(bào)表、權(quán)限控制場(chǎng)景)。實(shí)際使用中可根據(jù)業(yè)務(wù)需求進(jìn)一步擴(kuò)展類(lèi)型適配、樣式定制等功能,提升導(dǎo)出文件的實(shí)用性與美觀性。
以上就是基于Java POI實(shí)現(xiàn)動(dòng)態(tài)列Excel導(dǎo)出的通用方法的詳細(xì)內(nèi)容,更多關(guān)于Java POI動(dòng)態(tài)列Excel導(dǎo)出的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java遠(yuǎn)程連接Linux執(zhí)行命令的3種方式完整代碼
在一些Java應(yīng)用程序中需要執(zhí)行一些Linux系統(tǒng)命令,例如服務(wù)器資源查看、文件操作等,這篇文章主要給大家介紹了關(guān)于java遠(yuǎn)程連接Linux執(zhí)行命令的3種方式,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-06-06
教您如何3分鐘快速搞定EasyExcel導(dǎo)入與導(dǎo)出功能
對(duì)于EasyExcel庫(kù),我們可以使用它來(lái)實(shí)現(xiàn)數(shù)據(jù)的導(dǎo)入和導(dǎo)出,下面這篇文章主要給大家介紹了關(guān)于如何3分鐘快速搞定EasyExcel導(dǎo)入與導(dǎo)出功能的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-01-01
Java向kettle8.0傳遞參數(shù)的方式總結(jié)
介紹了如何在Kettle中傳遞參數(shù)到轉(zhuǎn)換和作業(yè)中,包括設(shè)置全局properties、使用TransMeta和JobMeta的parameterValue,以及通過(guò)EL表達(dá)式獲取參數(shù)值2025-01-01
Java+swing實(shí)現(xiàn)抖音上的表白程序詳解
這篇文章主要為大家詳細(xì)介紹了如何利用Java?swing實(shí)現(xiàn)抖音上的表白程序,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-06-06
詳解SpringBoot下文件上傳與下載的實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot下文件上傳與下載的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05
解決SpringBoot項(xiàng)目中l(wèi)og4j與logback的Jar包沖突問(wèn)題
這篇文章主要給大家介紹了解決SpringBoot項(xiàng)目中l(wèi)og4j與logback的Jar包沖突問(wèn)題,文中有詳細(xì)的解決方法和沖突的原因,有遇到相同問(wèn)題的朋友可以參考閱讀本文2023-10-10

