JAVA 使用POI实现单元格行合并生成

预期效果

maven引用

xml 复制代码
 <dependency>
     <groupId>org.apache.poi</groupId>
     <artifactId>poi-ooxml</artifactId>
     <version>5.2.2</version>
 </dependency>

Java代码实现

功能实现

java 复制代码
    private boolean callExcel(List<MColumnValueVo> mColumnValueVos,String name){
        SXSSFWorkbook workbook = new SXSSFWorkbook(100);
        Sheet sheet = workbook.createSheet("明细信息");

        //设置单元格居中
        CellStyle cellStyle = workbook.createCellStyle();
        //设置边框样式
        cellStyle.setAlignment(HorizontalAlignment.CENTER);//左右居中
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);// 上下居中
        String[] headers1 = {"号码","名称"};//2个
        String[] mxHeaders = {"行号","行性质"};//2个
        String[] headers2 = {"合计金额","状态"};//2个

        Row headerRow = sheet.createRow(0); // 创建表头行,索引为0
        for (int i = 0; i < headers1.length; i++) {//headers1表格合并并赋值
            Cell cell = headerRow.createCell(i);//创建列
            cell.setCellStyle(cellStyle);//设置表格样式
            cell.setCellValue(headers1[i]);//表格赋值内容
            sheet.addMergedRegion(new CellRangeAddress(0, 1, i, i));//表格的合并,先填内容在合并且合并保留内容为合并的第一行内容
        }

        int firstCol = headers1.length+mxHeaders.length; // 从第一行开始填充数据
        int hlt = firstCol+headers2.length;// 合计列
        // 自动调整列宽(可选)
        for (int colNum = 0; colNum < hlt; colNum++) {
            sheet.setColumnWidth(colNum, 256 * 25);
        }
        //发票明细表格合并并赋值
        Row two = sheet.getRow(1);
        if (two == null) {
            two = sheet.createRow(1);
        }
        sheet.addMergedRegion(new CellRangeAddress(0, 0, headers1.length, firstCol-1));
        Cell mergedCell = headerRow.createCell(headers1.length); // 合并后的单元格左上角
        mergedCell.setCellStyle(cellStyle);
        mergedCell.setCellValue("明细");

        for (int i = 0; i < mxHeaders.length; i++) {//明细表头赋值
            Cell cell = two.createCell(i + headers1.length);
            cell.setCellStyle(cellStyle);
            cell.setCellValue(mxHeaders[i]);
        }

        for (int i = 0; i < headers2.length; i++) {
            Cell cell = headerRow.createCell(i + firstCol);
            cell.setCellStyle(cellStyle);
            cell.setCellValue(headers2[i]);
            sheet.addMergedRegion(new CellRangeAddress(0, 1, firstCol+i, firstCol+i));
        }


        // 填充数据
        int lastRowIndex = 2; //记录最后行位置
        for (MColumnValueVo vo : mColumnValueVos) {
            // 创建行
            Row row = sheet.createRow(lastRowIndex);
            if(vo.getMxQueryOuts()!=null){//添加发票明细
                for (int i = 0; i < vo.getMxQueryOuts().size(); i++) {
                    MMColumnValueVo mxVo = vo.getMxQueryOuts().get(i);
                    Row row1 = sheet.getRow(lastRowIndex + i);
                    if(row1 == null) {
                        row1 = sheet.createRow(lastRowIndex + i);
                    }
                    for (int j = 0; j < headers2.length; j++) {
                        Cell cell = row1.createCell(headers1.length + j);
                        cell.setCellStyle(cellStyle);
                        cell.setCellValue(getValueFromMMVo(mxVo, j));
                    }
                }
            }
            for (int i = 0; i < headers1.length; i++) {
                Cell cell = row.createCell(i);
                cell.setCellStyle(cellStyle);
                cell.setCellValue(getValueFromMxVo1(vo, i));
                if(vo.getMxQueryOuts()!=null && vo.getMxQueryOuts().size()>1){
                    sheet.addMergedRegion(new CellRangeAddress(lastRowIndex, lastRowIndex+vo.getMxQueryOuts().size()-1, i, i));
                }
            }

            for (int i = 0; i < headers2.length; i++) {
                Cell cell = row.createCell(i + firstCol);
                cell.setCellStyle(cellStyle);
                cell.setCellValue(getValueFromMxVo2(vo, i));
                if(vo.getMxQueryOuts()!=null && vo.getMxQueryOuts().size()>1){
                    sheet.addMergedRegion(new CellRangeAddress(lastRowIndex, lastRowIndex+vo.getMxQueryOuts().size()-1, firstCol+i, firstCol+i));
                }
            }
            if(vo.getMxQueryOuts()==null){
                lastRowIndex++;
            }else {
                lastRowIndex += vo.getMxQueryOuts().size();
            }
            logger.info("lastRowIndex:{}",lastRowIndex);
        }
        // 写入到文件 name:绝对路径并带excel文件名称及后缀
        try (FileOutputStream out = new FileOutputStream(name)) {
            workbook.write(out);
        } catch (IOException e) {
            logger.error("生成明细信息excel表格异常",e);
            return false;
        } finally {
            // 关闭workbook,释放资源
            workbook.dispose();
        }
        return true;
    }

返回内容

java 复制代码
private String getValueFromMxVo1(MMColumnValueVo vo, int colNumMx) {
    switch (colNumMx) {
        case 0: return vo.getLineNo() != null ? vo.getLineNo().toString() : "";
        case 1: return vo.getLineNature();
        default: return "";
    }
}

注: 返回内容都可以按照该种方式

相关推荐
用户2986985301413 小时前
Java HTML 转 Word 完整指南
java·后端
渣哥13 小时前
原来公平锁和非公平锁差别这么大
java
渣哥13 小时前
99% 的人没搞懂:Semaphore 到底是干啥的?
java
J2K14 小时前
JDK都25了,你还没用过ZGC?那真得补补课了
java·jvm·后端
kfyty72514 小时前
不依赖第三方,不销毁重建,loveqq 框架如何原生实现动态线程池?
java·架构
isysc115 小时前
面了一个校招生,竟然说我是老古董
java·后端·面试
道可到18 小时前
Java 反射现代实践速查表(JDK 11+/17+)
java
侃侃_天下18 小时前
最终的信号类
开发语言·c++·算法
道可到19 小时前
Java 反射现代实践指南(JDK 11+ / 17+ 适用)
java
玉衡子19 小时前
九、MySQL配置参数优化总结
java·mysql