Springboot导出千万数据 (多个sheet)

该文章介绍了如何在SpringBoot项目中使用EasyExcel库处理大数据量(1000万行)的Excel导出,通过分片策略将数据写入多个工作表,以提高性能并降低内存消耗。
摘要由CSDN通过智能技术生成
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.zyh.demo.dao.DeriveMapper;
import com.zyh.demo.domain.Stu;
import com.zyh.demo.service.DeriveService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.List;

@Service
@Slf4j
public class DeriveServiceImpl implements DeriveService {

    @Autowired
    private DeriveMapper deriveMapper;
    @Autowired
    private HttpServletResponse response;

    /**
     * 下载数据到 Excel 文件
     *
     * @throws IOException IO 异常
     */
    public void download() throws IOException {
        log.info("*********导出开始!**************");
        long startTime = System.currentTimeMillis();
        String fileName = "downloadBig";
        OutputStream outputStream = null;

        try {
            int totalCount = 10000000;  // 总行数
            int sheetDataRows = 1000000;  // 每个 Sheet 的行数
            int writeDataRows = 1000000;  // 每次写入的行数

            // 获取桌面路径
            String filePath = "D:/derive/daochu/" + fileName + ".xlsx";

            // 计算需要的 Sheet 数量
            Integer sheetNum = totalCount % sheetDataRows == 0 ? (totalCount / sheetDataRows) : (totalCount / sheetDataRows + 1);
            // 计算一般情况下每一个 Sheet 需要写入的次数
            Integer oneSheetWriteCount = sheetDataRows / writeDataRows;
            // 计算最后一个 Sheet 需要写入的次数
            Integer lastSheetWriteCount = totalCount % sheetDataRows == 0 ?
                    oneSheetWriteCount :
                    (totalCount % sheetDataRows % writeDataRows == 0 ?
                            (totalCount / sheetDataRows / writeDataRows) :
                            (totalCount / sheetDataRows / writeDataRows + 1));
            outputStream = new FileOutputStream(filePath);
            ExcelWriter excelWriter = EasyExcel.write(outputStream).build();

            for (int i = 0; i < sheetNum; i++) {
                // 创建 Sheet
                WriteSheet sheet = new WriteSheet();
                sheet.setSheetName("Sheet" + i);
                sheet.setSheetNo(i);

                for (int j = 0; j < (i != sheetNum - 1 ? oneSheetWriteCount : lastSheetWriteCount); j++) {
                    // 创建 WriteSheet
                    WriteSheet writeSheet = EasyExcel.writerSheet(i, "Sheet" + (i + 1)).head(Stu.class)
                            .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).build();

                    // 从数据库中提取数据
                    List<Stu> data = fetchDataFromDatabase(i * sheetDataRows + j * writeDataRows, writeDataRows);
                    // 将数据写入 Excel
                    excelWriter.write(data, writeSheet);
                }
            }

            long endTime = System.currentTimeMillis();
            long elapsedTime = endTime - startTime;
            log.info("*********导出结束!导出耗时:" + elapsedTime + "毫秒**************");

            // 关闭 ExcelWriter
            excelWriter.finish();
            outputStream.flush();
            outputStream.close();

            // 返回给前端的响应
            response.setContentType("application/octet-stream");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

            // 从生成的文件读取内容并写入响应输出流
            try (InputStream inputStream = new FileInputStream(filePath);
                 OutputStream responseOutputStream = response.getOutputStream()) {
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    responseOutputStream.write(buffer, 0, bytesRead);
                }
            }

            // 删除生成的文件
//            File file = new File(filePath);
//            if (file.exists()) {
//                file.delete();
//            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                outputStream.close();
            }
        }
    }

    /**
     * 从数据库中获取数据
     *
     * @param offset 偏移量
     * @param limit  限制数量
     * @return 数据列表
     */
    public List<Stu> fetchDataFromDatabase(int offset, int limit) {
        // 调用数据库查询方法以检索数据,注意在 SQL 查询中使用 offset 和 limit
        return deriveMapper.stuListWithLimit(offset, limit);
    }

    /**
     * 数据导出接口
     *
     * @throws IOException IO 异常
     */
    @Override
    public String derive() throws IOException {
        download();
        return null;
    }
}

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.2.1</version>
        </dependency>

使用的时候根据实际情况进行调整,比如保存路径记得改

当然千万以下也是可以用的,在总行数的地方改一下,

每个 Sheet 的行数和每次写入的行数可以适当的调整
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值