详细实战——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列合并的单元格数据,得到的结果如下图所示:

由上图所示,样子有些崩溃,但数据还是正常显示,无数据覆盖的情况。

本示例的代码由于时间少,测试还不太完善,可能还有没有考虑到的情况,有问题的话,请留言讨论。

最后,本示例的完整代码里面还包含了模拟数据和测试类,在 百度网盘 中即可下载。

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