POI动态合并下载文件的单元格

7 篇文章 0 订阅
7 篇文章 0 订阅

最近在做图表报表相关的开发时,遇到了一个问题:页面上展示的Excel在下载打开后发现同一类别下的单元格没有合并,是一行一行的状态:

而预计的效果是要和页面上展示的一样:

因为这块展示功能的数据是从数据库中取出来在页面动态展示的,不能确保每次展示的数据都是同一种合并情况,所以想要在后端写死不可能了,接下来分析一下下载合并的需求:

把相同疑点编号的数据行进行合并,合并0~6以及第11列的相同行数据,要求合并的数据必须是在同一疑点下的,即使不同疑点下对应的其他数据列的数据相同也不能合并,了解到以上需求后,接下来就可以开干了。

思路:因为疑点编号是判断合并的依据,因此首先进行第一列的合并,接下来的列都以第一列为准进行合并,下边是对第一列所进行的处理:

public static void mergeSameColumn(Sheet sheet, int column) {
        //总行数
        int totalRows = sheet.getLastRowNum();
        //首次出现行数
        int firstRow = 0;
        //连续最终出现行数
        int lastRow = 0;
        boolean flag = false;
        List<String> list = new ArrayList<>();
        for (int i = 0; i < totalRows; i++) {
            String curRowCell = sheet.getRow(i).getCell(column).getStringCellValue();
            list.add(curRowCell);
        }
        System.out.println(list.toString());
        for(int j = 0;j < totalRows; j++ ) {
            if ((j+1) <= totalRows-1) {
                if (list.get(j).equals(list.get(j + 1))) {
                    if (!flag) {
                        firstRow = j;
                    }
                    lastRow = j + 1;
                    flag = true;
                } else if (!list.get(j).equals(list.get(j + 1))) {
                    if (flag) {
                        lastRow = j;
                        if (lastRow > firstRow) {
                            sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, column, column));
                            flag = false;
                        }
                    }
                }
                if (((j + 1) == totalRows) && (lastRow > firstRow)) {
                    sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, column, column));
                }
            }
        }
    }

思路是:初始化首次出现的行数和要合并连续出现的最终行数,这里column参数取0即可,接着拿到第一列值的集合,然后遍历第一列的值(集合),记录值首次出现的位置,直到值不同的时候就把集合的对应关系转换为行的对应关系进行行合并,依次遍历。

第一列处理好后,就可以得到所有第一列的合并单元格,进而拿到所有合并单元格的起始行和最终行,其他行均以这个合并单元格的集合为准,代码如下:

/**
     * 合并指定Excel sheet页、指定列中连续相同内容的单元格
     * @param sheet  Excel sheet
     * @param column 指定列
     */
    public static void mergeSpecifiedColumn(List<String> combineCell,Sheet sheet, int column) {
        for(int k = 0;k<combineCell.size();k++){
            List<Integer> integers = analysisResult(combineCell.get(k));
            String lastRowCellContent = sheet.getRow(integers.get(0)).getCell(column).getStringCellValue();
            sheet.addMergedRegion(new CellRangeAddress(integers.get(0), integers.get(1), column, column));
            //Set当前单元格的值
            Cell cell = sheet.getRow(integers.get(0)).getCell(column);
            cell.setCellValue(lastRowCellContent);
        }
    }
    //获取合并单元格集合
    public static List<CellRangeAddress> getCombineCellList(Sheet sheet)
    {
        List<CellRangeAddress> list = new ArrayList<>();
        //获得一个 sheet 中合并单元格的数量
        int sheetmergerCount = sheet.getNumMergedRegions();
        //遍历所有的合并单元格
        for(int i = 0; i<sheetmergerCount;i++)
        {
            //获得合并单元格保存进list中
            CellRangeAddress ca = sheet.getMergedRegion(i);
            list.add(ca);
        }
        return list;
    }

    /**
     * 判断cell是否为合并单元格,是的话返回合并行数
     * @param listCombineCell 获取的合并区域列表
     */
    public  static List<String> isCombineCell(List<CellRangeAddress> listCombineCell){
        int firstR = 0;
        int lastR = 0;
        List<String> result=new ArrayList<>();
        for(CellRangeAddress ca:listCombineCell)
        {
            //获取到固定第一列合并单元格的起始行, 结束行
            firstR = ca.getFirstRow();
            lastR = ca.getLastRow();
            result.add(firstR+":"+lastR);
            //String value = String.join(":",String.valueOf(firstR),String.valueOf(lastR));
            //result.add(value);
        }
        return result;
    }
    //解析获取的合并单元格
    public static List<Integer> analysisResult(String results){
        String[] splitValue = results.split(":");
        List<Integer> list = new ArrayList<>();
        int counterFirst = Integer.parseInt(splitValue[0]);
        int counterLast = Integer.parseInt(splitValue[1]);
        list.add(counterFirst);
        list.add(counterLast);
        return list;
    }

原本mergeSpecifiedColumn()方法中是要进行二次的循环处理判断连续相同值的合并单元格的值,因为考虑到值的合不合并只与第一列有关,故而直接取解析合并单元格的起始和最终行进行合并,免去了不少麻烦。

最后,在写好的导出代码下添加以下代码即可,我把获取合并单元格的语句专门放在了处理逻辑中去,这样保证了合并多列的连续相同单元格时不会获取到除第一列以外的合并单元格,方便其他列进行复用合并单元格的起始行和最终行,代码侵入性和通用型都很不错,如下:

                Sheet sheet = workbook.getSheet(sheetName);
                if(null != sheet) {
                    mergeSameColumn(sheet, 0);
                    //获取所有合并单元格
                    List<CellRangeAddress> combineCellList = ExpendResultQueryBOImpl.getCombineCellList(sheet);
                    //返回合并区域列表
                    List<String> combineCell = ExpendResultQueryBOImpl.isCombineCell(combineCellList);
                    mergeSpecifiedColumn(combineCell, sheet, 1);
                    mergeSpecifiedColumn(combineCell, sheet, 2);
                    mergeSpecifiedColumn(combineCell, sheet, 3);
                    mergeSpecifiedColumn(combineCell, sheet, 4);
                    mergeSpecifiedColumn(combineCell, sheet, 5);
                    mergeSpecifiedColumn(combineCell, sheet, 6);
                    mergeSpecifiedColumn(combineCell, sheet, 10);
                    mergeSpecifiedColumn(combineCell, sheet, 11);
                }

导出合并效果:

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值