首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

JSON 樹形數據處理:從解析到數據庫持久化完整實現

     編輯:Java 相關知識

前言

省市區三級聯動、組織架構、商品分類等層級數據常以 JSON 樹形結構存儲。本文詳細講解如何將複雜 JSON 樹形數據解析為 Java 對象,並通過遞歸算法持久化到關係型數據庫。

一、數據結構分析

典型 JSON 結構

{
  "name": "全國",
  "id": "0000000000",
  "items": [
    {
      "city": "北京市",
      "city_id": "1001000000",
      "items": [
        {"sub_city": "東城區", "sub_id": "2001001000"},
        {"sub_city": "西城區", "sub_id": "2001002000"}
      ]
    },
    {
      "city": "天津市", 
      "city_id": "1002000000",
      "items": [...]
    }
  ]
}

特點總結

  • 多層嵌套,深度不固定
  • 不同層級字段名不一致(city/city_id vs sub_city/sub_id)
  • 葉子節點無 items 字段或為空

二、實體類設計


public class JsonNode {
    private String id;           // 統一映射:city_id, sub_id, industry_id 等
    private String name;         // 統一映射:city, sub_city, industry 等
    private List<JsonNode> children; // 子節點集合
    
    // Getter/Setter 省略
    // 建議添加 @JsonAlias 適配多種字段名
}

三、數據預處理:字段名統一

由於各層級字段名不同,需先標準化:


private String normalizeJson(String rawJson) {
    return rawJson
        .replace("\"items\":\"\"", "")           // 移除空 items
        .replace("city_id", "id")                // 統一 id 字段
        .replace("sub_id", "id")
        .replace("industry_id", "id")
        .replace("city", "name")                 // 統一 name 字段
        .replace("sub_city", "name")
        .replace("sub_txt", "name")
        .replace("industry", "name")
        .replace("sub_industry", "name")
        .replace("profession_id", "id")
        .replace("profession", "name")
        .replace("sub_profession", "name");
}

四、遞歸解析與持久化核心邏輯

1. 入口方法


public String importJson(String filePath, String jsonType, String encoding) 
        throws Exception {
    // 1. 讀取文件
    String jsonData = FileUtil.readFile(filePath, encoding);
    
    // 2. 預處理
    jsonData = normalizeJson(jsonData);
    
    // 3. 提取根節點信息
    String rootId = extractValue(jsonData, "\"id\":\"", "\"");
    String rootName = extractValue(jsonData, "\"name\":\"", "\"");
    
    // 4. 保存根節點
    saveNode(jsonType, rootId, rootName, "-1", 1L);
    
    // 5. 提取子節點數組並解析
    String childrenJson = extractChildrenArray(jsonData);
    List<JsonNode> children = parseJsonArray(childrenJson);
    
    // 6. 遞歸處理子樹
    processChildren(children, rootId, jsonType, 1L);
    
    return "SUCCESS";
}

2. 遞歸處理方法


private void processChildren(List<JsonNode> nodes, String parentId, 
                             String jsonType, Long level) {
    if (nodes == null || nodes.isEmpty()) return;
    
    for (JsonNode node : nodes) {
        // 保存當前節點
        saveNode(jsonType, node.getId(), node.getName(), parentId, level + 1);
        
        // 遞歸處理子節點
        if (node.getChildren() != null && !node.getChildren().isEmpty()) {
            processChildren(node.getChildren(), node.getId(), jsonType, level + 1);
        }
    }
}

3. 數據庫持久化


private void saveNode(String type, String code, String name, 
                      String parentCode, Long level) {
    CommJsonData entity = new CommJsonData();
    entity.setJsonType(type);        // 數據類型:city, industry 等
    entity.setJsonCode(code);        // 業務編碼
    entity.setJsonName(name);        // 顯示名稱
    entity.setParentCode(parentCode); // 父節點編碼
    entity.setLevelId(level);        // 層級深度
    entity.setRowId(UUID.randomUUID().toString()); // 主鍵
    
    // 使用批量插入優化性能
    batchInsertBuffer.add(entity);
    if (batchInsertBuffer.size() >= BATCH_SIZE) {
        jdbcTemplate.batchUpdate(INSERT_SQL, batchInsertBuffer);
        batchInsertBuffer.clear();
    }
}

五、數據庫表設計


CREATE TABLE comm_json_data (
    row_id       VARCHAR(36) PRIMARY KEY,
    json_type    VARCHAR(50) NOT NULL,      -- city/industry/profession
    json_code    VARCHAR(50) NOT NULL,      -- 業務編碼
    json_name    VARCHAR(200) NOT NULL,     -- 顯示名稱
    parent_code  VARCHAR(50) NOT NULL,      -- 父節點編碼,根節點為 -1
    level_id     INT NOT NULL,              -- 層級:1=省,2=市,3=區
    create_time  TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_type_parent (json_type, parent_code),
    INDEX idx_type_code (json_type, json_code)
);

六、關鍵技術點與優化

1. 大數據量優化策略

  • 批量插入:累積 500-1000 條批量提交
  • 關閉自動提交:`connection.setAutoCommit(false)`
  • 預編譯語句:`PreparedStatement` 防注入+性能
  • 異步處理:生產者-消費者模式,解析與入庫分離

2. 異常數據容錯


try {
    saveNode(...);
} catch (Exception e) {
    log.error("節點保存失敗: id={}, name={}", node.getId(), node.getName(), e);
    // 記錄失敗節點供後續人工處理
    failedNodes.add(node);
}

3. 幂等性保證

  • 基於 json_type + json_code 唯一索引
  • 使用 `INSERT ... ON DUPLICATE KEY UPDATE` (MySQL) 或 `MERGE` (Oracle)
  • 支持重複導入不產生臟數據

七、完整工具類封裝


public class JsonTreeImporter {
    private JdbcTemplate jdbcTemplate;
    private static final int BATCH_SIZE = 500;
    private List<CommJsonData> batchBuffer = new ArrayList<>();
    private List<JsonNode> failedNodes = new ArrayList<>();
    
    public ImportResult importFromFile(File file, String type) {
        // 完整流程封裝...
    }
    
    public ImportResult importFromString(String json, String type) {
        // 字符串導入...
    }
    
    // 內部方法...
}

八、擴展應用場景

場景JSON 結構特點處理重點
行政區劃固定 3-4 層,編碼規律編碼校驗、歷史版本管理
組織架構深度不定,頻繁變更增量同步、移動節點處理
商品分類屬性繼承、SKU 關聯屬性合並、多維度分類
權限菜單排序、圖標、路由路徑前端路由生成、按鈕級權限

總結

JSON 樹形數據入庫核心在於:字段標準化 → 遞歸遍歷 → 批量持久化。掌握字段名映射、遞歸算法、數據庫批量操作三大技術點,即可高效處理各類層級數據導入需求。生產環境建議增加:增量同步機制、版本管理、數據校驗報告等企業級特性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved