Easy Excel 合并单元格

官方默认提供了两个单元格合并策略OnceAbsoluteMergeLoopMergeStrategy
OnceAbsoluteMerge只能实现一次合并,如果需要多次合并,则需要注册多次服务。
LoopMergeStrategy可以实现循环合并,但是只能实现每隔 n 个单元格合并。

如图,还有另外一个静态类 AbstractMergeStrategy 是两者的父类,可以据此,自己实现合并方案。

合并策略

java 复制代码
package cn.com.hmsm.bif.xingwen.accounting;  
  
import com.alibaba.excel.metadata.Head;  
import com.alibaba.excel.write.merge.AbstractMergeStrategy;  
import lombok.extern.slf4j.Slf4j;  
import org.apache.poi.ss.usermodel.Cell;  
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;  
  
/**  
 * 指定列,如果相邻两行的数据相同,则合并为一行  
 */  
@Slf4j  
public class ColumnSameDataMergeStrategy extends AbstractMergeStrategy {  
  
    private final int mergeRowIndex;  
  
    public ColumnSameDataMergeStrategy(int mergeRowIndex) {  
        this.mergeRowIndex = mergeRowIndex;  
    }  
  
    @Override  
    protected void merge(  
            Sheet sheet,  
            Cell cell,  
            Head head,  
            Integer relativeRowIndex  
    ) {  
  
        int rowIndex = cell.getRowIndex();  
        int colIndex = cell.getColumnIndex();  
  
        // 必须这样使用,不然lastRow 永远为空  
        sheet = cell.getSheet();  
        Row lastRow = sheet.getRow(rowIndex - 1);  
        if (lastRow == null) {  
            log.warn("rowIndex is {}, lastRow is null , data is {} ", rowIndex, cell);  
            return;  
        }  
        Cell lastRowCell = lastRow.getCell(colIndex);  
        // 先进行列的判断,再进行的判断  
        if (colIndex != mergeRowIndex) {  
            return;  
        }  
//        log.info("rowIndex is {}, data is {}", rowIndex, cell.toString());  
  
        // 如果数据相同,才进行合并  
        if (!lastRowCell.getStringCellValue().equals(cell.getStringCellValue())) {  
            return;  
        }  
  
        // 检查当前单元格是否已在合并中,如果在,则修改合数据;如果不存在,新建  
        List<CellRangeAddress> list = sheet.getMergedRegions();  
        for (int i = 0, listSize = list.size(); i < listSize; i++) {  
            CellRangeAddress cellAddresses = list.get(i);  
            // 检查列是否相同  
            if (cellAddresses.getFirstColumn() != colIndex || cellAddresses.getLastColumn() != colIndex) {  
                continue;  
            }  
            // 因为数据是从上到下添加的,行数是依次递增的,所以只需要检查合并的最后一行和上一行是否相同即可。  
            if (cellAddresses.getLastRow() == lastRowCell.getRowIndex()) {  
                // 见最后一行,改为当前行  
                cellAddresses.setLastRow(rowIndex);  
                sheet.removeMergedRegion(i);  
                sheet.addMergedRegion(cellAddresses);  
                return;  
            }  
  
        }  
  
        // 不存在已合并的区域,新建合格合并区域  
        CellRangeAddress cra = new CellRangeAddress(lastRowCell.getRowIndex(), cell.getRowIndex(), lastRowCell.getColumnIndex(), cell.getColumnIndex());  
        sheet.addMergedRegion(cra);  
  
    }  
  
}

使用

java 复制代码
try (ExcelWriter excelWriter = EasyExcel.write(filePath).withTemplate(templateFileName).build()) {  
                    WriteSheet writeSheet = EasyExcel.writerSheet("对账单")  
                                    .registerWriteHandler(new ColumnSameDataMergeStrategy(0))  
                                    .build();  
                    Map<String, Object> map = MapUtils.newHashMap();  
                    map.put("title", title);  
                    map.put("time", reconciliationCycle);  
                    excelWriter.fill(map, writeSheet);  

                    // 这里注意 入参用了forceNewRow 代表在写入list的时候不管list下面有没有空行 都会创建一行,然后下面的数据往后移动。默认 是false,会直接使用下一行,如果没有则创建。  
                    // forceNewRow 如果设置了true,有个缺点 就是他会把所有的数据都放到内存了,所以慎用  
                    // 简单的说 如果你的模板有list,且list不是最后一行,下面还有数据需要填充 就必须设置 forceNewRow=true 但是这个就会把所有数据放到内存 会很耗内存  
                    FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();  
                    excelWriter.fill(byStoreDtoList, fillConfig, writeSheet);  
//                    excelWriter.fill(byStoreDtoList, writeSheet);  
            }

注意,在使用时,依赖的是框架提供的数据,需要设置 forceNewRowtrue,将所有数据放入内存中,一次保存。否则会出现问题。

模板

效果图

相关推荐
z19408920664 小时前
在线题库整理:把重复劳动从 Excel 手工里解放出来
excel
开开心心_Every5 小时前
免费简洁的安卓黄历日历,软件推荐
运维·服务器·随机森林·pdf·电脑·excel·最小二乘法
VBAMatrix19 小时前
deepseek-v4正式接入Excel,一键生成财务分析报告
word·excel·审计·财务分析·deepseek·会计师事务所·tb工具箱
专注VB编程开发20年2 天前
傻瓜式Office 功能区插件 / Ribbon开发模板
ribbon·excel·vba·插件·扩展宏
专注VB编程开发20年2 天前
Excel 2024 / 365 已经把 “单元格填充效果→图片” 这个按钮删掉了
excel
开开心心就好3 天前
仅168KB的桌面图标自动隐藏工具
windows·计算机视觉·计算机外设·excel·启发式算法·宽度优先·csdn开发云
蒋胜山3 天前
Excel 练习题(7)
经验分享·excel
蒋胜山3 天前
Excel 练习题(6)
经验分享·excel
wcy_10113 天前
QCoder智能生成Excel数据清洗与可视化代码
python·excel
JoshRen4 天前
2026教程:上传Excel,用Gemini 3镜像站多模态一键生成问卷分析图表代码与结论(附国内免费方案)
excel