背景
在使用easyexcel导出时,如果遇到一个模板中同时存在 一部分是实体类中的字段,另外部分是列表的字段,需要特殊处理一下,比如下面的模板:
这里面 user
, addr
是实体类(或者map),extra
是一个字符串,data
,data1
是两组列表数据。
准备数据的代码如下:
private static Map<String, Object> getParams() {
// 准备导出的数据
User user = new User();
user.setName("user");
Map<String, Object> addr = new HashMap<>();
addr.put("name", "addr");
String extra = "extra";
List<Data> dataList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Data data = new Data();
data.setName("data" + i);
data.setAge(i);
dataList.add(data);
}
Map<String, Object> params = HashMap.newHashMap(16);
params.put("user", user);
params.put("addr", addr);
params.put("extra", extra);
params.put("data", dataList);
params.put("data1", dataList);
return params;
}
问题
我们一开始的想法很简单,直接把这些参数打包丢到map里面,直接fill一次不就成功了,但是,实际上并没有成功,导出代码如下:
var params = getParams();
String templateFileName = "D:\\test.xlsx";
String fileName = "D:\\test-res.xlsx";
try (ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(templateFileName).build()) {
WriteSheet writeSheet = EasyExcel.writerSheet().build();
excelWriter.fill(params, writeSheet);
}
导出结果:
可以看到,除了没有前缀的的extra
,所有带前缀的都导出失败了,仔细查阅文档后,发现这些需要用FillWrapper包装一下,为了方便使用,这里写了一个工具类,代码如下:
public static void export(String templateFileName, String outputFile, Map<String, Object> params){
try (ExcelWriter excelWriter = EasyExcel.write(outputFile).withTemplate(templateFileName).build()) {
WriteSheet writeSheet = EasyExcel.writerSheet().build();
// 先把不带前缀的都fill进去
excelWriter.fill(params, writeSheet);
params.forEach((key, val) -> {
// 基础类型都是不带前缀的,前面处理了,不再处理。
if (ClassUtil.isBasicType(ClassUtil.getClass(val))) {
return;
}
if (val instanceof Collection<?> collectionVal) {
// 这里注意 入参用了forceNewRow 代表在写入list的时候不管list下面有没有空行 都会创建一行,然后下面的数据往后移动。默认 是false,会直接使用下一行,如果没有则创建。
// forceNewRow 如果设置了true,有个缺点 就是他会把所有的数据都放到内存了,所以慎用
// 简单的说 如果你的模板有list,且list不是最后一行,下面还有数据需要填充 就必须设置 forceNewRow=true 但是这个就会把所有数据放到内存 会很耗内存
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
excelWriter.fill(new FillWrapper(key, collectionVal), fillConfig, writeSheet);
}else {
// bean/map 只能假装是个列表了
excelWriter.fill(new FillWrapper(key, Collections.singleton(val)), writeSheet);
}
});
}
}
代码中的ClassUtil
是hutool
的
导出结果:
可以看到,几处都填充成功了。
补充
web环境下把导出方法的前俩参数直接改成对应的输出/输入流就行了。