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,将所有数据放入内存中,一次保存。否则会出现问题。

模板

效果图

相关推荐
愿你天黑有灯下雨有伞11 小时前
Java使用FastExcel实现Excel文件导入
java·excel
爆爆凯11 小时前
Excel 导入导出工具类文档
java·excel
凌康ACG18 小时前
springboot打包二次压缩Excel导致损坏
spring boot·后端·excel
诸葛大钢铁1 天前
Excel转PDF的三种方法
笔记·职场和发展·pdf·excel
小小薛定谔1 天前
java操作Excel两种方式EasyExcel 和POI
java·python·excel
CodeCraft Studio1 天前
DHTMLX Suite 9.2 重磅发布:支持历史记录、类Excel交互、剪贴板、拖放增强等多项升级
javascript·excel·交互·表格·dhtmlx·grid·网格
小阳睡不醒2 天前
小白成长之路-Elasticsearch 7.0 配置
大数据·elasticsearch·excel
奋进的孤狼2 天前
【Excel】使用vlookup函数快速找出两列数据的差异项
excel
不讲废话的小白2 天前
解锁高效Excel技能:摆脱鼠标,快速编辑单元格
计算机外设·excel
CodeCraft Studio2 天前
Excel处理控件Aspose.Cells教程:使用 Python 在 Excel 中创建甘特图
python·excel·项目管理·甘特图·aspose·aspose.cells