[alibaba/easyexcel]使用填充方式,写入多行数据后,在SheetWriteHandler#afterSheetCreate中,无法合并单元格

2024-01-04 985 views
5
触发场景描述

模板excel: merge_template.xlsx 向模板excel中填充数据,模板sheet2可以正常填充并合并;模板sheet1中无法合并,代码抛出异常:

Exception in thread "main" java.lang.IllegalStateException: Cannot add merged region B12:B13 to sheet because it overlaps with an existing merged region (A11:D13).

2023-09-06_154956

触发Bug的代码
public class MergeTest {

    public static final int SHEET_NO_1 = 0;
    public static final int SHEET_NO_2 = 1;
    public static void main(String[] args) throws IOException {
        String fileName = "D:\\MergedExcel.xlsx";
        Resource resource = new ClassPathResource("/merge_template.xlsx");
        // 方案1
        try (ExcelWriter excelWriter = EasyExcel.write(fileName).inMemory(true).withTemplate(resource.getInputStream()).build()) {
            // 使用sheet2能生成目标文件,使用sheet1就会报错
            WriteSheet writeSheet = EasyExcel.writerSheet(SHEET_NO_1).registerWriteHandler(new SheetWriteHandler() {
                @Override
                public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
                    // 写10行数据,将第2列单元格,每两行行合并一次
                    Sheet sheet = writeSheetHolder.getSheet();
                    int startRow = 0;
                    for (int j = 0; j < 5; j++) {
                        int lastRow = startRow + 1;
                        System.out.println(String.format("%s_%s", startRow, lastRow));
                        CellRangeAddress cellRangeAddress = new CellRangeAddress(startRow, lastRow, 1, 1);
                        sheet.addMergedRegionUnsafe(cellRangeAddress);
                        startRow += 2;
                    }
                }}).build();
            excelWriter.fill(mockData(), FillConfig.builder().forceNewRow(true).build(), writeSheet);
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("export success");
    }

    private static List<Map<String, String>> mockData() {
        List<Map<String, String>> dataList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            Map<String, String> map = new HashMap<>();
            map.put("a", "1");
            map.put("b", "2");
            map.put("c", "3");
            map.put("d", "4");
            dataList.add(map);
        }
        return dataList;
    }
}
提示的异常或者没有达到的效果

异常:

Exception in thread "main" java.lang.IllegalStateException: Cannot add merged region B12:B13 to sheet because it overlaps with an existing merged region (A11:D13).

想要的效果: 2023-09-06_154956

回答

0

感觉你这个是因为你已经合并了单元格,程序在跑的时候发生了冲突。

2

是的,调试到poi包的org.apache.poi.ss.usermodel.helpers.RowShifter#shiftMergedRegions的这个方法,发生的问题,要合并的第二个单元格没有被剔除,导致报错的。 如果不再afterSheetCreate中处理,生成文件后,再读取sheet,使用同样的参数进行合并就是ok的,所以看起来像是easyexcel的bug

3

这个使用原生的poi也是不行的,poi不支持对已经合并的单元格操作 image 如果要实现这个功能,可以考虑在对模板写入数据之前,对模板的单元格恢复到普通的单元格,不存在合并,但是现在是不具备这个功能的,这个功能也可能存在歧义

1

@youlingdada 你这个demo直接合并“已经合并的单元格”肯定是不行的。我是用easyexcel直接插入10行数据,然后在SheetWriteHandler#afterSheetCreate中合并插入的10行数据的。

4

我的意思的poi不支持对已经合并过的单元格进行合并操作,当然你在SheetWriteHandler#afterSheetCreate中合并插入的数据,对采用模板填充的方式,模板单元格如果存在已经合并的情况也不能合并

5

@zhuangjiaju 明白了,谢谢回答

9

目前解决方式是将填充和合并分开处理即可。第一步只填充数据,并生成excel;然后再次读取第一步生成的excel,只进行合并操作,最后生成目标excel即可