文章目录
一、背景
近期开发的一个新功能需要导出和前端展示样式一致的统计表格,而前端使用的elementui的table组件,show-summary属性选择后可以自动计算。后端导出时其他单元格与返回前端展示时一致,但最后一行的合计行需要后端计算并填充。
二、实现
1、写法一
可以参考issue中填充模板形式,代码略。
2、写法二
由于表头和行数量是动态的,我是采取构造dataList和header的方式,未读取模板文件。部分逻辑为伪代码。
java
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.data.FormulaData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.google.common.collect.Lists;
import org.apache.poi.ss.usermodel.Workbook;
import java.util.List;
public class ExcelTest {
public void download() {
try {
ExcelWriter excelWriter = EasyExcel.write("需要生成的文件名.xlsx").inMemory(true).build();
WriteSheet mainSheet = EasyExcel.writerSheet(0, "需要写入的sheet名").head(buildHeadTitles("123")).build();
excelWriter.write(buildData("123"), mainSheet);
Workbook workbook = excelWriter.writeContext().writeWorkbookHolder().getWorkbook();
workbook.setForceFormulaRecalculation(true);
workbook.getCreationHelper().createFormulaEvaluator().evaluateAll();
excelWriter.finish();
// 传给前端的相关逻辑
} catch (Exception e) {
// 异常处理
}
}
private List<List<String>> buildHeadTitles(String targetId) {
// 构建动态表头,相邻两个同名表头会默认合并
// 这里的Lists是com.google.guava下的 com.google.common.collect.Lists
List<List<String>> headTitles = Lists.newArrayList();
// 第一列
headTitles.add(Lists.newArrayList("团队统计", "姓名", "姓名"));
headTitles.add(Lists.newArrayList("团队统计", "机构名称", "机构名称"));
// 查询并类似上面格式添加动态列
headTitles.add(Lists.newArrayList("团队统计", "分类1", "动态列1"));
return headTitles;
}
private List<List<Object>> buildData(String targetId) {
ListList<Object>> dataList = Lists.newArrayList();
// 循环塞数据行 =========== 循环开始
// 最后一行塞数据的其中一个单元格公式示例如下
// 在前面构造的公式字符串
List<Object> list = new ArrayList<>():
// 先塞其他数据
list.add("syz");
list.add("顶级机构");
list.add("1");
String formulaStr = "SUM(VALUE(D4),VALUE(E4),VALUE(F4))";
WriteCellData<String> formula = new WriteCellData<>();
FormulaData formulaData = new FormulaData();
formula.setFormulaData(formulaData);
formulaData.setFormulaValue(formulaStr);
list.add(formula);
dataList.add(list)
// ============= 循环结束
return dataList;
}
}
三、遇到的问题
- 需要注意的是只有3.0.0+版本,才包含WriteCellData类,以及对应的formulaData的内部类,workbook相关的计算属性才会被调用,否则不会生效。此前2.0.0+的版本,找了半天设置未生效原因,翻了下workbook设置源码和相关issue才发现。
- 计算序号与字母转换时可以善用hutool工具包的ExcelUtil,已提供了序号到字母的转换,从0开始,如0-A,1-B。。。26-AA。。。等等,便于公式计算行和列。
四、参考
https://easyexcel.opensource.alibaba.com/docs/current/quickstart/write