最近项目碰到了这样的需求,查阅了一些资料,使用了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列合并的单元格数据,得到的结果如下图所示:
由上图所示,样子有些崩溃,但数据还是正常显示,无数据覆盖的情况。
本示例的代码由于时间少,测试还不太完善,可能还有没有考虑到的情况,有问题的话,请留言讨论。
最后,本示例的完整代码里面还包含了模拟数据和测试类,在 百度网盘 中即可下载。