alibaba / easyexcel

快速、简洁、解决大文件内存溢出的java处理Excel工具
https://easyexcel.opensource.alibaba.com
Apache License 2.0
31.96k stars 7.49k forks source link

excel模板导出,数据列表需要动态填充,动态填充的行数据需要合并单元格,测试发现动态填充7行没有问题,填充8行以上时就报错:Cannot add merged region C25:D25 to sheet because it overlaps with an existing merged region (B25:L25). #2587

Open MatthewWaung opened 2 years ago

MatthewWaung commented 2 years ago

触发场景描述 按照excel模板导出xlsx文件,数据列表需要动态填充,动态填充的行数据需要合并单元格,测试发现动态填充7行没有问题,填充8行以上时就报错,如:Cannot add merged region C25:D25 to sheet because it overlaps with an existing merged region (B25:L25). 模板文件格式类似是这样的: image

触发Bug的代码

            //单元格合并
            List<CellRangeAddress> cellRangeAddress = new ArrayList<>();
            if (CollectionUtil.isNotEmpty(excelVoList)) {
                if (excelVoList.size() > 1) {
                    for (int i = 0; i < excelVoList.size(); i++) {
                        cellRangeAddress.add(new CellRangeAddress(firstRow, lastRow, 2, 3));
                        cellRangeAddress.add(new CellRangeAddress(firstRow, lastRow, 7, 9));
                        cellRangeAddress.add(new CellRangeAddress(firstRow, lastRow, 12, 13));
                        firstRow++;
                        lastRow++;
                    }
                }
            }

           ......

         ExcelWriter excelWriter = EasyExcel.write(os).withTemplate(inputStream)
                    .registerWriteHandler(piFillMergeStrategy)
                    .build();
            WriteSheet writeSheet = EasyExcel.writerSheet().build();
            FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();

            //参数集合,直接写入到Excel数据
            excelWriter.fill(paramsMap, writeSheet);
            //列表数据
            excelWriter.fill(excelVoList, fillConfig, writeSheet);

单元格合并策略是这样的:

        @Override
        public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) {
          if (CollectionUtil.isNotEmpty(cellRangeAddress)) {
            if (row.getRowNum() >= beginRow && row.getRowNum() <= beginRow + mergeRows) {
                for (CellRangeAddress item : cellRangeAddress) {
                    writeSheetHolder.getSheet().addMergedRegionUnsafe(item);
                }
            }
        }
    }

提示的异常或者没有达到的效果 同样的逻辑,数据列表7行(包括)以下导出没有问题,7行以上导出就会报错

zhuangjiaju commented 2 years ago

你输出下所有合并的单元格信息 ,这个8层是你合并的有面积覆盖了

MatthewWaung commented 2 years ago

合并单元格信息debug看后是没有问题的,我怀疑是内部缓存没有及时清掉导致的,我把第8行取消单元格合并,依然会报第9行合并被覆盖了

MatthewWaung commented 2 years ago

关键是7行及以下合并没问题,列表数据有8行及以上就出现问题了