在Java开发中,我们与第三方系统通信时,尤其是调用RESTful API接口,通常都要面对返回的JSON格式数据。如果返回的数据结构足够简单,仅包含一层键值对,那我们只需创建一个简单的POJO类即可完成解析。但实际开发中,复杂嵌套的JSON结构是家常便饭:

  • 多层嵌套
  • 动态字段
  • 含数组与对象混合结构
  • 字段可能存在也可能不存在
  • 不同接口或同一接口不同时间返回结构可能不同

这时候,传统的方式——为每种结构定义Java类,显然不再适用,容易造成如下问题:

  • 项目中实体类泛滥,维护困难;
  • 数据结构稍微改动就要改代码;
  • 编写繁琐、调试复杂;
  • 接入周期变长,增加开发成本。

一、背景场景:接收第三方支付账单

假设我们通过接口调用,获取了支付平台提供的账单数据,返回如下JSON结构:

{
  "bill_response": {
    "merchant_id": "M20250723001",
    "settlement_date": "2025-07-22",
    "total_count": 3,
    "bills": [
      {
        "order_id": "OID1001",
        "amount": 299.00,
        "status": "SUCCESS"
      },
      {
        "order_id": "OID1002",
        "amount": 58.99,
        "status": "FAILED"
      },
      {
        "order_id": "OID1003",
        "amount": 108.75,
        "status": "SUCCESS"
      }
    ]
  }
}

这个返回数据结构特点是:

  • 包含嵌套对象(bill_response);
  • 嵌套结构中包含数组(bills);
  • 每个账单项是一个对象;
  • 字段可能在不同场景中出现缺失或结构变化(如退款、失败订单等);

如果使用传统POJO定义,需要:

  • 定义 BillResponse 类;
  • 创建 BillItem 内部类;
  • 编写嵌套字段映射代码;
  • 手动处理字段缺失或格式不一致问题;

工作量非常大,灵活性差,容易出错。


二、解决方案:Gson + OGNL 快速解析与字段提取

技术组合介绍

工具 作用
Gson 将复杂 JSON 字符串解析为 Map/List 结构,支持嵌套与数组
OGNL 通过路径表达式快速访问 Map/List 中的目标字段,无需多层 get 操作

三、项目依赖配置

pom.xml 中引入如下依赖:

<dependencies>
    <!-- Gson:JSON序列化/反序列化 -->
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.8.9</version>
    </dependency>

    <!-- OGNL:对象图导航表达式 -->
    <dependency>
        <groupId>ognl</groupId>
        <artifactId>ognl</artifactId>
        <version>3.2.21</version>
    </dependency>
</dependencies>

四、核心工具类封装(JsonUtils)

我们将Gson和OGNL的使用封装在一个通用工具类中:

方法1:JSON字符串转Map结构

public static Map<String, Object> transferToMap(String json) {
    return new Gson().fromJson(json, new TypeToken<Map<String, Object>>() {}.getType());
}

方法2:通过表达式获取任意字段

public static <T> T getValue(String json, String expression, Class<T> resultType) throws Exception {
    Map<String, Object> map = transferToMap(json);
    Object result = Ognl.getValue(expression, map);
    return resultType.cast(result);
}

五、实战案例:解析支付账单

我们来实际演示如何提取这个账单结构中的数据。

1. 提取结算日期

String json = "..."; // 假设是上述账单JSON字符串
String date = JsonUtils.getValue(json, "bill_response.settlement_date", String.class);
// 输出:2025-07-22

2. 提取账单总条数

Integer total = JsonUtils.getValue(json, "bill_response.total_count", Integer.class);
// 输出:3

3. 提取账单列表(数组)

List<Map<String, Object>> bills = JsonUtils.getValue(json, "bill_response.bills", List.class);
for (Map<String, Object> bill : bills) {
    System.out.println("订单:" + bill.get("order_id") + ",金额:" + bill.get("amount") + ",状态:" + bill.get("status"));
}

4. 提取第一个订单的金额

Double firstAmount = JsonUtils.getValue(json, "bill_response.bills[0].amount", Double.class);
// 输出:299.00

5. 提取第二个订单的状态

String secondStatus = JsonUtils.getValue(json, "bill_response.bills[1].status", String.class);
// 输出:FAILED

六、OGNL表达式拓展技巧

表达式 含义
bill_response.settlement_date 访问嵌套字段
bill_response.bills[0] 获取第一个账单项
bill_response.bills[2].order_id 获取第3个订单的ID
bill_response.bills.size() 获取账单数量(扩展用法)

七、方案优势总结

优势 描述
零实体类解析 不需要定义任何POJO,适应结构多变的JSON
通用性强 任意JSON格式通吃,无需硬编码字段结构
开发效率高 一行表达式搞定数据提取,开发调试更快
易于维护 JSON结构改动无需改Java代码,只需调整表达式路径

八、常见应用场景推荐

  • 接入支付平台账单、订单、通知结构;
  • 接收AI模型/大语言模型返回的复杂结构;
  • 处理带有“动态字段”的配置JSON;
  • 日志采集系统中的嵌套数据结构清洗;
  • 可视化平台的结构驱动型数据处理;

九、结语

在第三方对接或平台集成场景中,复杂JSON结构不可避免。通过将Gson与OGNL结合使用,我们可以:

  • 抛弃传统冗余实体类定义;
  • 更快速地完成字段提取与数据处理;
  • 更从容地应对API结构变动;

这一技巧既是架构层设计简化的体现,也是代码可维护性提升的重要手段,值得每一位Java开发者在项目中实践落地。

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐