1. 应用场景
项目上需要对某张数据量较大(其实也就4600多条数据,每行11列)的报表导出excel,然后发现抛出异常信息如下:
The maximum number of Cell Styles was exceeded. You can define up to 64000 style in a .xlsx Workbook
导致这个问题的直接原因,是因为在循环给sheet页的每个单元格设置样式时,使用了()
2. 解决方案
其实网上一搜一大把答案,基本都是说把createCellStyle()放到循环外面就行。所以我就照着做放到了循环外面,发现问题解决了!(真的解决了吗?其实只是伪解决)如果给某些个单元格设置一些不同的,比如背景色、字体啥的样式,那么新的问题又来了:所有的单元格样式,都会被最后设置的样式给覆盖,最后导出的excel所有单元格都是一样的了,呔!所以脑子转一转,想到了使用全局样式map保存所有不同的样式,设置样式时,先去map获取,有则使用,没有则创建后存放到map中,这样就能保证不过多的创建单元格样式了。具体看代码
2.1. 设置全局样式map
/** 全局样式map,避免【The maximum number of Cell Styles was exceeded. You can define up to 64000 style in a .xlsx Workbook】 */
private Map<String, XSSFCellStyle> styleMap = new HashMap<String, XSSFCellStyle>();
2.2. 获取与添加样式
XSSFCellStyle xssfCellStyle = null;
// 该属性为存放样式配置的json,请根据具体业务修改
JSONObject styleJsonObject = (JSONObject)(style);
// 是否需要保存到样式map中的标识
boolean flag = false;
// 判断全局样式集合
if (()) {
// 为空则创建
xssfCellStyle = ();
flag = true;
} else {
// 是否已包含现有样式
if ((())) {
xssfCellStyle = (());
} else {
// 获取不到则创建
xssfCellStyle = ();
flag = true;
}
}
// ......此处省略一万行设置样式的业务代码
// 这行代码修改前使用的是(xssfCellStyle),会引起其他异常,必须修改
().cloneStyleFrom(xssfCellStyle);
// 如果是创建的样式,则设置完后存放到样式map中
if (flag) {
((), xssfCellStyle);
flag = false;
}
--------------------------------------------------分割线(2022-04-19)-----------------------------------------------
().cloneStyleFrom(xssfCellStyle);
以上这行代码,只是为了解决样式与workbook不同源的问题。设置同源后,再使用以下代码设置单元格样式就行了
(xssfCellStyle);
--------------------------------------------------分割线(2022-05-12)-----------------------------------------------
多次测试发现以上代码存在一个bug:
因为为全局变量,如果同一个excel多次导出时,还是会提示非同源错误。
调整方案:
在设置样式之前,将重新实例化为空map
// 每次导出都初始化样式map,避免非同源错误
= new HashMap<String, XSSFCellStyle>();
在类中设置为全局变量时,可以直接=null,不做修改亦可。
至此,该方案为最终方案。如果看到的童鞋发现存在其他bug,欢迎评论补充,大家共同进步。