功能这么全的excel导出,你确定不需要?

news2024/11/14 13:58:28

欢迎来到我的博客,代码的世界里,每一行都是一个故事


在这里插入图片描述

🎏:你只管努力,剩下的交给时间

🏠 :小破站

功能这么全的excel导出,你确定不需要?

    • 前言
    • Maven坐标
    • HSSFWorkbook、SXSSFWorkbook和XSSFWorkbook的区别
      • 1. HSSFWorkbook
        • 示例:
      • 2. XSSFWorkbook
        • 示例:
      • 3. SXSSFWorkbook
        • 示例:
        • 注意事项:
        • 性能比较:
      • 总结:
    • SXSSFWorkbook相关实现
      • 创建两个sheet
      • 实现单元格合并
      • 基础样式实现
      • 设置固定列
      • 实现列的下拉选项
      • 实现表头过滤
      • 设置合并区域中单元格边框
      • 根据下标填充数据
      • 根据别名填充数据

前言

“导出一个 Excel 文件难吗?可能你已经使用了许多第三方工具来实现这个功能,但今天我要向你介绍 Apache POI。它不仅仅是导出 Excel,它还能让你精确控制每一个单元格的格式、数据类型和样式。想象一下,几行代码就能生成一个定制化的表格!接下来,让我们一起来看看这个工具有多么强大。”

Maven坐标

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.2.3</version>
</dependency>

HSSFWorkbook、SXSSFWorkbook和XSSFWorkbook的区别

HSSFWorkbookXSSFWorkbookSXSSFWorkbook 是 Apache POI 中用于处理不同类型 Excel 文件的三种工作簿对象,它们之间的区别主要体现在对文件格式的支持和性能处理方面。

1. HSSFWorkbook

  • 支持的文件格式:Excel 97-2003(.xls
  • 文件格式限制.xls 文件格式是二进制文件格式,最大支持 65,536 行和 256 列。
  • 内存消耗:所有的 Excel 数据都会加载到内存中,处理大文件时会出现内存不足的情况。
  • 适用场景:适合处理较小的旧版 .xls 文件,当数据量不大时可以使用。
示例:
Workbook workbook = new HSSFWorkbook(); // 创建 .xls 文件

2. XSSFWorkbook

  • 支持的文件格式:Excel 2007 及以上版本(.xlsx
  • 文件格式限制.xlsx 是基于 XML 的文件格式,支持 1,048,576 行和 16,384 列,远大于 .xls 的限制。
  • 内存消耗:和 HSSFWorkbook 类似,所有数据都会加载到内存中。如果数据量很大,可能导致 OutOfMemoryError
  • 适用场景:用于生成或操作较新的 .xlsx 文件,适合数据量较小或中等的场景。
示例:
Workbook workbook = new XSSFWorkbook(); // 创建 .xlsx 文件

3. SXSSFWorkbook

  • 支持的文件格式:Excel 2007 及以上版本(.xlsx
  • 文件格式限制:和 XSSFWorkbook 一样,支持 1,048,576 行和 16,384 列。
  • 内存消耗SXSSFWorkbook 是基于 XSSFWorkbook 的流式处理实现,使用临时文件来存储不常用的行,避免将所有数据加载到内存中。适合处理大数据量的场景。
  • 适用场景:特别适合导出大数据量的 Excel 文件,因为它不会消耗太多内存。默认只保留一定数量的行在内存中,其他行会写入到磁盘的临时文件中。
示例:
Workbook workbook = new SXSSFWorkbook(); // 创建流式写入的 .xlsx 文件
注意事项:
  • 在写入完成后,需要调用 dispose() 方法清理临时文件。
性能比较:
  • HSSFWorkbookXSSFWorkbook 适合较小的数据集,所有内容都保存在内存中,容易导致内存溢出。
  • SXSSFWorkbook 是大数据集的最佳选择,通过使用流式写入机制,有效控制内存使用,避免内存溢出问题。

总结:

  • HSSFWorkbook:处理旧版 .xls 文件,适合小数据量。
  • XSSFWorkbook:处理新版 .xlsx 文件,适合小到中等数据量。
  • SXSSFWorkbook:处理大数据量的 .xlsx 文件,采用流式写入方式节省内存。

SXSSFWorkbook相关实现

创建两个sheet

// 执行两次即可
SXSSFSheet sheet = workbook.createSheet(sheetName);

实现单元格合并

这里对于行合并与列合并都进行讲解

// 创建表头行的方法
private void createHeaderRows(Sheet sheet, Map<String, Object> headers) {
  // 创建第一行,用于存放一级表头
  Row row1 = sheet.createRow(0);
  // 创建第二行,用于存放嵌套表头
  Row row2 = sheet.createRow(1);

  int colIdx = 0; // 定义列索引
  // 遍历表头结构的每个条目
  for (Map.Entry<String, Object> entry : headers.entrySet()) {
    if (entry.getValue() instanceof String) {
      // 如果表头项是字符串类型(单行表头)
      Cell cell = row1.createCell(colIdx); // 在第一行创建单元格
      cell.setCellValue((String) entry.getValue()); // 设置单元格的值为表头项的值
      // 合并单元格,使该单元格占据两行
      sheet.addMergedRegion(new CellRangeAddress(0, 1, colIdx, colIdx));
      colIdx++; // 列索引加1,移动到下一个列位置
    } else if (entry.getValue() instanceof Map) {
      // 如果表头项是Map类型(多行表头)
      Cell cell = row1.createCell(colIdx); // 在第一行创建单元格
      cell.setCellValue(entry.getKey()); // 设置单元格的值为表头项的键(即第一层表头)

      // 将表头项的值转换为Map<String, String>类型,用于表示嵌套的子表头
      Map<String, String> subHeaders = (Map<String, String>) entry.getValue();
      int subColIdx = colIdx; // 定义子列索引,初始值为当前列索引
      // 遍历子表头结构的每个条目
      for (Map.Entry<String, String> subEntry : subHeaders.entrySet()) {
        Cell subCell = row2.createCell(subColIdx); // 在第二行创建单元格
        subCell.setCellValue(subEntry.getValue()); // 设置单元格的值为子表头的值
        subColIdx++; // 子列索引加1,移动到下一个列位置
      }
      // 合并单元格,使第一行的表头项跨越多列(与子表头对应)
      sheet.addMergedRegion(new CellRangeAddress(0, 0, colIdx, subColIdx - 1));
      colIdx = subColIdx; // 更新主列索引,使其指向下一个表头位置
    }
  }
}

基础样式实现

实现水平居中、垂直居中、上边框、下边框、左边框、右边框

/**
     * description: 基础样式创建
     * @param workbook workbook
     * @return org.apache.poi.ss.usermodel.CellStyle
     * @since 2024/9/5
     */
public static CellStyle baseStyle(SXSSFWorkbook workbook) {
  CellStyle style = workbook.createCellStyle();
  // 水平居中
  style.setAlignment(HorizontalAlignment.CENTER);
  // 垂直居中
  style.setVerticalAlignment(VerticalAlignment.CENTER);
  // 上边框
  style.setBorderTop(BorderStyle.THIN);
  // 下边框
  style.setBorderBottom(BorderStyle.THIN);
  // 左边框
  style.setBorderLeft(BorderStyle.THIN);
  // 右边框
  style.setBorderRight(BorderStyle.THIN);
  return style;
}

设置固定列

sheet.createFreezePane(5, 0);

实现列的下拉选项

public static void exportExcelWithDropdown(SXSSFWorkbook workbook, SXSSFSheet sheet, int columnIndexWithValues) {
        Set<String> uniqueValues = new HashSet<>();
        // 从第3行开始遍历(跳过表头)
        int lastRowNum = sheet.getLastRowNum();
        for (int i = 2; i <= lastRowNum; i++) {
            Row row = sheet.getRow(i);
            if (row != null) {
                Cell cell = row.getCell(columnIndexWithValues);
                if (cell != null) {
                    uniqueValues.add(cell.getStringCellValue());
                }
            }
        }

        // Step 2: 将这些唯一值转换为下拉选项列表
        List<String> dropdownOptions = new ArrayList<>(uniqueValues);
        // 1. 创建隐藏的 Sheet 来存储下拉选项
        // 根据列号命名
        String hiddenSheetName = "hidden" + columnIndexWithValues;
        SXSSFSheet hiddenSheet = workbook.createSheet(hiddenSheetName);

        // 2. 将下拉选项写入隐藏的 Sheet(从第 0 行开始写入)
        for (int i = 0; i < dropdownOptions.size(); i++) {
            hiddenSheet.createRow(i).createCell(0).setCellValue(dropdownOptions.get(i));
        }

        // 3. 设置下拉选项范围公式:比如 hiddenSheetName!$A$1:$A$N
        String formula = hiddenSheetName + "!$A$1:$A$" + dropdownOptions.size();

        // 4. 创建数据验证帮助器
        DataValidationHelper validationHelper = sheet.getDataValidationHelper();
        DataValidationConstraint constraint = validationHelper.createFormulaListConstraint(formula);

        // 5. 将数据验证应用到指定的单元格区域
        CellRangeAddressList addressList = new CellRangeAddressList(3, lastRowNum, columnIndexWithValues, columnIndexWithValues);
        DataValidation validation = validationHelper.createValidation(constraint, addressList);

        // 6. 设置验证的一些兼容性选项
        // 隐藏下拉箭头(兼容性设置)
        // 设置是否显示错误提示
        validation.setSuppressDropDownArrow(true);
        validation.setShowErrorBox(true);

        // 7. 添加数据验证到表格中
        sheet.addValidationData(validation);

        // 8. 将隐藏的 Sheet 设置为不可见
        workbook.setSheetHidden(workbook.getSheetIndex(hiddenSheet), true);
    }

实现表头过滤

/**
     * description: 实现表头过滤
     * @param sheet sheet
     * @param headerRowIndex 表头行
     * @since 2024/9/5
     */
public static void exportExcelWithFilter(SXSSFSheet sheet, int headerRowIndex) {
  // 获取表头行
  Row headerRow = sheet.getRow(headerRowIndex);

  // 检查表头行是否存在
  if (headerRow != null) {
    // 获取表头的最后一列索引
    int lastColumnIndex = headerRow.getLastCellNum() - 1;

    // 设置自动筛选,应用于整个表头所在的所有列
    sheet.setAutoFilter(new CellRangeAddress(headerRowIndex, sheet.getLastRowNum(), 0, lastColumnIndex));
  } else {
    log.error("表头行不存在,请检查 headerRowIndex 的值!");
  }

  // 清理资源或继续处理逻辑
}

设置合并区域中单元格边框

/**
     * description: 设置合并区域中所有单元格的边框
     * @param sheet sheet
     * @param startRow 开始行
     * @param endRow 结束行
     * @param startCol 开始列
     * @param endCol 结束列
     * @param style 样式
     * @since 2024/9/5
     */
public static void setBorders(Sheet sheet, int startRow, int endRow, int startCol, int endCol, CellStyle style) {
  for (int row = startRow; row <= endRow; row++) {
    Row sheetRow = sheet.getRow(row);
    if (sheetRow == null) {
      sheetRow = sheet.createRow(row);
    }
    for (int col = startCol; col <= endCol; col++) {
      Cell cell = sheetRow.getCell(col);
      if (cell == null) {
        cell = sheetRow.createCell(col);
      }
      cell.setCellStyle(style);
    }
  }
}

根据下标填充数据

/**
     * description: 填充数据
     * @param sheet sheet
     * @param data 数据
     * @param dataCellStyle 样式
     * @since 2024/9/5
     */
public static void fillDataRows(SXSSFSheet sheet, List<Map<String, Object>> data, CellStyle dataCellStyle) {
  // 数据从第三行开始(索引从3开始)
  int rowIdx = 3;
  // 遍历数据列表的每个数据行(Map结构)
  for (Map<String, Object> dataRow : data) {
    // 创建新行,并将行索引递增
    Row row = sheet.createRow(rowIdx++);
    // 列索引重置为0
    int colIdx = 0;
    // 遍历数据行中的每个值
    for (Object value : dataRow.values()) {
      // 在当前行创建新单元格,并将列索引递增
      Cell cell = row.createCell(colIdx++);
      // 设置单元格的值,若值为null则设置为空字符串
      cell.setCellValue((Double) (value != null ? value: 0));
      cell.setCellStyle(dataCellStyle);
    }
  }
}

根据别名填充数据

/**
     * description: fillDataRowsToAlisa
     * @param sheet sheet
     * @param data 数据
     * @param dataStyle 数据样式
     * @param columnAliasMap 列别名映射
     * @since 2024/9/9
     */
private static void fillDataRowsToAlisa(SXSSFSheet sheet, List<Map<String, Object>> data, CellStyle dataStyle,Map<String, Integer> columnAliasMap) {
  int rowIdx = 3;
  for (Map<String, Object> dataRow : data) {
    Row row = sheet.createRow(rowIdx++);
    for (Map.Entry<String, Object> entry : dataRow.entrySet()) {
      String alias = entry.getKey();
      Object value = entry.getValue();
      // 使用别名查找列索引
      Integer colIdx = columnAliasMap.get(alias);
      if (colIdx != null) {
        Cell cell = row.createCell(colIdx);
        cell.setCellValue(value != null ? value.toString() : "");
        cell.setCellStyle(dataStyle);
      }
    }
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2128174.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【音视频】使用movie、drawtext过滤器实现图片、文字水印(6-3)

本来准备从六月份开始研究使用ffmpeg的movie filter实现图片水印、drawtext filter实现文字水印的能力&#xff0c;但一直没时间&#xff0c;临近中秋终于有空&#xff0c;于是研究了下ffmpeg命令行&#xff08;这里不做展示&#xff0c;关注代码实现&#xff09;&#xff0c;从…

AI客服机器人开启企业客户服务新纪元

随着人工智能(AI)技术的迅猛发展&#xff0c;使得AI客服机器人走进了我们的视野&#xff0c;成为提高客户满意度和业务效率的不二法宝。这些智能机器人不仅能够处理海量信息&#xff0c;还能为客户提供个性化的服务体验。 一、AI客服机器人的基本原理 AI客服机器人是基于人工智…

Azure web app has no access to openai private endpoint in virtual network

题意&#xff1a;"Azure Web 应用无法访问虚拟网络中的 OpenAI 私有端点。" 问题背景&#xff1a; I am trying to host a web application similar to a private ChatGPT instance within a secluded virtual network, ensuring that theres no external internet …

​年化收益52%,最大回撤13%,卡玛比率3.77,ETF轮动系列大有可为(附策略代码和数据下载)。

原创内容第648篇&#xff0c;专注量化投资、个人成长与财富自由。 今天继续开发策略&#xff0c;先看结果&#xff1a; 年化52%&#xff0c;最大回撤13%&#xff0c;卡玛比率3.77。 策略逻辑&#xff1a; 买入规则&#xff1a; 5日均线大于20日均线 。 最近20个交易日的涨…

【Prompt Engineering:思维树 (ToT)、检索增强生成 (RAG)、自动推理并使用工具 (ART)】

思维树 (ToT) 对于需要探索或预判战略的复杂任务来说&#xff0c;传统或简单的提示技巧是不够的。最近&#xff0c;Yao et el. (2023)(opens in a new tab) 提出了思维树&#xff08;Tree of Thoughts&#xff0c;ToT&#xff09;框架&#xff0c;该框架基于思维链提示进行了总…

全球著名地标卫星影像收藏第5辑

世界那么大&#xff0c;一起去看看&#xff01; 我们在《全球著名地标卫星影像收藏第4辑》一文中&#xff0c;为大家分享了10全球著名地标高清卫星影像&#xff0c;现在继续为大家分享10个著名地标。 我们整理这些地标的KML文件分享大家&#xff0c;也可以打开相应URL链接即可…

tofixed和math.round什么区别

1、floor 返回不大于的最大整数&#xff08;向下取整&#xff09; 2、round 则是4舍5入的计算&#xff0c;入的时候是到大于它的整数&#xff08;当-1.5时可见&#xff0c;四舍五入后得到的结果不是我们期待的&#xff0c;解决办法是先对他取绝对值&#xff0c;然后在用round方…

全平台7合一自定义DIY小程序源码系统 数据库结构全新升级 带完整的安装代码包以及搭建部署教程

系统概述 随着小程序市场的日益成熟&#xff0c;越来越多的企业和个人开始意识到小程序在品牌推广、用户获取和服务提供方面的巨大潜力。然而&#xff0c;传统的小程序开发方式往往存在开发周期长、成本高、灵活性差等问题&#xff0c;难以满足快速变化的市场需求。因此&#…

如何做尘埃粒子计数器校准,多久一次?北京中邦兴业

尘埃粒子计数器的校准是确保其测量准确性和可靠性的重要环节。以下是关于尘埃粒子计数器校准的详细说明&#xff1a; 一、校准目的 尘埃粒子计数器作为评估和监控洁净室及其他控制环境中空气质量的关键仪器&#xff0c;其准确性和可靠性直接关系到数据的准确性和有效性。定期校…

从To B到AI:产品经理的转型攻略

经过几个月的AI学习之后&#xff0c;我已经对To B产品经理转型AI有了一些自己的理解。 个人认为&#xff0c;想要顺利转型&#xff0c;需要依次经历以下几个思考与学习过程&#xff1a; 认清AI能为产品经理带来的价值&#xff1b;确定AI技术的学习范围&#xff1b;学习AI技术…

关于项目中的内存问题、死锁问题如何定位?——Valgrind

valgrind是如何实现的&#xff1f; 基于仿真方式 在实际处理器的基础上仿真一个虚拟处理器&#xff0c;使应用程序运行于这个虚拟处理器之上&#xff0c;从而进行监视分析。 core dump内存问题定位&#xff1a; 1.无效指针&#xff08;野指针&#xff09; 2.内存泄漏(一般不…

Windows下SDL2创建最简单的一个窗口

先看运行效果 再上代码&#xff1a; #include <stdio.h> #include "SDL.h"int main(int argc, char* argv[]) {// 初始化SDL视频子系统if (SDL_Init(SDL_INIT_VIDEO) -1){printf("Error: %s\n", SDL_GetError());return -1;} // 创建一个窗口SDL_…

再次进阶 舞台王者 第八季完美童模全球赛品牌大使【韩嘉潞】赛场秀场超燃合集!

7月20-23日&#xff0c;2024第八季完美童模全球总决赛在青岛圆满落幕。在盛大的颁奖典礼上&#xff0c;一位才能出众的少女——韩嘉潞&#xff0c;迎来了她舞台生涯的璀璨时刻。 品牌大使——韩嘉潞&#xff0c;以璀璨童星之姿&#xff0c;优雅地踏上完美童模盛宴的绚丽舞台&am…

InstantID模型部署教程

一、介绍 InstantID 是由 InstantX 团队、小红书公司和北京大学联合开发的一项前沿技术&#xff0c;旨在实现零样本身份保持生成&#xff0c;仅需单张图像即可支持多种下游任务&#xff0c;可以在几秒钟内实现零样本身份保留生成。 InstantID 以其独特的无需微调方式&#xf…

Anolis OS 8.8 CentOS8离线安装mysql-8.0.9

下载mysql安装包&#xff1a; mysql下载地址 在Linux系统中&#xff0c;mysql的安装包除了要区分系统和cpu架构之外&#xff0c;还区分安装方式&#xff0c;下载不同的包&#xff0c;安装方式也完全不一样&#xff0c;安装完成后的效果也完全不一样。 我之前下载的包按照官方…

Zabbix企业级应用案列

随着业务的越发复杂&#xff0c;对软件系统的要求越来越高&#xff0c;这意味着我们需要随时掌控系统的运行情况。因此&#xff0c;对系统的实时监控以及可视化展示&#xff0c;就成了基础架构的必须能力。 一、zabbix可视化 1.Grafana 简介 Grafana 是一个开源的指标量监测和…

汽车保养维修|基于java的汽车保养系统小程序(源码+数据库+文档)

汽车保养系统小程序 目录 基于java的汽车保养系统小程序 一、前言 二、系统设计 三、系统功能设计 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设布道师&#xff0c;阿里云…

简单聊聊bait文件

场景&#xff1a;业务同事发现某云主机部署了企业主机安全&#xff0c;在该主机上发现了一个诱饵文件&#xff0c;显示注意&#xff1a;此文件是诱饵文件&#xff0c;用于防止重要文件被病毒加密。请勿修改或删除此文件。 解决方法&#xff1a;联系企业主机安全运维同事发现&am…

基于SpringBoot+Vue的小区停车场管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于JavaSpringBootVueMySQL的…

opencv之图像轮廓(三)--凸包

文章目录 前言获取凸包凸缺陷几何学测试测试轮廓是否是凸形的点到轮廓的距离 形状场景算法比较轮廓轮廓的特征值宽高比ExtentSolidity等效直径&#xff08;Equivalent Diameter&#xff09;方向掩模和像素点使用Numpy函数获取轮廓像素点使用OpenCV函数获取轮廓点 最大值和最小值…