基于Java POI实现动态列Excel导出的通用方法

 更新时间:2025年07月14日 08:42:23   作者:自由的疯  
在企业级开发中,Excel导出功能是常见需求,当面对前端动态传参、列数不确定的场景时,编写通用的动态列导出方法能显著提升开发效率,本文将结合Java POI框架,详细解析如何实现支持多级表头、动态列求和及合并单元格的Excel导出功能,并提供完整代码示例与使用说明

一、核心功能特性

1. 动态列处理

  • 支持从前端接收​​List<String>​​​类型的列名集合(​​cellList​​​),结合固定列数组(​​strCloumnAry​​)动态拼接最终列集合
  • 使用​​LinkedHashMap​​维护列顺序,确保导出列与传入顺序一致

2. 多级表头支持

  • 通过​​headerNum​​参数控制表头层级(1-3 级)
  • 表头名称通过​​||​​​分隔(如​​"船舶信息||完船日期||吨位"​​),自动解析为多级结构

3. 数据统计功能

  • 自动识别数值型列(​​Number​​​类型),生成​​totalMap​​存储列求和结果
  • 支持在导出数据末尾添加 "合计" 行,并合并单元格显示

4. 样式与布局优化

  • 统一设置单元格边框、居中对齐、字体大小
  • 自动调整列宽适应内容
  • 多级表头行合并相同标题单元格,提升可读性

二、关键代码解析

1. 列集合初始化

LinkedHashMap<String, Integer> allColumn = new LinkedHashMap<>();
// 先添加固定列
for (int i = 0; i < strCloumnAry.length; i++) {
    allColumn.putIfAbsent(strCloumnAry[i], i);
}
// 再添加动态列(避免重复)
int i = strCloumnAry.length;
for (String key : cellList) {
    if (!allColumn.containsKey(key)) {
        allColumn.put(key, i++);
    }
}
  • 使用​​LinkedHashMap​​保持顺序,固定列在前,动态列在后
  • 通过​​putIfAbsent​​避免重复列名导致的索引冲突

2. 多级表头生成

if (headerNum == 2) { // 二级表头处理
    for (String key : allColumn.keySet()) {
        String[] parts = key.split("\|\|"); // 按||拆分
        if (parts.length == 2) {
            // 一级表头行
            Cell cell1 = headerRow1.createCell(allColumn.get(key));
            cell1.setCellValue(parts[0]);
            // 二级表头行
            Cell cell2 = headerRow2.createCell(allColumn.get(key));
            cell2.setCellValue(parts[1]);
        }
    }
}
  • 通过​​split("\|\|")​​解析多级表头名称
  • 根据​​headerNum​​创建对应行数的表头行(1-3 级)
  • 同一列的多级表头单元格共享相同列索引

3. 数据行与合计行

// 写入数据行
int row = headerNum; // 表头行下方开始写数据
for (Map<String, Object> data : datas) {
    Row dataRow = sheet.createRow(row++);
    for (Map.Entry<String, Integer> entry : allColumn.entrySet()) {
        Cell cell = dataRow.createCell(entry.getValue());
        cell.setCellValue(data.get(entry.getKey()) != null ? data.get(entry.getKey()).toString() : "");
    }
}

// 写入合计行
Row totalRow = sheet.createRow(row);
totalRow.createCell(0).setCellValue("合计");
for (Map.Entry<String, Object> entry : totalMap.entrySet()) {
    int colIndex = allColumn.get(entry.getKey());
    Cell cell = totalRow.createCell(colIndex);
    cell.setCellValue(entry.getValue() != null ? entry.getValue().toString() : "");
}
// 合并合计行标题单元格
sheet.addMergedRegion(new CellRangeAddress(row, row, 0, maxSp));
  • ​totalMap​​通过遍历数据行自动计算数值列总和
  • 合计行标题 "合计" 通过​​CellRangeAddress​​合并多个列单元格
  • ​maxSp​​变量动态计算需要合并的列范围

4. 单元格样式设置

// 创建通用样式
CellStyle cellStyle = workbook.createCellStyle();
cellStyle.setAlignment(HorizontalAlignment.CENTER);
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
cellStyle.setBorderTop(BorderStyle.THIN);
cellStyle.setBorderBottom(BorderStyle.THIN);
cellStyle.setBorderLeft(BorderStyle.THIN);
cellStyle.setBorderRight(BorderStyle.THIN);

// 表头字体设置
Font headerFont = workbook.createFont();
headerFont.setFontHeightInPoints((short) 10);
cellStyle.setFont(headerFont);
  • 统一设置水平 / 垂直居中对齐
  • 添加细边框样式
  • 表头使用 10 号字体

三、使用示例

1. 方法参数说明

参数名类型说明
responseHttpServletResponseServlet 响应对象,用于输出文件流
datasList<Map<String,Object>>导出数据集合,每个 Map 代表一行数据
cellListList动态列名集合(如前端勾选的列)
baseFileNameString基础文件名(不含时间戳)
strAryString[]固定列显示名称数组(与 strCloumnAry 对应)
strCloumnAryString[]固定列字段名数组(如数据库字段名)
headerNumint表头层级(1-3 级)

2. 调用示例

// 假设前端传入动态列名为["price","quantity"]
List<String> cellList = Arrays.asList("price", "quantity");
// 固定列字段名与显示名
String[] strCloumnAry = {"name", "date"};
String[] strAry = {"商品名称", "日期"};

// 构造模拟数据
List<Map<String, Object>> datas = new ArrayList<>();
Map<String, Object> data1 = new HashMap<>();
data1.put("name", "苹果");
data1.put("date", "2023-10-01");
data1.put("price", 5.99);
data1.put("quantity", 100);
datas.add(data1);

// 调用导出方法(二级表头示例)
exportDynamicExcel(response, datas, cellList, "商品销售报表", strAry, strCloumnAry, 2);

3. 表头命名规范

多级表头通过​​||​​分隔,如:

  • 一级表头:​​"销售额"​
  • 二级表头:​​"季度数据||销售额"​
  • 三级表头:​​"年度汇总||季度数据||销售额"​

四、优化与扩展建议

1. 类型适配优化

当前代码仅处理​​Number​​类型数值求和,可扩展支持:

  • ​String​​类型数值转换(需校验格式)
  • ​LocalDate​​​/​​LocalDateTime​​类型日期格式化显示

2. 样式扩展

  • 添加条件格式(如数值超过阈值时标红)
  • 支持不同背景色区分奇偶行
  • 表头行添加自动筛选功能

3. 性能优化

  • 大数据量场景可改用​​SXSSFWorkbook​​(基于磁盘缓存的流式处理)
  • 合并单元格操作可批量处理,减少​​sheet.addMergedRegion​​调用次数

4. 错误处理增强

  • 添加参数校验(如​​cellList​​​与​​strCloumnAry​​重复校验)
  • 提供更友好的异常提示信息(如字段名不存在)

五、总结

本文提供的动态列 Excel 导出方法通过灵活的参数设计,实现了:

  • 动态列与固定列的混合展示
  • 1-3 级多级表头的自动解析
  • 数值列自动求和与合计行生成
  • 统一的单元格样式与布局优化

适用于需要根据用户选择动态展示列的管理系统(如数据报表、权限控制场景)。实际使用中可根据业务需求进一步扩展类型适配、样式定制等功能,提升导出文件的实用性与美观性。

以上就是基于Java POI实现动态列Excel导出的通用方法的详细内容,更多关于Java POI动态列Excel导出的资料请关注脚本之家其它相关文章!

相关文章

  • 10分钟带你理解Java中的弱引用

    10分钟带你理解Java中的弱引用

    这篇文章将带大家快速理解Java中弱引用,文章介绍的很详细,对大家学习Java很有帮助哦,有需要的可以参考借鉴。
    2016-08-08
  • java远程连接Linux执行命令的3种方式完整代码

    java远程连接Linux执行命令的3种方式完整代码

    在一些Java应用程序中需要执行一些Linux系统命令,例如服务器资源查看、文件操作等,这篇文章主要给大家介绍了关于java远程连接Linux执行命令的3种方式,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-06-06
  • MyBatis执行SQL的两种方式小结

    MyBatis执行SQL的两种方式小结

    本文主要介绍了MyBatis执行SQL的两种方式小结,主要包括SqlSession 发送SQL和SqlSession获取Mapper接口,通过Mapper接口发送SQL,具有一定的参考价值,感兴趣的可以了解一下
    2023-10-10
  • 教您如何3分钟快速搞定EasyExcel导入与导出功能

    教您如何3分钟快速搞定EasyExcel导入与导出功能

    对于EasyExcel库,我们可以使用它来实现数据的导入和导出,下面这篇文章主要给大家介绍了关于如何3分钟快速搞定EasyExcel导入与导出功能的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-01-01
  • Java向kettle8.0传递参数的方式总结

    Java向kettle8.0传递参数的方式总结

    介绍了如何在Kettle中传递参数到转换和作业中,包括设置全局properties、使用TransMeta和JobMeta的parameterValue,以及通过EL表达式获取参数值
    2025-01-01
  • Java+swing实现抖音上的表白程序详解

    Java+swing实现抖音上的表白程序详解

    这篇文章主要为大家详细介绍了如何利用Java swing实现抖音上的表白程序,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2022-06-06
  • 详解SpringBoot下文件上传与下载的实现

    详解SpringBoot下文件上传与下载的实现

    这篇文章主要介绍了SpringBoot下文件上传与下载的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-05-05
  • SpringBoot自定义注解开发指南

    SpringBoot自定义注解开发指南

    在开发SpringBoot程序的过程中,有可能与其他业务系统进行对接开发,获取封装公共的API接口等等,下面这篇文章主要给大家介绍了关于SpringBoot自定义注解的相关资料,需要的朋友可以参考下
    2022-06-06
  • Java FutureTask类使用案例解析

    Java FutureTask类使用案例解析

    这篇文章主要介绍了Java FutureTask类使用案例解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值析,需要的朋友可以参考下
    2020-04-04
  • 解决SpringBoot项目中log4j与logback的Jar包冲突问题

    解决SpringBoot项目中log4j与logback的Jar包冲突问题

    这篇文章主要给大家介绍了解决SpringBoot项目中log4j与logback的Jar包冲突问题,文中有详细的解决方法和冲突的原因,有遇到相同问题的朋友可以参考阅读本文
    2023-10-10

最新评论