本文我们将探讨如何在 Spring Boot 应用程序中使用 Jackson 的流式 API(JsonParser)高效处理大型 JSON 对象。通过增量反序列化大型 JSON 对象,可以避免内存和性能瓶颈。本文将通过一个实时示例,演示如何处理大型 JSON 负载,并实现数据的增量处理和过滤。我们将实现一个 Spring Boot 控制器来处理大型 JSON 输入,并使用 Postman 进行测试,提供示例输入和输出。该解决方案确保低内存消耗和高性能,特别适用于包含数百万条记录的 JSON 文件。

为了在 Spring Boot 应用程序中使用 Jackson 的 JsonParser(流式 API)高效处理大型 JSON 对象,我们可以实现一种增量反序列化的解决方案,以避免性能和内存消耗问题。我将通过一个实时示例为您讲解,并展示如何使用 Postman 进行测试。


场景

假设我们正在处理一个包含数百万条产品详细信息的大型 JSON 文件,如果一次性加载整个文件,可能会导致内存问题。我们希望增量处理该文件,并仅返回部分数据(例如,符合特定条件的产品)给客户端。

实现步骤

1. Spring Boot 配置

Maven 依赖
在 pom.xml 中添加以下 Jackson 依赖:

<dependencies>
    <!-- Jackson for JSON Processing -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
    </dependency>
</dependencies>

 

2. 处理 JSON 流式数据的控制器

创建一个 Spring Boot 控制器来处理传入的请求。

@RestController
@RequestMapping("/api/products")
public class ProductController {

    @PostMapping("/process-large-json")
    public ResponseEntity<List<Product>> processLargeJson(@RequestBody InputStream inputStream) {
        List<Product> matchingProducts = new ArrayList<>();
        
        try (JsonParser jsonParser = new JsonFactory().createParser(inputStream)) {
            // Start parsing JSON
            if (jsonParser.nextToken() == JsonToken.START_ARRAY) {
                while (jsonParser.nextToken() != JsonToken.END_ARRAY) {
                    Product product = readProduct(jsonParser);

                    // Filter logic - Example: Only process products with price > 100
                    if (product != null && product.getPrice() > 100) {
                        matchingProducts.add(product);
                    }
                }
            }
        } catch (IOException e) {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
        }

        return ResponseEntity.ok(matchingProducts);
    }

    // Utility method to read each product incrementally
    private Product readProduct(JsonParser jsonParser) throws IOException {
        Product product = new Product();
        while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
            String fieldName = jsonParser.getCurrentName();
            jsonParser.nextToken(); // move to value

            if ("id".equals(fieldName)) {
                product.setId(jsonParser.getIntValue());
            } else if ("name".equals(fieldName)) {
                product.setName(jsonParser.getText());
            } else if ("price".equals(fieldName)) {
                product.setPrice(jsonParser.getDoubleValue());
            }
        }
        return product;
    }
}

3. 产品模型

创建一个简单的 Product 类来保存解析后的数据。

public class Product {
    private int id;
    private String name;
    private double price;

    // Getters and setters
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public double getPrice() { return price; }
    public void setPrice(double price) { this.price = price; }
}

4. 用于测试的大型 JSON 输入示例

以下是一个大型 JSON 输入示例(包含多个产品对象)。您可以将其保存到文件中,或直接在 Postman 中输入。

[
    { "id": 1, "name": "Product 1", "price": 50 },
    { "id": 2, "name": "Product 2", "price": 150 },
    { "id": 3, "name": "Product 3", "price": 200 },
    { "id": 4, "name": "Product 4", "price": 80 },
    { "id": 5, "name": "Product 5", "price": 120 }
]

5. 使用 Postman 进行测试

端点: POST /api/products/process-large-json

请求体: Raw JSON 数据

在 Postman 中,按照以下步骤操作:

  1. 选择 POST 方法。

  2. 设置 URL 为 http://localhost:8080/api/products/process-large-json。

  3. 在 Body 选项卡中,选择 raw,然后选择 JSON。

  4. 粘贴大型 JSON 数组(示例见上文)。

  5. 点击 Send。

预期输出:

价格大于 100 的产品将被返回。以下是过滤后的输出示例:

[
    { "id": 2, "name": "Product 2", "price": 150 },
    { "id": 3, "name": "Product 3", "price": 200 },
    { "id": 5, "name": "Product 5", "price": 120 }
]

解释

  • JsonParser: 流式 API(JsonParser)逐个处理 JSON 令牌,而无需将整个文件加载到内存中,非常适合处理大型数据。

  • 增量处理: Product 对象被增量反序列化。仅符合特定条件(例如,价格 > 100)的对象会被存储在内存中并返回,从而减少内存使用。

  • InputStream: 传入的请求体作为 InputStream 处理,使我们能够直接处理大型 JSON 对象。

该解决方案高效处理大型 JSON 负载,同时确保内存使用保持在较低水平。

— 感谢阅读 —
广告

一起交流

分享你的思考,让讨论更进一步。