EasyExcel导出数据多行合并单元格


前言

记录使用EasyExcel导出Excel合并多行数据


一、话不多说上代码

代码如下:这是比较初始版本的、没做优化,如有大佬多多提点

package com.ffcs.oss.config;

import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;

import java.util.List;

public class ExcelFileCellsMerge implements CellWriteHandler {


    /**
     * 用第几行开始合并 ,默认为1,因为第0行是标题,EasyExcel 的默认也是
     */
    private int mergeRowIndex = 1;

    @Override
    public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {
    }

    @Override
    public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
    }

    /*
     * 在对单元格的所有操作完成后调用
     */
    @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) {
            // 前五列需要合并 所以需要读取到第五列
            if (curColIndex == 5) {
                mergeWithPrevRow(writeSheetHolder, cell, curRowIndex);
            }
        }
    }

    /**
     * 当前单元格向上合并
     *
     * @param writeSheetHolder
     * @param cell             当前单元格
     * @param curRowIndex      当前行
     */
    private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex) {
        //获取当前行的当前列的数据和上一行的当前列列数据,通过上一行数据是否相同进行合并
        Cell curCell = cell.getSheet().getRow(curRowIndex).getCell(0);
        Cell curCell1 = cell.getSheet().getRow(curRowIndex).getCell(1);
        Cell curCell2 = cell.getSheet().getRow(curRowIndex).getCell(2);
        Cell curCell3 = cell.getSheet().getRow(curRowIndex).getCell(3);
        Cell curCell4 = cell.getSheet().getRow(curRowIndex).getCell(4);
        Cell curCell5 = cell.getSheet().getRow(curRowIndex).getCell(5);
        Object curData = curCell.getCellTypeEnum() == CellType.STRING ? curCell.getStringCellValue() : curCell.getNumericCellValue();
        Object curData1 = curCell1.getCellTypeEnum() == CellType.STRING ? curCell1.getStringCellValue() : curCell1.getNumericCellValue();
        Object curData2 = curCell2.getCellTypeEnum() == CellType.STRING ? curCell2.getStringCellValue() : curCell2.getNumericCellValue();
        Object curData3 = curCell3.getCellTypeEnum() == CellType.STRING ? curCell3.getStringCellValue() : curCell3.getNumericCellValue();
        Object curData4 = curCell4.getCellTypeEnum() == CellType.STRING ? curCell4.getStringCellValue() : curCell4.getNumericCellValue();
        Object curData5 = curCell5.getCellTypeEnum() == CellType.STRING ? curCell5.getStringCellValue() : curCell5.getNumericCellValue();
        // 获取上一行数据
        Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(0);
        Cell preCell1 = cell.getSheet().getRow(curRowIndex - 1).getCell(1);
        Cell preCell2 = cell.getSheet().getRow(curRowIndex - 1).getCell(2);
        Cell preCell3 = cell.getSheet().getRow(curRowIndex - 1).getCell(3);
        Cell preCell4 = cell.getSheet().getRow(curRowIndex - 1).getCell(4);
        Cell preCell5 = cell.getSheet().getRow(curRowIndex - 1).getCell(5);
        Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue();
        Object preData1 = preCell1.getCellTypeEnum() == CellType.STRING ? preCell1.getStringCellValue() : preCell1.getNumericCellValue();
        Object preData2 = preCell2.getCellTypeEnum() == CellType.STRING ? preCell2.getStringCellValue() : preCell2.getNumericCellValue();
        Object preData3 = preCell3.getCellTypeEnum() == CellType.STRING ? preCell3.getStringCellValue() : preCell3.getNumericCellValue();
        Object preData4 = preCell4.getCellTypeEnum() == CellType.STRING ? preCell4.getStringCellValue() : preCell4.getNumericCellValue();
        Object preData5 = preCell5.getCellTypeEnum() == CellType.STRING ? preCell5.getStringCellValue() : preCell5.getNumericCellValue();
        String curString = String.valueOf(curData) + curData1 + curData2 + curData3 + curData4 + curData5;
        String preString = String.valueOf(preData) + preData1 + preData2 + preData3 + preData4 + preData5;

        // 比较当前行的单元格与上一行是否相同,相同合并当前单元格与上一行
        if (curString.equals(preString)) {
            Sheet sheet = writeSheetHolder.getSheet();
            // 获取合并信息
            List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();
            boolean isMerged = false;
            // 下标
            int index = 0;
            for (int i = 0; i < mergeRegions.size(); i++) {
                CellRangeAddress cellRangeAddr = mergeRegions.get(i);
                // 若上一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元
                if (cellRangeAddr.isInRange(curRowIndex - 1, index)) {
                    sheet.removeMergedRegion(mergeRegions.size() - 6);
                    cellRangeAddr.setLastRow(curRowIndex);
                    sheet.addMergedRegion(cellRangeAddr);
                    isMerged = true;
                }
                index++;
                // 这个是第几列
                if (index > 5) {
                    index = 0;
                }
            }
            if (!isMerged) {
                for (int i = 0; i <= 5; i++) {
                    CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, i, i);
                    sheet.addMergedRegion(cellRangeAddress);
                }
            }
        }
    }

}

2.导出使用

代码如下:

	List<ExportExcel> list =new ArrayList<>();
	response.setContentType("application/vnd.ms-excel");
	response.setCharacterEncoding("utf-8");
	// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
	String fileName = URLEncoder.encode("Excel文件名", "utf-8").replaceAll("\\+", "%20");
	response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
	EasyExcel.write(response.getOutputStream(), ExportExcel.class)
	.registerWriteHandler(new ExcelFileCellsMerge())
	.sheet(0, "sheet页名称").doWrite(list);

3、导出效果如下

在这里插入图片描述


总结

找了很久没找到合并多行表格的代码,这是我根据查找的样例、结合自身项目需求进行修改而来的。使用范围有所限制,当然有大佬可以进行优化一下。万分感谢。

  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
可以通过实现EasyExcel的WriteHandler接口来实现相同数据合并单元格的功能。具体步骤如下: 1. 新建一个类实现WriteHandler接口,并重写对应的方法。 2. 在实现的方法中,通过Excel的API获取到要合并的单元格的起始行、起始列、结束行、结束列。可以使用Map来记录每一种相同数据的位置信息,然后再遍历Map合并单元格。 3. 使用EasyExcel的write方法时,通过指定Handler参数,将编写好的WriteHandler实例传递进去即可。 下面是示例代码: ```java public class MergeCellWriteHandler implements WriteHandler { private Map<String, List<CellRangeAddress>> mergeMap = new HashMap<>(); @Override public void row(int i, List<Object> list) { //处理行数据,将相同的数据合并单元格 String key = list.get(0).toString(); //以第一列为key if (mergeMap.containsKey(key)) { List<CellRangeAddress> cellRangeList = mergeMap.get(key); CellRangeAddress lastCellRange = cellRangeList.get(cellRangeList.size() - 1); if (i - lastCellRange.getLastRow() == 1) { //如果上一个单元格的结尾行是当前行的上一行,则可以合并单元格 lastCellRange.setLastRow(i); } else { cellRangeList.add(new CellRangeAddress(i, i, 0, list.size() - 1)); //如果不连续,则新建一个单元格范围 } } else { List<CellRangeAddress> cellRangeList = new ArrayList<>(); cellRangeList.add(new CellRangeAddress(i, i, 0, list.size() - 1)); mergeMap.put(key, cellRangeList); } } @Override public void sheet(int i) { } @Override public void start() { } @Override public void end() { //处理完整个sheet后,将记录的单元格范围进行合并 Sheet sheet = EasyExcel.writerSheet().build().getSheet(); for (Map.Entry<String, List<CellRangeAddress>> entry : mergeMap.entrySet()) { String key = entry.getKey(); List<CellRangeAddress> cellRangeList = entry.getValue(); for (CellRangeAddress cellRange : cellRangeList) { sheet.addMergedRegion(cellRange); } } } } ``` 使用方法: ```java EasyExcel.write("test.xlsx") .sheet() .registerWriteHandler(new MergeCellWriteHandler()) .head(head) .doWrite(data); ``` 其中head和data分别是表头和数据,可以从数据库或其他数据源中获取。要实现合并单元格,需要将第一列相同的数据合并。示例中以第一列为key,记录每一种相同数据所对应的单元格范围,最后进行合并。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值