首页 > 其他分享 >EasyExcel动态单元格合并(跨行或跨列)

EasyExcel动态单元格合并(跨行或跨列)

时间:2024-03-09 16:24:21浏览次数:28  
标签:sheet int EasyExcel 单元格 合并 跨列 && rangeAddress

EasyExcel动态单元格合并(跨行或跨列)

  • 简单的合并单元格可以参照官网提供的@OnceAbsoluteMerge()和@ContentLoopMerge()两个注解进行

@OnceAbsoluteMerge()注解只会合并一次就不再执行了

动态相同值合并单元格代码示例(可以直接使用):

先看结果:

  1. 开启合并列行合并单元格,指定1,3,5,6列进行跨行合并结果图:

    跨行跨列

  2. 开启行合并结果图(指定1,3,5,6列进行跨行合并)

    跨行

  3. 开启列合并结果图

    跨列

具体代码显示:

  1. 测试使用(先创建两个类麻烦,测试类中将注释放开可以使用内部类进行测试)

    
    import com.alibaba.excel.EasyExcel;
    import com.alibaba.excel.metadata.Head;
    import com.alibaba.excel.write.merge.AbstractMergeStrategy;
    import org.apache.poi.ss.usermodel.Cell;
    import org.apache.poi.ss.usermodel.Sheet;
    import org.apache.poi.ss.util.CellRangeAddress;
    import org.junit.jupiter.api.Assertions;
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.Test;
    
    import java.io.File;
    import java.util.*;
    
    /**
     * 功能描述:easyExcel单元格导出合并测试类,
     *
     * @author SXT
     * @version 1.0
     * @date 2024/3/8 20:56
     */
    public class EasyExcelTest {
    
        /** excel表头 */
        private List<List<String>> head;
    
        /** excel内容 */
        private List<List<Object>> data;
    
        @Test
        public void testMergeCell(){
            File file = new File("C:\\Users\\sxtvv\\Desktop\\testExcel合并.xlsx");
            EasyExcel.write(file)
                    .head(head)
                    .sheet()
                    // 开启相等值 列合并,行合并,从行索引1(excel中第二行)开始合并, 指定跨行合并的列索引
                    //.registerWriteHandler(new MergeCellStrategyHandler(true, true, 1, Set.of(0, 2, 4, 5)))
    
                    // 开启相等值 列合并,从行索引1(excel中第二行)开始合并
                    //.registerWriteHandler(new MergeCellStrategyHandler(true, 1))
    
                    // 开启相等值 行合并,从行索引1(excel中第二行)开始合并, 指定跨行合并的列索引
                    .registerWriteHandler(new MergeCellStrategyHandler(true, 1, Set.of(0, 2, 4, 5)))
                    .doWrite(data);
            System.out.println("导出成功");
    
        }
    
        @BeforeEach
        public void buildHead(){
            List<List<String>> head = new ArrayList<>();
            head.add(List.of("字段1"));
            head.add(List.of("字段2"));
            head.add(List.of("字段3"));
            head.add(List.of("字段4"));
            head.add(List.of("字段5"));
            head.add(List.of("字段6"));
            this.head = head;
        }
    
        @BeforeEach
        public void buildData(){
            List<List<Object>> data = new ArrayList<>();
            Set<Integer> column = Set.of(2, 4, 5);
            Set<Integer> row = Set.of(2,3, 6,7,8);
            // 重复
            int repeat = 2;
            for (int i = 0; i < 10; i++) {
                List<Object> el = new ArrayList<>(6);
                if (row.contains(i)) {
                    el.add("相同");
                    el.add("测试-1");
                    el.add("相同");
                    el.add("测试-" + i);
                    el.add("测试-" + i);
                    el.add("测试-" + i);
                }else {
                    for (int j = 0; j <6; j++) {
                        if (column.contains(j)) {
                            el.add("相同");
                        }else {
                            el.add("测试" + (i + 1) + "-" + (j + 1));
                        }
                    }
                }
                data.add(el);
            }
            this.data = data;
        }
    
        /**
         * 规则: 优先合并列,再合并行
         */
        //static class MergeCellStrategyHandler extends AbstractMergeStrategy {
        //    /**
        //     * 相同列合并
        //     */
        //    private boolean alikeColumn;
        //
        //    /**
        //     * 相同行合并
        //     */
        //    private boolean alikeRow;
        //
        //    /** 开始进行合并的行index */
        //    private int rowIndex;
        //
        //    /** 跨行合并的列index */
        //    private Set<Integer> columns;
        //
        //    private int currentRowIndex = 0;
        //
        //    public MergeCellStrategyHandler(boolean alikeColumn, boolean alikeRow, int rowIndex, Set<Integer> columns){
        //        Assertions.assertNotNull(columns, "指定列跨行合并不能为空");
        //        this.alikeColumn = alikeColumn;
        //        this.alikeRow = alikeRow;
        //        this.rowIndex = rowIndex;
        //        this.columns = columns;
        //    }
        //
        //    /**
        //     * 指定是否进行跨列合并单元格
        //     * @param alikeColumn
        //     * @param rowIndex
        //     */
        //    public MergeCellStrategyHandler(boolean alikeColumn, int rowIndex){
        //        this(alikeColumn, false, rowIndex, new HashSet<>());
        //    }
        //
        //    /**
        //     * 指定是否进行跨行合并单元格
        //     * @param alikeRow
        //     * @param rowIndex
        //     * @param columns
        //     */
        //    public MergeCellStrategyHandler(boolean alikeRow, int rowIndex, Set<Integer> columns){
        //        this(false, alikeRow, rowIndex, columns);
        //    }
        //
        //
        //    @Override
        //    protected void merge(Sheet sheet, Cell cell, Head head, Integer integer) {
        //        int rowId = cell.getRowIndex();
        //        currentRowIndex = rowId == currentRowIndex ? currentRowIndex : rowId;
        //        if (rowIndex > rowId) {
        //            return;
        //        }
        //        int columnId = cell.getColumnIndex();
        //        // 列合并
        //        if (alikeColumn && columnId > 0) {
        //            String currentCellVal = this.getCellVal(cell);
        //            Cell preCell = cell.getRow().getCell(columnId - 1);
        //            String preCellVal = this.getCellVal(preCell);
        //            if (null != currentCellVal && null != preCellVal && !preCellVal.isBlank() && !currentCellVal.isBlank()) {
        //                // 当前单元格内容与上一个单元格内容相等,进行合并处理
        //                if (preCellVal.equals(currentCellVal)) {
        //                    CellRangeAddress rangeAddress = new CellRangeAddress(currentRowIndex, currentRowIndex, columnId - 1, columnId);
        //                    rangeAddress = this.findExistAddress(sheet, rangeAddress, currentCellVal);
        //                    if (null != rangeAddress) {
        //                        sheet.addMergedRegion(rangeAddress);
        //                    }
        //                }
        //            }
        //        }
        //        // 行合并
        //        if (alikeRow && rowIndex < rowId && columns.contains(columnId)) {
        //            String currentCellVal = this.getCellVal(cell);
        //            Cell preCell = sheet.getRow(rowId - 1).getCell(columnId);
        //            String preCellVal = this.getCellVal(preCell);
        //            if (null != currentCellVal && null != preCellVal && !preCellVal.isBlank() && !currentCellVal.isBlank()) {
        //                // 当前单元格内容与上一行单元格内容相等,进行合并处理
        //                if (preCellVal.equals(currentCellVal)) {
        //                    //sheet.validateMergedRegions();
        //                    CellRangeAddress rangeAddress = new CellRangeAddress(currentRowIndex - 1, currentRowIndex, columnId, columnId);
        //                    rangeAddress = this.findExistAddress(sheet, rangeAddress, currentCellVal);
        //                    if (null != rangeAddress) {
        //                        sheet.addMergedRegion(rangeAddress);
        //                    }
        //                }
        //            }
        //        }
        //
        //    }
        //
        //    /**
        //     * 合并单元格地址范围,发现存在相同的地址则进行扩容合并
        //     *
        //     * @param isColumn       true:跨列合并 false:跨行合并
        //     * @param sheet
        //     * @param rangeAddress   :
        //     * @param currentVal 当前单元格中的值
        //     * @return
        //     */
        //    private CellRangeAddress findExistAddress(Sheet sheet, CellRangeAddress rangeAddress, String currentVal) {
        //        List<CellRangeAddress> mergedRegions = sheet.getMergedRegions();
        //        int existIndex = 0;
        //        Map<Integer, CellRangeAddress> existIdexMap = new LinkedHashMap<>();
        //        if (null != mergedRegions && !mergedRegions.isEmpty()) {
        //            //验证当前合并的单元格是否存在重复(fixme 重复问题待处理!!!)
        //            for (CellRangeAddress mergedRegion : mergedRegions) {
        //                if (mergedRegion.intersects(rangeAddress)) {
        //                    existIdexMap.put(existIndex, mergedRegion);
        //                }
        //                existIndex++;
        //            }
        //        }
        //        if (existIdexMap.isEmpty()) {
        //            return rangeAddress;
        //        }
        //        List<Integer> existIndexList = new ArrayList<>(existIdexMap.size());
        //        for (Map.Entry<Integer, CellRangeAddress> addressEntry : existIdexMap.entrySet()) {
        //            CellRangeAddress exist = addressEntry.getValue();
        //            // 自动进行单元格合并处理
        //            int firstRow = rangeAddress.getFirstRow();
        //            int lastRow = rangeAddress.getLastRow();
        //            int firstColumn = rangeAddress.getFirstColumn();
        //            int lastColumn = rangeAddress.getLastColumn();
        //
        //            int firstRow1 = exist.getFirstRow();
        //            int lastRow1 = exist.getLastRow();
        //            int firstColumn1 = exist.getFirstColumn();
        //            int lastColumn1 = exist.getLastColumn();
        //            // 跨行合并 最后一列相等, 行不相等
        //            if (lastRow > lastRow1 && lastColumn == lastColumn1) {
        //                // 检查进行跨行合并的单元格是否已经存在跨列合并
        //                if (lastColumn > 0 && firstColumn1 != lastColumn1) {
        //                    // 获取当前单元格的前一列单元格
        //                    String cellVal = this.getCellVal(sheet.getRow(lastRow).getCell(lastColumn - 1));
        //                    if (null != cellVal && cellVal.equals(currentVal)) {
        //                        exist.setLastRow(lastRow);
        //                    }
        //                } else {
        //                    exist.setLastRow(lastRow);
        //                }
        //                rangeAddress = exist;
        //                existIndexList.add(addressEntry.getKey());
        //            }
        //
        //            // 跨列合并 行相等,列不相等
        //            if (lastColumn > lastColumn1 && firstRow == firstRow1 ) {
        //                exist.setLastColumn(lastColumn);
        //                rangeAddress = exist;
        //                existIndexList.add(addressEntry.getKey());
        //            }
        //        }
        //        // 移除已经存在且冲突的合并数据
        //        if (existIndexList.isEmpty()) {
        //            rangeAddress = null;
        //        }else {
        //            sheet.removeMergedRegions(existIdexMap.keySet());
        //        }
        //        return rangeAddress;
        //    }
        //
        //    private String getCellVal(Cell cell) {
        //        String val = null;
        //        try {
        //            val = cell.getStringCellValue();
        //        }catch (Exception e){
        //            System.out.printf("读取单元格内容失败:行%d 列%d %n", (cell.getRowIndex() + 1), (cell.getColumnIndex() + 1));
        //        }
        //        return val;
        //    }
        //}
    
    }
    
    
  2. 使用easyexce导出excel并进合并单元格可以直接实现CellWriteHandler接口进行单元格合并,也可以继承AbstractMergeStrategy类实现抽象方法merge()进行,下列代码使用继承的方式显示单元格合并(核心类)

    
    import com.alibaba.excel.metadata.Head;
    import com.alibaba.excel.write.merge.AbstractMergeStrategy;
    import org.apache.poi.ss.usermodel.Cell;
    import org.apache.poi.ss.usermodel.Sheet;
    import org.apache.poi.ss.util.CellRangeAddress;
    
    import java.util.*;
    
    /**
     * 功能描述:规则: 优先合并列,再合并行
     *
     * @author SXT
     * @version 1.0
     * @date 2024/3/9 15:12
     */
    public class MergeCellStrategyHandler extends AbstractMergeStrategy {
        /**
         * 相同列合并
         */
        private boolean alikeColumn;
    
        /**
         * 相同行合并
         */
        private boolean alikeRow;
    
        /** 开始进行合并的行index */
        private int rowIndex;
    
        /** 跨行合并的列index */
        private Set<Integer> columns;
    
        private int currentRowIndex = 0;
    
        /**
         * 构造方法,指定合并方式
         * @param alikeColumn
         * @param alikeRow
         * @param rowIndex
         * @param columns
         */
        public MergeCellStrategyHandler(boolean alikeColumn, boolean alikeRow, int rowIndex, Set<Integer> columns){
            this.alikeColumn = alikeColumn;
            this.alikeRow = alikeRow;
            this.rowIndex = rowIndex;
            this.columns = columns;
        }
    
        /**
         * 指定是否进行跨列合并单元格
         * @param alikeColumn
         * @param rowIndex
         */
        public MergeCellStrategyHandler(boolean alikeColumn, int rowIndex){
            this(alikeColumn, false, rowIndex, new HashSet<>());
        }
    
        /**
         * 指定是否进行跨行合并单元格
         * @param alikeRow
         * @param rowIndex
         * @param columns
         */
        public MergeCellStrategyHandler(boolean alikeRow, int rowIndex, Set<Integer> columns){
            this(false, alikeRow, rowIndex, columns);
        }
    
    
        @Override
        protected void merge(Sheet sheet, Cell cell, Head head, Integer integer) {
            int rowId = cell.getRowIndex();
            currentRowIndex = rowId == currentRowIndex ? currentRowIndex : rowId;
            if (rowIndex > rowId) {
                return;
            }
            int columnId = cell.getColumnIndex();
            // 列合并
            if (alikeColumn && columnId > 0) {
                String currentCellVal = this.getCellVal(cell);
                Cell preCell = cell.getRow().getCell(columnId - 1);
                String preCellVal = this.getCellVal(preCell);
                if (null != currentCellVal && null != preCellVal && !preCellVal.isBlank() && !currentCellVal.isBlank()) {
                    // 当前单元格内容与上一个单元格内容相等,进行合并处理
                    if (preCellVal.equals(currentCellVal)) {
                        CellRangeAddress rangeAddress = new CellRangeAddress(currentRowIndex, currentRowIndex, columnId - 1, columnId);
                        rangeAddress = this.findExistAddress(sheet, rangeAddress, currentCellVal);
                        if (null != rangeAddress) {
                            sheet.addMergedRegion(rangeAddress);
                        }
                    }
                }
            }
            // 行合并
            if (alikeRow && rowIndex < rowId && columns.contains(columnId)) {
                String currentCellVal = this.getCellVal(cell);
                Cell preCell = sheet.getRow(rowId - 1).getCell(columnId);
                String preCellVal = this.getCellVal(preCell);
                if (null != currentCellVal && null != preCellVal && !preCellVal.isBlank() && !currentCellVal.isBlank()) {
                    // 当前单元格内容与上一行单元格内容相等,进行合并处理
                    if (preCellVal.equals(currentCellVal)) {
                        //sheet.validateMergedRegions();
                        CellRangeAddress rangeAddress = new CellRangeAddress(currentRowIndex - 1, currentRowIndex, columnId, columnId);
                        rangeAddress = this.findExistAddress(sheet, rangeAddress, currentCellVal);
                        if (null != rangeAddress) {
                            sheet.addMergedRegion(rangeAddress);
                        }
                    }
                }
            }
    
        }
    
        /**
         * 合并单元格地址范围,发现存在相同的地址则进行扩容合并
         *
         * @param sheet
         * @param rangeAddress  单元格合并地址
         * @param currentVal 当前单元格中的值
         * @return
         */
        private CellRangeAddress findExistAddress(Sheet sheet, CellRangeAddress rangeAddress, String currentVal) {
            List<CellRangeAddress> mergedRegions = sheet.getMergedRegions();
            int existIndex = 0;
            Map<Integer, CellRangeAddress> existIdexMap = new LinkedHashMap<>();
            if (null != mergedRegions && !mergedRegions.isEmpty()) {
                //验证当前合并的单元格是否存在重复
                for (CellRangeAddress mergedRegion : mergedRegions) {
                    if (mergedRegion.intersects(rangeAddress)) {
                        existIdexMap.put(existIndex, mergedRegion);
                    }
                    existIndex++;
                }
            }
            if (existIdexMap.isEmpty()) {
                return rangeAddress;
            }
            List<Integer> existIndexList = new ArrayList<>(existIdexMap.size());
            for (Map.Entry<Integer, CellRangeAddress> addressEntry : existIdexMap.entrySet()) {
                CellRangeAddress exist = addressEntry.getValue();
                // 自动进行单元格合并处理
                int firstRow = rangeAddress.getFirstRow();
                int lastRow = rangeAddress.getLastRow();
                int firstColumn = rangeAddress.getFirstColumn();
                int lastColumn = rangeAddress.getLastColumn();
    
                int firstRow1 = exist.getFirstRow();
                int lastRow1 = exist.getLastRow();
                int firstColumn1 = exist.getFirstColumn();
                int lastColumn1 = exist.getLastColumn();
                // 跨行合并 最后一列相等, 行不相等
                if (lastRow > lastRow1 && lastColumn == lastColumn1) {
                    // 检查进行跨行合并的单元格是否已经存在跨列合并
                    if (lastColumn > 0 && firstColumn1 != lastColumn1) {
                        // 获取当前单元格的前一列单元格
                        String cellVal = this.getCellVal(sheet.getRow(lastRow).getCell(lastColumn - 1));
                        if (null != cellVal && cellVal.equals(currentVal)) {
                            exist.setLastRow(lastRow);
                        }
                    } else {
                        exist.setLastRow(lastRow);
                    }
                    rangeAddress = exist;
                    existIndexList.add(addressEntry.getKey());
                }
    
                // 跨列合并 行相等,列不相等
                if (lastColumn > lastColumn1 && firstRow == firstRow1 ) {
                    exist.setLastColumn(lastColumn);
                    rangeAddress = exist;
                    existIndexList.add(addressEntry.getKey());
                }
            }
            // 移除已经存在且冲突的合并数据
            if (existIndexList.isEmpty()) {
                rangeAddress = null;
            }else {
                sheet.removeMergedRegions(existIdexMap.keySet());
            }
            return rangeAddress;
        }
    
        /**
         * 获取单元格中的内容
         * @param cell
         * @return
         */
        private String getCellVal(Cell cell) {
            String val = null;
            try {
                val = cell.getStringCellValue();
            }catch (Exception e){
                System.out.printf("读取单元格内容失败:行%d 列%d %n", (cell.getRowIndex() + 1), (cell.getColumnIndex() + 1));
            }
            return val;
        }
    }
    

标签:sheet,int,EasyExcel,单元格,合并,跨列,&&,rangeAddress
From: https://www.cnblogs.com/qiushuiyu-108/p/18062852

相关文章

  • 用lazarus编写的类RichView显示控件初步支持markdown格式的表格,并增加单元格字体颜色
    用lazarus编写的类RichView显示控件初步支持markdown格式的表格,并增加单元格字体颜色等功能,可在信创电脑使用,功能慢慢添加中。github:https://github.com/szlbz/QFComponent其中图像格式支持:bmp,jpg,png等 除以上格式外,还支持单、双分割线等......
  • 解决easyexcel合并单元格数组求和重复问题
    背景EasyExcel(根据条件动态合并单元格的重复数据))_Violet-CSDN博客_easyexcel动态合并单元格现有的订单导出是使用的easyExcel完成的.对于相同单元格的合并是自定义的策略,问题是对于重复单元格的值会合并,表格求和时值会虚高现需要对合并格做修改,做到值只有一个。思路sheet合并......
  • EasyExcel合并行处理并优化
    业务场景由于业务需要导出如下图中订单数据和订单项信息,而一个订单对应多个订单项,所以会涉及到自定义合并行 1.简单处理项目使用的EasyExcel,经查找发现Excel种有个AbstractMergeStrategy抽象类,可以用于合并单元格。于是先简单的写一个工具类实现根据数据自定义合并单元行,基本......
  • 把图片插在excel单元格里
    本文以WPS专业版举例1、如下图,选择对应的单元格 2、通过“插入”菜单插入图片或直接粘贴图片3、如下图,对插入的图片点击鼠标右键,选择“切换为嵌入单元格图片”4、完成 ......
  • Npoi操作Excel单元格合并
    publicasyncTask<byte[]>ExportNewReportByQuotationId(GuidquotationId){//stringsql=@$"select""Id""asModelId,(q.qq).keyaskey,(q.qq).valueasmyValuefrom(withaas(select""Id"&q......
  • WPF DataGrid下的单元格嵌入CheckBox列表
    <DataGridWidth="auto"Height="auto"AutoGenerateColumns="False"CanUserAddRows="False"GridLinesVisibility="All">        <DataGrid.Columns><DataGridTempla......
  • Java中使用Jsoup实现网页内容爬取与Html内容解析并使用EasyExcel实现导出为Excel文件
    场景Pythont通过request以及BeautifulSoup爬取几千条情话:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/87348030Node-RED中使用html节点爬取HTML网页资料之爬取Node-RED的最新版本:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/124182289Jsoup......
  • antd 单元格合并处理
    实现效果代码tableData为Table的数据constmergeCells=(text,dataSource,index,key)=>{//上一行该列数据是否一样if(index!==0&&text===dataSource[index-1][key]){return0}letrowSpan=1//判断下一行是否相等f......
  • SharePoint Online 中Excel引用另一个Excel中的单元格
    前言最近,碰到一个需求,用户想要在SharePointOnline中从一个Excel文件引用另一个Excel文件的内容,所以就研究了一下。正文1.建一个测试的Excel文件,随便写点东西,如下图:2.新建另一个Excel,用来引用上一个Excel文件,如下图:3.在第一个Excel中的文件,选中单......
  • 关于easyExcel解析未添加@ExcelProperty报错问题分析
    在一次做辅料商品导出列表的需求,并且上线之后发现,怎么商品列表的导出没有反应,一看日志,发现报错了:这里新加了两个字段用于做转换使用。因为之前很少用easyExcel,所以以为只要不加@ExcelProperty,easyExcel就不会去解析字段,没想到easyExcel还是去做了解析。源码分析通过上面的......