省市區三級聯動、組織架構、商品分類等層級數據常以 JSON 樹形結構存儲。本文詳細講解如何將複雜 JSON 樹形數據解析為 Java 對象,並通過遞歸算法持久化到關係型數據庫。
{
"name": "全國",
"id": "0000000000",
"items": [
{
"city": "北京市",
"city_id": "1001000000",
"items": [
{"sub_city": "東城區", "sub_id": "2001001000"},
{"sub_city": "西城區", "sub_id": "2001002000"}
]
},
{
"city": "天津市",
"city_id": "1002000000",
"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");
}
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";
}
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);
}
}
}
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)
);
try {
saveNode(...);
} catch (Exception e) {
log.error("節點保存失敗: id={}, name={}", node.getId(), node.getName(), e);
// 記錄失敗節點供後續人工處理
failedNodes.add(node);
}
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 樹形數據入庫核心在於:字段標準化 → 遞歸遍歷 → 批量持久化。掌握字段名映射、遞歸算法、數據庫批量操作三大技術點,即可高效處理各類層級數據導入需求。生產環境建議增加:增量同步機制、版本管理、數據校驗報告等企業級特性。