引入依赖
<!-- excel导入导出 -->
<dependency>
<groupId>com.github.stupdit1t</groupId>
<artifactId>poi-excel</artifactId>
<version>3.0.6</version>
</dependency>
需求分析
我们是要求生成一个行列都是动态的excel,启动设计到行列的统计,关于这种复杂的excel 导出发现网上信息还是偏少,于是自己总结了一下,并参考了一些开源的工具类。
效果
满足基本功能,实现效果ok,数据量为5w加
核心功能讲解
首先组装数据,后台返回个list对象回来
List<Map<String, Object>> data = Lists.newArrayList();
定义动态表头也就是excel 表头
List<String> shopName = Lists.newArrayList();
shopName.add("核算仓位");
shopName.add("产品明细");
shopName.add("规格型号");
shopName.add("计量单位");
for (int i = 0; i < 500; i++) {
shopName.add("佐籽" + i);
}
shopName.add("合计袋");
shopName.add("合计个");
//excel表头标题数据 split为标题
String collect = shopName.stream().collect(Collectors.joining(","));
String[] split = collect.split(",");
组装动态行,列数据 以及动态列统计 统计动态行
//组织行数据 行列都可以是冬动态的 用map存放数据 key为fields具体的key对应
Map<String,Object> map = Maps.newHashMap();
//组装列统计数据 map(key,value) value 为列统计值
Map<String,Object> map501 = Maps.newHashMap();
//组装数据
for (int j = 0; j < 500; j++) {
map.put("zuozi" + j,j);
int c = 0;
for (int i = 0; i < 50; i++) {
c += j;
}
map501.put("zuozi" + j,c);
}
//组装行列数据,追加一行为统计列数据 采用最近比较简单不需要计算坐标
for (int i = 0; i < 51; i++) {
//最后一行是统计值
if(i == 50){
Map<String, Object> foodMap = new HashMap<>();
map501.entrySet().forEach(k ->{
foodMap.put(k.getKey(),"统计1"+k);
});
foodMap.put("rowStatistics", 1 + i);
foodMap.put("rowsMultipliedBySize", 1 + i);
data.add(foodMap);
}
//这是每一行对应列的value值
else {
Student student = new Student();
Map<String, Object> foodMap = new HashMap<>();
student.setUnit(10+ i);
student.setAccountingPosition("核算仓位"+ i);
student.setName("包子"+i);
student.setSkuName("规格" + i);
foodMap.put("accountingPosition", student.getAccountingPosition());
foodMap.put("name", student.getName() );
foodMap.put("skuName", student.getSkuName() );
foodMap.put("unit", student.getUnit() + i);
//遍历组装动态列的数据
map.entrySet().forEach(k ->{
foodMap.put(k.getKey(),k.getKey());
});
foodMap.put("rowStatistics", 1 + i);
foodMap.put("rowsMultipliedBySize", 1 + i);
data.add(foodMap);
}
}
组装fields 的key 也就是excel 表头对应的key
//组装fields 的key
List<String> cloumn = Lists.newArrayList();
cloumn.add("accountingPosition");
cloumn.add("name");
cloumn.add("skuName");
cloumn.add("unit");
for (int i = 0; i < 500; i++) {
cloumn.add("zuozi" + i);
}
cloumn.add("rowStatistics");
cloumn.add("rowsMultipliedBySize");
String collect1 = cloumn.stream().collect(Collectors.joining(","));
//这就是对应的fields 姓名:username
String[] split1 = collect1.split(",");
导出公共方法
// 2.执行导出
ExcelHelper.opsExport(PoiWorkbookType.BIG_XLSX)
.opsSheet(data)
.autoNum()
.opsHeader().simple()
// 大标题声明
.title("*****管理有限公司\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n")
//excel表头 split为可变参数 需要把excel表头安装顺序变成可变参数生成excel表头
.texts( split )
.done()
.opsColumn()
//表头对应的key 比如:表头为姓名 key为userName 需要根据key去填充数据
.fields( split1 )
.done()
//尾部 excel最后生成的数据
.opsFooter()
//尾行标题 text 为名字 location为需要合并的列坐标
.text("合计:", "1,1,A,E")
/*.text("=SUM(A1:A50)", "A1:A50")*/
.done()
.done()
.export("D:/mapExport.xlsx");
编写测试类,完整例子
@Test
public void complexData() {
// 1.获取列表数据 .texts("核算仓位", "产品明细","规格型号","计量单位",shopName,"合计袋","合计个").done()
List<Map<String, Object>> data = Lists.newArrayList();
//自定义list数据
List<String> shopName = Lists.newArrayList();
shopName.add("核算仓位");
shopName.add("产品明细");
shopName.add("规格型号");
shopName.add("计量单位");
for (int i = 0; i < 500; i++) {
shopName.add("佐籽" + i);
}
shopName.add("合计袋");
shopName.add("合计个");
//excel表头标题数据 split为标题
String collect = shopName.stream().collect(Collectors.joining(","));
String[] split = collect.split(",");
//组织行数据 行列都可以是冬动态的 用map存放数据 key为fields具体的key对应
Map<String,Object> map = Maps.newHashMap();
//组装列统计数据 map(key,value) value 为列统计值
Map<String,Object> map501 = Maps.newHashMap();
//组装数据
for (int j = 0; j < 500; j++) {
map.put("zuozi" + j,j);
int c = 0;
for (int i = 0; i < 50; i++) {
c += j;
}
map501.put("zuozi" + j,c);
}
//组装行列数据,追加一行为统计列数据 采用最近比较简单不需要计算坐标
for (int i = 0; i < 51; i++) {
//最后一行是统计值
if(i == 50){
Map<String, Object> foodMap = new HashMap<>();
map501.entrySet().forEach(k ->{
foodMap.put(k.getKey(),"统计1"+k);
});
foodMap.put("rowStatistics", 1 + i);
foodMap.put("rowsMultipliedBySize", 1 + i);
data.add(foodMap);
}
//这是每一行对应列的value值
else {
Student student = new Student();
Map<String, Object> foodMap = new HashMap<>();
student.setUnit(10+ i);
student.setAccountingPosition("核算仓位"+ i);
student.setName("包子"+i);
student.setSkuName("规格" + i);
foodMap.put("accountingPosition", student.getAccountingPosition());
foodMap.put("name", student.getName() );
foodMap.put("skuName", student.getSkuName() );
foodMap.put("unit", student.getUnit() + i);
//遍历组装动态列的数据
map.entrySet().forEach(k ->{
foodMap.put(k.getKey(),k.getKey());
});
foodMap.put("rowStatistics", 1 + i);
foodMap.put("rowsMultipliedBySize", 1 + i);
data.add(foodMap);
}
}
StringUtils.collectionToDelimitedString(shopName,",");
//组装fields 的key
List<String> cloumn = Lists.newArrayList();
cloumn.add("accountingPosition");
cloumn.add("name");
cloumn.add("skuName");
cloumn.add("unit");
for (int i = 0; i < 500; i++) {
cloumn.add("zuozi" + i);
}
cloumn.add("rowStatistics");
cloumn.add("rowsMultipliedBySize");
String collect1 = cloumn.stream().collect(Collectors.joining(","));
//这就是对应的fields 姓名:username
String[] split1 = collect1.split(",");
// 2.执行导出
ExcelHelper.opsExport(PoiWorkbookType.BIG_XLSX)
.opsSheet(data)
.autoNum()
.opsHeader().simple()
// 大标题声明
.title("*****管理有限公司\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n")
//excel表头 split为可变参数 需要把excel表头安装顺序变成可变参数生成excel表头
.texts( split )
.done()
.opsColumn()
//表头对应的key 比如:表头为姓名 key为userName 需要根据key去填充数据
.fields( split1 )
.done()
//尾部 excel最后生成的数据
.opsFooter()
//尾行标题 text 为名字 location为需要合并的列坐标
.text("合计:", "1,1,A,E")
/*.text("=SUM(A1:A50)", "A1:A50")*/
.done()
.done()
.export("D:/mapExport.xlsx");
}