# POI Excel 组样式设置

POI Excel 组样式设置

问题背景

在使用SXSSFWorkbook处理动态行数的Excel时,遇到设置行组(groupRow)不生效的问题。原因是行数超过SXSSFWorkbook的内存窗口大小,导致已写的行被写入磁盘,内存中找不到对应行。解决方法包括设置窗口参数为-1以保存所有行,或者先写入磁盘再用XSSFWorkbook读取并设置行组。对于超大量数据,如10w+行,建议采用后者避免内存压力。

实现原理

阅读SheetgroupRow方法发现可以用反射实现,设置行对应的层级可实现组的效果

  • 行层级控制:通过设置SXSSFRow._outlineLevel属性(行层级)实现分组折叠层级

  • 大纲级别设置:使用SXSSFSheet.setWorksheetOutlineLevelRowIfNecessary设置工作表最大分组层级

  • 内存优化:采用SXSSFWorkbook的流式处理,通过ROW_ACCESS_WINDOW_SIZE控制内存行数

  • groupRow 方法源码如下

@Override
public void groupRow(int fromRow, int toRow) {
    int maxLevelRow = -1;
    for(SXSSFRow row : _rows.subMap(fromRow, toRow + 1).values()){
        final int level = row.getOutlineLevel() + 1;
        row.setOutlineLevel(level);
        maxLevelRow = Math.max(maxLevelRow, level);
    }

    setWorksheetOutlineLevelRowIfNecessary((short) Math.min(Short.MAX_VALUE, maxLevelRow));
}

实现步骤

// 步骤1:反射初始化(只执行一次)
final Field outlineField = SXSSFRow.class.getDeclaredField("_outlineLevel");
outlineField.setAccessible(true);
final Method setOutlineMethod = SXSSFSheet.class.getDeclaredMethod("setWorksheetOutlineLevelRowIfNecessary", short.class);
setOutlineMethod.setAccessible(true);

// 步骤2:逐行处理数据
for (T data : list) {
    // 步骤3:获取分组信息
    QueryExportCellDTO cellInfo = getCellInfo(data); // 从数据中提取分组信息
    
    // 步骤4:设置行层级
    if (cellInfo != null) {
        outlineField.setInt(row, cellInfo.getLevel()); // 设置_outlineLevel属性
        maxLevelRow = Math.max(maxLevelRow, cellInfo.getLevel());
    }
}

// 步骤5:设置工作表大纲级别
if (maxLevelRow > 0) {
    setOutlineMethod.invoke(sheet, (short) maxLevelRow);
}

核心参数说明

参数类型作用
_outlineLevelint控制行分组层级(0为最外层,数值越大层级越深)
setWorksheetOutlineMethod设置工作表支持的最大折叠层级(超过该层级的折叠按钮将不会显示)
QueryExportCellDTO自定义数据对象包含level(层级)、groupFlag(是否分组行)、childrenSize(子节点数)等分组信息

注意事项

  • 反射性能优化:反射对象outlineFieldsetOutlineMethod在方法外初始化避免重复开销
  • 层级范围:Excel支持0-7级分组折叠,建议层级不要超过4级
  • 内存控制:建议配合SXSSFWorkbook(int rowAccessWindowSize)构造函数限制内存行数
  • 异常处理:反射调用后应恢复字段访问权限(当前代码未展示,可添加finally块处理)

效果示意图

▾ 层级1 (点击折叠)
  ▸ 层级2
    ▸ 层级3
    ▸ 层级3
  ▸ 层级2
▾ 层级1

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值