java使用poi导出excel时,createCellStyle过多导致的异常

时间:2025-04-23 08:33:54

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,欢迎评论补充,大家共同进步。