用 StreamingResponseBody 打造“无限加载”的Excel导出神器:让大数据导出不再卡顿!

2,004 阅读3分钟

引言

在这个数据爆炸的时代,我们经常需要处理大量的数据。无论是数据分析、报表生成还是数据导出,处理大数据总是让人头疼。传统的数据导出方式通常是将所有数据一次性生成并返回给客户端,这种方式在处理大数据量时可能会导致性能问题,甚至导致服务器崩溃。

今天,我们就来探讨一个有趣的话题——如何使用 StreamingResponseBody 打造一个“无限加载”的Excel导出神器,让大数据导出不再卡顿!

什么是 StreamingResponseBody

StreamingResponseBody 是 Spring Framework 提供的一个接口,用于处理 HTTP 响应的流式输出。它允许我们在服务器端逐步生成响应内容,并将其立即发送给客户端,而不需要等待所有数据准备完毕。

简单来说,StreamingResponseBody 就像是一个“快递员”,它会一边打包数据,一边送到客户端手中,而不是等到所有包裹都准备好再一起送出去。

示例:大量数据导出成Excel

假设我们正在开发一个系统,需要将大量数据导出成Excel文件。我们将使用 StreamingResponseBody 来实现这一功能,让导出过程更加流畅和高效。

1. 添加依赖

首先,我们需要在 pom.xml 中添加必要的依赖,包括 Apache POI 和 Spring Boot。

<dependencies>
    <!-- Spring Boot Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Apache POI for Excel -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>5.2.2</version>
    </dependency>
</dependencies>

2. 创建控制器

接下来,我们需要创建一个控制器来处理用户的请求,并使用 StreamingResponseBody 逐步生成Excel文件。

import com.google.common.base.Stopwatch;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

import java.io.IOException;
import java.io.OutputStream;
import java.util.concurrent.TimeUnit;

@RestController
public class DataExportController {

    private static final int ROW_COUNT = 100000; // 模拟10万行数据

    @GetMapping("/export")
    public ResponseEntity<StreamingResponseBody> exportData() {
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=data.xlsx");

        StreamingResponseBody responseBody = outputStream -> {
            try (SXSSFWorkbook workbook = new SXSSFWorkbook(100)) { // 每100行刷新一次
                Sheet sheet = workbook.createSheet("Data");

                // 创建表头
                Row headerRow = sheet.createRow(0);
                String[] headers = {"ID", "Name", "Age", "Email"};
                for (int i = 0; i < headers.length; i++) {
                    Cell cell = headerRow.createCell(i);
                    cell.setCellValue(headers[i]);
                }

                // 创建数据行
                Stopwatch stopwatch = Stopwatch.createStarted();
                for (int i = 1; i <= ROW_COUNT; i++) {
                    Row row = sheet.createRow(i);
                    row.createCell(0).setCellValue(i);
                    row.createCell(1).setCellValue("User" + i);
                    row.createCell(2).setCellValue(20 + i % 10);
                    row.createCell(3).setCellValue("user" + i + "@example.com");

                    if (i % 1000 == 0) { // 每1000行刷新一次
                        workbook.write(outputStream);
                        outputStream.flush();
                        System.out.println("已导出 " + i + " 行数据,耗时: " + stopwatch.elapsed(TimeUnit.MILLISECONDS) + " ms");
                        stopwatch.reset().start();
                    }
                }

                // 写入剩余的数据
                workbook.write(outputStream);
                outputStream.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        };

        return ResponseEntity.ok()
                .headers(headers)
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(responseBody);
    }
}

3. 前端页面

虽然这是一个后端功能,但我们也可以创建一个简单的前端页面来触发导出操作。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>大数据导出神器</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f9f9f9;
            color: #333;
            text-align: center;
            padding: 50px;
        }
        h1 {
            color: #ff6600;
        }
        button {
            padding: 10px 20px;
            font-size: 16px;
            background-color: #ff6600;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
        }
        button:hover {
            background-color: #e65c00;
        }
    </style>
</head>
<body>
<h1>大数据导出神器</h1>
<button onclick="exportData()">点击导出Excel</button>

<script>
    function exportData() {
        window.location.href = '/export';
    }
</script>

</body>
</html>

4. 运行效果

当你访问前端页面并点击“点击导出Excel”按钮时,你会看到一个下载对话框,选择保存位置后,Excel文件将开始逐步生成并下载。整个过程中,你可以看到控制台输出的进度信息,让你知道导出的进度。

结语

通过使用 StreamingResponseBody,我们可以轻松地实现流式响应,为用户提供更加流畅和高效的体验。希望这篇文章能给你带来一些灵感,让你在处理大数据时也能找到更多的乐趣!

如果你觉得这篇文章对你有帮助,别忘了点赞和分享哦!让我们一起传播快乐,让这个世界变得更加美好!🎉🎉🎉


希望这篇博客能给你带来一些启发和乐趣!如果有任何问题或建议,欢迎在评论区留言交流。😊