多sheet excel 导出

在处理大量数据导出到Excel时,将数据分到多个Sheet后统一导出是一种高效且常见的方法。下面用一个流程图帮你快速了解核心流程,然后再看具体的代码实现。

复制代码
flowchart TD
    A[开始导出请求] --> B[计算数据总量与Sheet数量]
    B --> C[创建ExcelWriter实例]
    C --> D[循环创建每个Sheet]
    D --> E{是否还有未处理数据?}
    E -- 是 --> F[分页查询当前Sheet数据]
    F --> G[创建WriteSheet并设置名称]
    G --> H[将数据写入当前Sheet]
    H --> D
    E -- 否 --> I[执行excelWriter.finish]
    I --> J[关闭输出流]
    J --> K[导出完成]

下面是基于 ​​EasyExcel​​ 库的具体实现方案和代码示例。

📝 核心代码实现

首先,在项目的 pom.xml 文件中添加 EasyExcel 依赖。

复制代码
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.3.2</version> <!-- 请使用最新稳定版本 -->
</dependency>

下面是实现分 Sheet 导出的关键代码:

复制代码
@Service
public class DataExportService {

    @Autowired
    private YourMapper yourMapper; // 你的数据访问层

    /**
     * 将大数据量分Sheet导出为Excel
     * @param response HttpServletResponse
     */
    public void exportLargeDataToSheets(HttpServletResponse response) {
        // 1. 设置响应头,告诉浏览器这是一个Excel文件下载请求
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("UTF-8");
        String fileName = "大数据导出示例.xlsx";
        try {
            fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + fileName);

        // 2. 获取数据总量,并计算需要的Sheet数
        long totalCount = yourMapper.selectCount(null); // 假设的方法,获取总数据量
        int batchSize = 5000; // 每个Sheet存放的数据行数,可调整
        int sheetCount = (int) (totalCount / batchSize) + (totalCount % batchSize > 0 ? 1 : 0);

        // 3. 创建ExcelWriter实例
        ExcelWriter excelWriter = null;
        try (OutputStream outputStream = response.getOutputStream()) {
            excelWriter = EasyExcel.write(outputStream, YourDataModel.class).build(); // YourDataModel是你的数据模型类

            // 4. 循环创建并写入每个Sheet
            for (int sheetIndex = 0; sheetIndex < sheetCount; sheetIndex++) {
                // 计算当前页的起始位置
                long currentPage = sheetIndex + 1;
                long startRow = sheetIndex * batchSize;
                // 分页查询数据
                List<YourDataModel> dataList = yourMapper.selectBatch(startRow, batchSize); // 假设的分页查询方法

                // 创建WriteSheet,并指定Sheet名称(例如:Sheet1, Sheet2...)
                WriteSheet writeSheet = EasyExcel.writerSheet(sheetIndex, "数据页_" + (sheetIndex + 1)).build();

                // 将当前批次的数据写入到对应的Sheet中
                excelWriter.write(dataList, writeSheet);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 5. 非常重要!最终必须调用finish方法,才会真正写出文件,并关闭相关资源。
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }
    }
}

💡 代码要点解析

  • ​数据查询​ :关键在于​分页查询​ 。使用 limit startRow, batchSize 这样的SQL语句,分批从数据库拉取数据,避免一次性加载全部数据导致内存溢出(OOM)。你需要根据使用的持久层框架(如MyBatis)实现对应的分页查询方法。
  • ​Sheet管理​ :通过循环创建多个 WriteSheet 对象,每个对象对应Excel中的一个工作表。writerSheet(sheetIndex, "Sheet名称") 方法用于指定Sheet的索引和名称。
  • ​资源管理​ExcelWriterOutputStream 必须正确关闭。在 finally 块中调用 excelWriter.finish() 是确保资源释放和文件正确生成的关键。

🚀 进阶优化建议

当数据量特别大(例如百万行以上)时,可以考虑以下优化方案:

  • ​异步导出​:对于耗时很长的导出任务,建议采用异步处理。用户触发导出后,服务端生成一个任务ID并立即返回。任务在后台执行,用户可通过任务ID轮询进度或等待完成后下载。
  • ​多线程并行处理​:如果不同Sheet的数据相互独立,可以使用多线程并行查询和写入,充分利用多核CPU能力。但要注意线程安全和数据库连接池压力。
  • ​限制与压缩​:Excel单个Sheet最多支持约104万行数据。如果总数据量远超于此,分Sheet是必须的。最终生成的文件如果过大,可以考虑打包成ZIP格式提供下载。

⚠️ 注意事项

  • ​内存监控​ :即使分页查询,也要注意每批数据的大小(batchSize),避免单个批次数据过大。建议根据实际数据行的内存占用来调整 batchSize,通常设置在几千到一万条记录为宜。
  • ​事务与连接​ :长时间执行的导出任务可能会占用数据库连接。确保查询方法的事务传播行为设置正确(例如 @Transactional(readOnly = true, timeout = 60)),避免长时间占用写事务。

希望这份详细的指南和代码示例能帮助你顺利实现需求!如果你在具体实现中遇到其他问题,可以随时提出。

相关推荐
笨蛋不要掉眼泪2 小时前
SpringBoot项目Excel模板下载功能详解
java·spring boot·后端·spring·excel·ruoyi
胖咕噜的稞达鸭2 小时前
C++篇 String实现避坑指南:搞定构造,拷贝与析构,增删查改,流提取流插入与比对大小 一文全解
开发语言·数据结构·c++
std860213 小时前
JavaScript性能优化实战技术文章大纲
java
歪歪1003 小时前
如何根据实际需求选择使用 TCP 或 UDP 协议?
开发语言·网络·网络协议·tcp/ip·计算机网络·udp
不枯石3 小时前
Matlab通过GUI实现点云的导向(引导)滤波(附最简版)
开发语言·图像处理·算法·计算机视觉·matlab
熊猫_豆豆3 小时前
MATLAB 九大行星太阳系运行程序
开发语言·nginx·matlab
他们叫我技术总监3 小时前
帆软Report11多语言开发避坑:法语特殊引号导致SQL报错的解决方案
java·数据库·sql
程序员三明治3 小时前
二分查找思路详解,包含二分算法的变种,针对不同题的做法
java·数据结构·算法·二分查找
枣伊吕波3 小时前
五十三、bean的管理-bean的获取、bean的作用域、第三方bean
java·开发语言