Java 流式返回 JSON 分段提取的实战指南

在现代开发中,越来越多的应用需要从后端以 JSON 格式获取数据。处理这些数据时,如果一次性加载全部内容,可能会导致内存占用过高或响应时间延长。因此,我们需要采用流式处理(Streaming)的方法进行分段提取数据。

在这篇文章中,我将带领你了解整个过程,并通过具体的示例代码来帮助你实现这一目标。

任务流程概述

以下是实现Java流式返回JSON分段提取的主要步骤:

步骤 描述
1 创建一个 RESTful API
2 设计用于流式响应的 DTO(数据传输对象)
3 使用 StreamingResponseBody 接口进行流式返回
4 处理 JSON 数据的提取和传输
5 在客户端使用流处理数据

步骤详解

1. 创建一个 RESTful API

首先,我们需要创建一个基本的 Spring Boot 应用,并添加依赖项:

<!-- 在 pom.xml 中添加依赖项 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

接下来,创建一个控制器类来处理请求:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

@RestController
public class DataController {

    @GetMapping("/data")
    public StreamingResponseBody streamData() {
        // 这里将实现流式返回逻辑
    }
}

2. 设计用于流式响应的 DTO

定义一个数据传输对象(DTO)来封装返回的数据:

public class DataDTO {
    private String id;
    private String content;

    // 构造函数,getter和setter省略
}

3. 使用 StreamingResponseBody 接口进行流式返回

我们将使用 StreamingResponseBody 来实现流式响应:

@GetMapping("/data")
public StreamingResponseBody streamData() {
    return outputStream -> {
        // 需要重点查看这里
        // 设定输出格式
        outputStream.write("[".getBytes());

        for (int i = 0; i < 100; i++) {
            // 创建数据对象
            DataDTO data = new DataDTO();
            data.setId(String.valueOf(i));
            data.setContent("Content " + i);
            
            // 将对象转换成 JSON 格式
            String json = convertToJson(data);
            
            // 写入到输出流
            outputStream.write(json.getBytes());
            if (i < 99) {
                outputStream.write(",".getBytes()); // 添加分隔符
            }
            outputStream.flush(); // 刷新输出流以确保数据被及时发送
        }

        outputStream.write("]".getBytes());
        outputStream.flush(); // 刷新最后的输出流
    };
}

private String convertToJson(DataDTO data) {
    // 使用Jackson或Gson库将对象转换为JSON字符串
    return new ObjectMapper().writeValueAsString(data);
}

4. 处理 JSON 数据的提取和传输

在上面的代码中,convertToJson 方法使用 Jackson 库将 DTO 对象转换为 JSON 格式。在控制器中,我们创建了流式响应,并逐个将 JSON 数据对象写入输出流,如果输出过多数据则会使用 flush() 方法将其发送出去。

5. 在客户端使用流处理数据

在客户端,您可以使用 JavaScript 的 Fetch API 来处理服务器发送的流式数据:

fetch('/data')
  .then(response => {
    const reader = response.body.getReader();
    let decoder = new TextDecoder();
    let result = '';

    reader.read().then(function processText({ done, value }) {
      if (done) {
        // 处理完成
        console.log('Stream finished');
        return;
      }
      result += decoder.decode(value, { stream: true });
      console.log(result); // 输出当前接收到的数据
      return reader.read().then(processText);
    });
  });

关系图

以下是使用 mermaid 语法生成的关系图,展示了整个数据流转的结构:

erDiagram
    DATA {
        string id
        string content
    }
    
    REST_API {
        string endpoint
        string method
    }
    
    REST_API ||--o{ DATA : returns

旅行图

继续使用 mermaid 语法,展示客户端如何接收和处理流数据的过程:

journey
    title 客户端获取流式返回数据的过程
    section 从服务器请求数据
      用户点击请求数据按钮: 5: 用户
      发送 GET 请求: 5: 客户端
    section 获取数据
      开始读取流: 4: 客户端
      持续接收数据: 5: 客户端
    section 数据处理
      输出接收到的数据: 5: 客户端

结尾

通过以上步骤,我们实现了 Java 流式返回 JSON 分段提取的功能。使用流式处理可以大大减少内存消耗,提升性能。希望这篇文章能帮助你更好地理解和应用流式数据处理的概念。

如果在实现过程中有任何问题,欢迎随时询问!