詳細實戰——Java靈活創建Excel文件

最近項目碰到了這樣的需求,查閱了一些資料,使用了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列合併的單元格數據,得到的結果如下圖所示:

由上圖所示,樣子有些崩潰,但數據還是正常顯示,無數據覆蓋的情況。

本示例的代碼由於時間少,測試還不太完善,可能還有沒有考慮到的情況,有問題的話,請留言討論。

最後,本示例的完整代碼裏面還包含了模擬數據和測試類,在 百度網盤 中即可下載。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章