[alibaba/easyexcel]动态合并单元格、合并行的问题

2024-05-30 577 views
5

使用以下合并策略,是每3行合并一次。如果我想第一次合并3行,第二次合并2行呢

ExcelWriterBuilder excelWriterBuilder = EasyExcel.write(response.getOutputStream(), TaskUserExcelDTO.class);

 IntStream.range(0, 8).forEach(idx ->
        excelWriterBuilder.registerWriteHandler(new LoopMergeStrategy(3, idx)));
 excelWriterBuilder.sheet("sheet").doWrite(taskUsers);

实现效果如下: image

@zhuangjiaju

回答

8

我寻找到一个解决方案

        try (final FileOutputStream outputStream = new FileOutputStream("D://1.xlsx");) {
            //获取excelWriter,直接build出来
            final ExcelWriter excelWriter = EasyExcel.write(outputStream, TaskUserExcelDTO.class).build();
            //选定sheet,直接build出来
            final WriteSheet sheet = EasyExcel.writerSheet("sheet").build();
            //构建table,直接build出来,按需构建,LoopMergeStrategy第一个参数是每几个合并,第二个参数是列的索引,从0开始的
            final WriteTable table0 = EasyExcel.writerTable(0).needHead(false).registerWriteHandler(new LoopMergeStrategy(3, 0)).build();
            final WriteTable table1 = EasyExcel.writerTable(1).needHead(false).registerWriteHandler(new LoopMergeStrategy(2, 0)).build();
            //获得需要写入的数据
            final List<TaskUserExcelDTO> data = taskUsers();
            //写入table(事实证明,table可以重复利用
            excelWriter.write(data.stream().limit(3).collect(Collectors.toList()), sheet, table0);
            excelWriter.write(data.stream().skip(3).limit(2).collect(Collectors.toList()), sheet, table1);
            excelWriter.write(data.stream().skip(5).collect(Collectors.toList()), sheet, table0);
            //不要忘记关闭
            excelWriter.finish();
        } catch (IOException e) {
            log.error("", e);
        }

image 顺带一提,我也是普通用户,这个代码是根据官方教程使用table写入改的

2

@pdkst 感谢您花时间处理我这个问题。 我参考了:com.alibaba.excel.write.merge.LoopMergeStrategy 最终是这样实现的:

public class CustomLoopMergeStrategy extends AbstractMergeStrategy {

    /**
     * 需要合并的动态行,比如:3、2
     */
    private LinkedList<Integer> eachRow;
    private int columnIndex;

    /**
     * 最大合并的列
     */
    private int maxColumn;

    public CustomLoopMergeStrategy(List<Integer> eachRow, int columnIndex, int maxColumn) {
        if (eachRow.stream().anyMatch(row -> row < 1)) {
            throw new IllegalArgumentException("EachRows must be greater than 1");
        }
        this.eachRow = new LinkedList<>(eachRow);
        this.columnIndex = columnIndex;
        this.maxColumn = maxColumn;
    }

    @Override
    protected void merge(Sheet sheet, Cell cell, Head head, int relativeRowIndex) {

        if (eachRow.isEmpty() || head.getColumnIndex() > maxColumn) {
            return;
        }

        if (head.getColumnIndex() == maxColumn) {
            eachRow.removeFirst();
            return;
        }

        if (head.getColumnIndex() == columnIndex && eachRow.getFirst() != 1) {
            CellRangeAddress cellRangeAddress = new CellRangeAddress(cell.getRowIndex(),
                    cell.getRowIndex() + eachRow.getFirst() - 1, cell.getColumnIndex(), cell.getColumnIndex());
            sheet.addMergedRegion(cellRangeAddress);
        }
    }

昨天刚使用easyexcel,也是普通用户,不过最终实现了想要的效果, 代码应该还有优化的空间。

1

@pdkst 感谢您花时间处理我这个问题。 我参考了:com.alibaba.excel.write.merge.LoopMergeStrategy 最终是这样实现的:

public class CustomLoopMergeStrategy extends AbstractMergeStrategy {

    /**
     * 需要合并的动态行,比如:3、2
     */
    private LinkedList<Integer> eachRow;
    private int columnIndex;

    /**
     * 最大合并的列
     */
    private int maxColumn;

    public CustomLoopMergeStrategy(List<Integer> eachRow, int columnIndex, int maxColumn) {
        if (eachRow.stream().anyMatch(row -> row < 1)) {
            throw new IllegalArgumentException("EachRows must be greater than 1");
        }
        this.eachRow = new LinkedList<>(eachRow);
        this.columnIndex = columnIndex;
        this.maxColumn = maxColumn;
    }

    @Override
    protected void merge(Sheet sheet, Cell cell, Head head, int relativeRowIndex) {

        if (eachRow.isEmpty() || head.getColumnIndex() > maxColumn) {
            return;
        }

        if (head.getColumnIndex() == maxColumn) {
            eachRow.removeFirst();
            return;
        }

        if (head.getColumnIndex() == columnIndex && eachRow.getFirst() != 1) {
            CellRangeAddress cellRangeAddress = new CellRangeAddress(cell.getRowIndex(),
                    cell.getRowIndex() + eachRow.getFirst() - 1, cell.getColumnIndex(), cell.getColumnIndex());
            sheet.addMergedRegion(cellRangeAddress);
        }
    }

昨天刚使用easyexcel。代码估计有bug,还有优化的空间,见谅。 不过最终实现了想要的效果。

实现效果就好

8

楼上的应该可以。逻辑就是参照合并策略自己写一个。

9

上面方法不行

4

上面方法不行

我最新的版本,业务上已使用过。去年写的,略微复杂:

public class CustomLoopMergeStrategy extends AbstractMergeStrategy {

    private LinkedList<Integer> eachRow;
    private int columnIndex;
    private int maxColumn;
    private LinkedList<Integer> totalRows;

    public CustomLoopMergeStrategy(List<Integer> eachRow, int columnIndex, int maxColumn) {
        if (eachRow.stream().anyMatch(row -> row < 1)) {
            throw new IllegalArgumentException("EachRows must be greater than 1");
        }
        this.eachRow = new LinkedList<>(eachRow);
        this.columnIndex = columnIndex;
        this.maxColumn = maxColumn;
        final int[] acc = {0};
        this.totalRows = eachRow.stream().map(item -> {
            int result = item + acc[0], item1 = item + acc[0];

            acc[0] = item1;
            if (item == 1) {
                result = 0;
            }

            return result;
        }).filter(i -> i != 0).collect(Collectors.toCollection(LinkedList::new));
    }

    @Override
    protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {

        if (totalRows.isEmpty() || eachRow.isEmpty() || head.getColumnIndex() > maxColumn) {
            return;
        }

        if (head.getColumnIndex() == maxColumn && eachRow.getFirst() == 1) {
            eachRow.removeFirst();
            return;
        }

        if (relativeRowIndex >= totalRows.getFirst()) {
            totalRows.removeFirst();
            eachRow.removeFirst();
        }

        if (head.getColumnIndex() == columnIndex && !totalRows.isEmpty() && !eachRow.isEmpty()
                && relativeRowIndex == totalRows.getFirst() - eachRow.getFirst()) {

            CellRangeAddress cellRangeAddress = new CellRangeAddress(cell.getRowIndex(),
                    cell.getRowIndex() + eachRow.getFirst() - 1, cell.getColumnIndex(), cell.getColumnIndex());

            sheet.addMergedRegion(cellRangeAddress);

        }
    }
}

使用的地方:

                List<Integer> eachRows = data.stream()
                        .collect(Collectors.groupingBy(BaseDTO::getGroupId))
                        .entrySet().stream().sorted(Map.Entry.comparingByKey())
                        .map(entry -> entry.getValue().size())
                        .collect(Collectors.toList());

                IntStream.range(0, mergeColumns).forEach(idx ->
                        excelWriterBuilder.registerWriteHandler(new CustomLoopMergeStrategy(eachRows, idx, mergeColumns)));
9

请问一下,分批次导出的时候,如何做到动态合并单元格? 因为第一次就要把导出Excel的何并规则确定了,所以最多只能确定第一次的规则。 以下代码没有效果:

` MyMergeStrategy myMergeStrategy = new MyMergeStrategy(getCellRangeAddresss()); ExcelWriterSheetBuilder writerSheetBuilder = EasyExcel.writerSheet(0, "商品明细表").head(FinancialReport.class);

    WriteSheet writeSheet = writerSheetBuilder.registerWriteHandler(myMergeStrategy).build();
    excelWriter.write(exportList, writeSheet);

    MyMergeStrategy myMergeStrategy_2 = new MyMergeStrategy(getCellRangeAddresss_2());
    WriteSheet writeSheet_2 = writerSheetBuilder.registerWriteHandler(myMergeStrategy_2).build();
    excelWriter.write(exportList, writeSheet_2);

`

6

请问一下,分批次导出的时候,如何做到动态合并单元格? 因为第一次就要把导出Excel的何并规则确定了,所以最多只能确定第一次的规则。 以下代码没有效果:

` MyMergeStrategy myMergeStrategy = new MyMergeStrategy(getCellRangeAddresss()); ExcelWriterSheetBuilder writerSheetBuilder = EasyExcel.writerSheet(0, "商品明细表").head(FinancialReport.class);

  WriteSheet writeSheet = writerSheetBuilder.registerWriteHandler(myMergeStrategy).build();
  excelWriter.write(exportList, writeSheet);

  MyMergeStrategy myMergeStrategy_2 = new MyMergeStrategy(getCellRangeAddresss_2());
  WriteSheet writeSheet_2 = writerSheetBuilder.registerWriteHandler(myMergeStrategy_2).build();
  excelWriter.write(exportList, writeSheet_2);

`

同样遇到这个问题,请问有找到解决方案吗?