文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

使用EasyExcel导出表格时合并单元格

2023-09-01 16:07

关注

现在需要将一个导出列表数据到Excel表格的功能进行改造,将指定列相同数据自动合并单元格。
在这里插入图片描述
如上图所示,指定A、B两列自动合并,如图所示(6、7),(8、9),(13、14、15)要自动合并单元格。

EasyExcel是一个基于Java的、快速、简洁、解决大文件内存溢出的Excel处理工具。他能让你在不用考虑性能、内存的等因素的情况下,快速完成Excel的读、写等功能。

EasyExcel相比其他Excel解析框架(Apache poi和jxl),拥有更好的内存消耗管理算法。特别是对07版Excel的解决,EasyExcel重写了底层解析逻辑,一个3M的Excel解析只需要几M内存,但是用poi解析可能需要100M左右的内存。EasyExcel提高了读取性能,64M内存20秒读取75M的Excel,还有更快的极速模式,但是消耗的内存会更多一些。

EasyExcel支持自定义策略合并单元格,可以方便快捷填充数据到模板中,有活跃的中文社区支持,完善的测试用例可以覆盖大部分业务场景的使用。

使用EasyExcel导出Excel代码示例:

@Test    public void testWrite() throws IOException {        List<DemoMergeData> resultList = new ArrayList<>();        resultList.add(DemoMergeData.builder().id(1).sub("张胜男").date("12").build());        resultList.add(DemoMergeData.builder().id(1).sub("李四").date("224").build());        resultList.add(DemoMergeData.builder().id(3).sub("王五").date("224").build());        resultList.add(DemoMergeData.builder().id(4).sub("赵柳").date("224").build());        resultList.add(DemoMergeData.builder().id(5).sub("赵柳").date("224").build());        resultList.add(DemoMergeData.builder().id(5).sub("赵柳").date("224").build());        resultList.add(DemoMergeData.builder().id(8).sub("赵柳").date("224").build());        resultList.add(DemoMergeData.builder().id(8).sub("赵柳").date("224").build());        resultList.add(DemoMergeData.builder().id(9).sub("陈琪").date("224").build());        resultList.add(DemoMergeData.builder().id(10).sub("小白").date("241").build());        resultList.add(DemoMergeData.builder().id(11).sub("小黑").date("241").build());        resultList.add(DemoMergeData.builder().id(12).sub("小黑").date("241").build());        resultList.add(DemoMergeData.builder().id(12).sub("小黑").date("241").build());        resultList.add(DemoMergeData.builder().id(12).sub("小黑").date("241").build());        resultList.add(DemoMergeData.builder().id(13).sub("小黑").date("241").build());        //  设置文件名称        String fileName = "C:\\Users\\Administrator\\Downloads\\test\\t1.xlsx";        File file = new File(fileName);        if (!file.exists()) {            file.createNewFile();        }        //  sheet名称        EasyExcel.write(fileName, DemoMergeData.class)                .autoCloseStream(Boolean.TRUE)                .sheet("测试导出").doWrite(resultList);    }

导出表格样式:
在这里插入图片描述

自定义策略一代码示例:

public class ExcelFillCellMergeStrategy implements CellWriteHandler {    private int[] mergeColumnIndex;    private int mergeRowIndex;        public ExcelFillCellMergeStrategy() {    }    public ExcelFillCellMergeStrategy(int mergeRowIndex, int[] mergeColumnIndex) {        this.mergeRowIndex = mergeRowIndex;        this.mergeColumnIndex = mergeColumnIndex;    }    @Override    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {        //当前行        int curRowIndex = cell.getRowIndex();        //当前列        int curColIndex = cell.getColumnIndex();        if (curRowIndex > mergeRowIndex) {            for (int columnIndex : mergeColumnIndex) {                if (curColIndex == columnIndex) {                    mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);                    break;                }            }        }    }        private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {        //获取当前行的当前列的数据和上一行的当前列列数据,通过上一行数据是否相同进行合并        Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();        Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);        Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue();        // 比较当前行的第一列的单元格与上一行是否相同,相同合并当前单元格与上一行        if (curData.equals(preData)) {            Sheet sheet = writeSheetHolder.getSheet();            List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();            boolean isMerged = false;            for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {                CellRangeAddress cellRangeAddr = mergeRegions.get(i);                // 若上一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元                if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) {                    sheet.removeMergedRegion(i);                    cellRangeAddr.setLastRow(curRowIndex);                    sheet.addMergedRegion(cellRangeAddr);                    isMerged = true;                }            }            // 若上一个单元格未被合并,则新增合并单元            if (!isMerged) {                CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex, curColIndex);                sheet.addMergedRegion(cellRangeAddress);            }        }    }    @Override    public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) {    }    @Override    public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer integer, Boolean aBoolean) {    }}

测试代码示例:

@Test    public void testWrite() throws IOException {        int[] mergeColumnIndex = {0,1};    // 需要从第几行开始合并        int mergeRowIndex = 1;        // 数据就不初始化了        List<DemoMergeData> resultList = new ArrayList<>();        // 设置文件名称        String fileName = "C:\\Users\\Administrator\\Downloads\\test\\t1.xlsx";        File file = new File(fileName);        if (!file.exists()) {            file.createNewFile();        }        //  sheet名称        EasyExcel.write(fileName, DemoMergeData.class)                .autoCloseStream(Boolean.TRUE)                .registerWriteHandler(new ExcelFillCellMergeStrategy(mergeRowIndex,mergeColumnIndex))                .sheet("测试导出").doWrite(resultList);    }

导出样式:
在这里插入图片描述

自定义策略二代码示例:

public class MultiColumnMergeStrategy extends AbstractMergeStrategy {    // 合并的列编号,从0开始,指定的index或自己按字段顺序数    private Integer startCellIndex = 0;    private Integer endCellIndex = 0;    // 数据集大小,用于区别结束行位置    private Integer maxRow = 0;    // 禁止无参声明    private MultiColumnMergeStrategy() {    }    public MultiColumnMergeStrategy(Integer maxRow, Integer startCellIndex, Integer endCellIndex) {        this.startCellIndex = startCellIndex;        this.endCellIndex = endCellIndex;        this.maxRow = maxRow;    }    // 记录上一次合并的信息    private final List<List<String>> dataList = new ArrayList<>();        @Override    protected void merge(Sheet sheet, Cell cell, Head head, int relativeRowIndex) {        int currentCellIndex = cell.getColumnIndex();        int currentRowIndex = cell.getRowIndex();        // 判断该列是否需要合并        if (currentCellIndex < startCellIndex || currentCellIndex > endCellIndex) {            return;        }        Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();        String currentCellValue = curData.toString();        List<String> rowList;        if (dataList.size() > currentRowIndex - 1) {            rowList = dataList.get(currentRowIndex - 1);        } else {            rowList = new ArrayList<>();            dataList.add(rowList);        }        rowList.add(currentCellValue);        // 结束的位置触发下最后一次没完成的合并        if (relativeRowIndex == (maxRow - 1) && currentCellIndex == endCellIndex) {            System.out.println(JSONObject.toJSONString(dataList));            List<String> tempList = null;            Integer tempIndex = null;            for (int i = 0; i < dataList.size(); i++) {                if (tempList == null) {                    tempList = dataList.get(i);                    tempIndex = i;                    continue;                }                List<String> currList = dataList.get(i);                if (tempList.equals(currList)) {                    if (i >= dataList.size() - 1) {                        // 结束的位置触发下最后一次没完成的合并                        for (int j = 0; j < tempList.size(); j++) {sheet.addMergedRegionUnsafe(new CellRangeAddress(tempIndex + 1, i + 1, startCellIndex + j, startCellIndex + j));                        }                    }                    continue;                }                // 当前行数据和上一行数据不同且上面有多行相同数据时触发合并                if (i - tempIndex > 1) {                    for (int j = 0; j < tempList.size(); j++) {                        sheet.addMergedRegionUnsafe(new CellRangeAddress(tempIndex + 1, i, startCellIndex + j, startCellIndex + j));                    }                }                tempIndex = i;                tempList = currList;            }        }    }}

测试代码示例:

@Test    public void testWrite() throws IOException {        // 数据就不初始化了        List<DemoMergeData> resultList = new ArrayList<>();        // 设置文件名称        String fileName = "C:\\Users\\Administrator\\Downloads\\test\\t1.xlsx";        File file = new File(fileName);        if (!file.exists()) {            file.createNewFile();        }        //  sheet名称        EasyExcel.write(fileName, DemoMergeData.class)                .autoCloseStream(Boolean.TRUE)                .registerWriteHandler(new MultiColumnMergeStrategy(resultList.size(),0,1))                .sheet("测试导出").doWrite(resultList);    }

导出样式:
在这里插入图片描述

EasyExcel功能灵活强大,可以根据自身业务场景去自定义样式,也可以使用通过模板填充功能实现导出国际化语言等复杂功能。

来源地址:https://blog.csdn.net/iiopsd/article/details/128197352

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯