EasyExcel如何实现单元格合并

后端 潘老师 5个月前 (12-11) 125 ℃ (0) 扫码查看

本文主要讲解关于EasyExcel如何实现单元格合并相关内容,让我们来一起学习下吧!

作为一名光荣的crud(搬砖)工程师,导出Excel可是必备的技能树(❛‿˂̵✧),使用原生的poi导出代码既复杂又容易出bug,日常工作中更多的时使用阿里开源的EasyExcel;文档中有关合并单元格的例子不太满足日常工作的需要,本篇文章自定义了一个合并的策略,实现行内容相同的合并。

合并策略


/**
 * 行内容相同合并策略
 */
public static class RowContentSameMergeStrategy implements RowWriteHandler {

    /**
     * 数据量,即导出数据的行数,不包含表头
     */
    private final int dataSize;

    /**
     *  表头数量,即导出列的数量
     */
    private final int headSize;

    /**
     *  数据的开始行
     */
    private Integer startRow;

    /**
     *  合并的高度
     */
    private int[][] mergeHeight;

    public RowContentSameMergeStrategy(int dataSize, int headSize) {
        this.dataSize = dataSize - 1;
        this.headSize = headSize;
    }

    @Override
    public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) {
        if (isHead) {
            return;
        }
        // 定义数据的开始行
        if (startRow == null) {
            startRow = row.getRowNum();
        }

        // 没到最后一行,直接返回
        if (relativeRowIndex != dataSize) {
            return;
        }
        // 定义数据的结束行
        int endRow = row.getRowNum();

        // 定义二维数组记录合并的高度
        mergeHeight = new int[endRow + 1][headSize + 1];

        // 全部sheet已经加载完毕
        // 需要进行单元格的合并
        // 这里处理的是行合并,不处理列合并

        // 读取每列
        for (int cellIndex = 0; cellIndex < headSize; cellIndex++) {

            // startRowPoint=开始行指针 endRowPoint=结束行指针 preCellIndex=前一列单元格
            int startRowPoint = startRow, endRowPoint = startRow, preCellIndex = cellIndex - 1;
            // startRowCell=开始行当前单元格的内容
            String startRowCell = null;

            for (; endRowPoint <= endRow; endRowPoint++) {

                if (startRowPoint == endRowPoint) {
                    startRowCell = writeSheetHolder.getSheet().getRow(startRowPoint).getCell(cellIndex).getStringCellValue();
                    continue;
                }

                if (preCellIndex >= 0 ) {
                    // 前一个格子的高度
                    int preHeight = mergeHeight[startRowPoint][preCellIndex];
                    // 若当前格子合并的高度已经超过了前一列,直接进行重置处理
                    if (endRowPoint - startRowPoint + 1 > preHeight) {
                        // 需要进行合并
                        if (startRowPoint != endRowPoint - 1) {
                            merge(writeSheetHolder, startRowPoint, endRowPoint - 1, cellIndex);
                        }

                        // 重置两个指针,由于endPoint会固定往后走一位,所以将start调整到当前位置
                        startRowPoint = endRowPoint;
                        endRowPoint = endRowPoint - 1;
                        continue;
                    }
                }

                // 计算当前行数据是否相同
                String endCell = writeSheetHolder.getSheet().getRow(endRowPoint).getCell(cellIndex).getStringCellValue();

                // 最后一行的特殊处理
                // 如果相同直接合并单元格
                if (endRowPoint == endRow && StringUtils.equals(startRowCell, endCell)) {
                    merge(writeSheetHolder, startRowPoint, endRowPoint, cellIndex);
                    continue;
                }

                // 不相同 -> 需要进行单元格的合并
                if (!StringUtils.equals(startRowCell, endCell)) {
                    // 需要进行合并
                    if (startRowPoint != endRowPoint - 1) {
                        merge(writeSheetHolder, startRowPoint, endRowPoint - 1, cellIndex);
                    }
                    // 重置两个指针,由于endPoint会固定往后走一位,所以将start调整到当前位置
                    startRowPoint = endRowPoint;
                    endRowPoint = endRowPoint - 1;
                }

                // 相同 -> 继续读取下一行
            }
        }
    }

    private void merge(WriteSheetHolder writeSheetHolder, int startRowPoint, int endRowPoint, int cellIndex) {

        // 计算高度
        int height = endRowPoint - startRowPoint + 1;

        CellRangeAddress cellRangeAddress = new CellRangeAddress(
                startRowPoint, endRowPoint,
                cellIndex, cellIndex
        );

        // 维护高度
        for (int i = startRowPoint; i <= endRowPoint; i++) {
            mergeHeight[i][cellIndex] = height;
        }
        writeSheetHolder.getSheet().addMergedRegionUnsafe(cellRangeAddress);
    }

}

策略使用

public static void main(String[] args) {
    List<DemoData> list = new ArrayList<>();
    list.add(new DemoData("us", "x", "y1", "z1"));
    list.add(new DemoData("us", "x", "y1", "z2"));
    list.add(new DemoData("us", "x", "y1", "z3"));
    list.add(new DemoData("jp", "x", "y2", "z1"));
    list.add(new DemoData("jp", "x", "y2", "z2"));
    list.add(new DemoData("jp", "x", "y2", "z3"));


    String fileName = "mergeWrite" + System.currentTimeMillis() + ".xlsx";

    // 自定义合并单元格策略

    // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
    EasyExcel.write(fileName, DemoData.class)
            .registerWriteHandler(new RowContentSameMergeStrategy(list.size(), 4))
            .sheet("模板")
            .doWrite(list);
}

以上就是关于EasyExcel如何实现单元格合并相关的全部内容,希望对你有帮助。欢迎持续关注潘子夜个人博客(www.panziye.com),学习愉快哦!


版权声明:本站文章,如无说明,均为本站原创,转载请注明文章来源。如有侵权,请联系博主删除。
本文链接:https://www.panziye.com/back/12468.html
喜欢 (0)
请潘老师喝杯Coffee吧!】
分享 (0)
用户头像
发表我的评论
取消评论
表情 贴图 签到 代码

Hi,您需要填写昵称和邮箱!

  • 昵称【必填】
  • 邮箱【必填】
  • 网址【可选】