最近項目碰到了這樣的需求,查閱了一些資料,使用了POI,結合自己的需求整理了下,相關的全部代碼可在文章末尾處點擊 百度網盤 下載。
————————————————————————操作環境如下——————————————————————————
類別 | 名稱 | 簡介 |
編譯器軟件 | IDEA | Java編程語言開發的集成環境 |
Jar包管理 | maven | 可通過小段描述信息來管理項目的構建 |
想要達成的目標:
根據得到的數據,生成對應的Excel文件(也適用於前端傳數據,後端根據數據生成Excel文件)。
————————————————————————實際操作———————————————————————————
首先,說明下,本示例是按照順序,一行行執行寫入的,因此,先確定下數據格式。在這裏,本次對數據格式最終要求爲 List<List<Map>> ,數據中不區分表頭和表數據。
簡單解釋下,List<List<Map>>則爲全部數據的集合。List<Map>爲一行的數據,合併單元格的數據已首次的行數爲準。Map 中存儲單元格的相關信息,需要的屬性如下:
- text:單元格數據;
- row:所佔的行數值,一般爲1,大於1則視爲需要合併單元格;
- col:所佔的列數值,一般爲1,大於1則視爲需要合併單元格;
- cell:單元格寬度。
數據示例如下,數據實際列總數數爲5列:
[
[
{text="單位",row=2,col=1,cell=280},
{text="部門",row=1,col=3,cell=600},
{text="總財報",row=1,col=1,cell=200}
],
[
{text="銷售一部財報",row=1,col=1,cell=200},
{text="銷售二部財報",row=1,col=1,cell=200},
{text="銷售三部財報",row=1,col=1,cell=200},
{text="銷售部總財報",row=1,col=1,cell=200}
],
[
{text="長江分部",row=1,col=1,cell=280},
{text="150",row=1,col=1,cell=200},
{text="800",row=1,col=1,cell=200},
{text="50",row=1,col=1,cell=200},
{text="1000",row=1,col=1,cell=200}
]
]
pom.xml依賴文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.testExcel.demo</groupId>
<artifactId>testExcel</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--poi-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>RELEASE</version>
</dependency>
</dependencies>
</project>
核心的方法已封裝成工具類,如下所示:
package com.testExcel.util;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.util.CellRangeAddress;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 測試轉換Excel工具類
*/
public class ExcelUtils {
/**
* 創建並將數據寫入HSSFWorkbook對象
* @param execlName excel中表名
* @param data 數據List<List<Map>>
* @return
*/
public static HSSFWorkbook createExcel(String execlName,List<List<Map>> data){
//創建一個文件工作簿
HSSFWorkbook workbook = new HSSFWorkbook();
//創建一張表
HSSFSheet sheet = workbook.createSheet(execlName);
//創建一行
HSSFRow row = sheet.createRow(0);
//設置爲居中加粗
HSSFCellStyle style = workbook.createCellStyle();
HSSFFont font = workbook.createFont();
font.setBold(true);
style.setAlignment(HorizontalAlignment.CENTER);
style.setFont(font);
//創建填充對象
HSSFCell cell;
//記錄當前的行值和列值
int rowCode = 0;
int colCode = 0;
//記錄合併單元格的數據
List<Map> rowAndCol = new ArrayList<Map>();
//解析全部數據
for (List<Map> list : data) {
//解析每一行的數據
for (Map map : list) {
//判斷是否爲第一行除外的數據且有合併記錄
if(rowCode>0 && rowAndCol.size() != 0){
//解析合併記錄
for(Map<String,Integer> rac :rowAndCol){
//若行數值符合條件的情況下
if(rowCode >= rac.get("rowStart") && rowCode <= rac.get("rowEnd")){
//若列數值也符合情況下
if(colCode <= rac.get("colEnd") && colCode >= rac.get("colStart")){
//若合併的行數起始值和結束值相等或不等的情況
if(rac.get("colStart") == rac.get("colEnd")){
colCode++;
}else{
colCode = colCode+(rac.get("colEnd")-rac.get("colStart"))+1;
}
}
}
}
}
//獲取待解析數據中的行值和列值
int rowNum = Integer.parseInt(map.get("row").toString());
int colNum = Integer.parseInt(map.get("col").toString());
//判斷是否大於1,若大於1,則涉及到合併
if(rowNum >1 || colNum >1){
//合併單元格
sheet.addMergedRegion(new CellRangeAddress(rowCode, rowCode+(rowNum-1),colCode, colCode +(colNum-1)));
//記錄合併的信息
Map<String,Integer> tMap = new HashMap();
tMap.put("rowStart",rowCode);
tMap.put("colStart",colCode);
tMap.put("rowEnd",rowCode+rowNum-1);
tMap.put("colEnd",colCode+colNum-1);
rowAndCol.add(tMap);
}
//設置列寬
sheet.setColumnWidth(colCode,Integer.parseInt(map.get("cell").toString())/colNum/9*256);
//創建單元格對象
cell = row.createCell(colCode);
//寫入數據
cell.setCellValue(map.get("text").toString());
//設置單元格式
cell.setCellStyle(style);
//自增列值
if(colNum>1){
colCode = colCode+colNum;
}else{
colCode++;
}
}
//重置列值
colCode = 0;
//行值自增
rowCode++;
//創建新的行
row = sheet.createRow(rowCode);
}
return workbook;
}
/**
* 本地生成文件
* @param filename 文件路徑
* @param workbook excel對象
* @throws Exception
*/
public static void buildExcelFile(String filename,HSSFWorkbook workbook) throws Exception{
FileOutputStream fos = new FileOutputStream(filename);
workbook.write(fos);
fos.flush();
fos.close();
}
}
根據上述的數據示例及核心代碼,可以的到如下所示的execl表格:
代碼也能適應一些複雜的情況,比如更改上述數據示例數據,讓“部門”變爲2行3列合併的單元格數據,得到的結果如下圖所示:
由上圖所示,樣子有些崩潰,但數據還是正常顯示,無數據覆蓋的情況。
本示例的代碼由於時間少,測試還不太完善,可能還有沒有考慮到的情況,有問題的話,請留言討論。
最後,本示例的完整代碼裏面還包含了模擬數據和測試類,在 百度網盤 中即可下載。