当前位置: 首页 > article >正文

Java解析多层嵌套JSON数组并将数据存入数据库示例

今天前端问我能不能帮忙把菜单数据存进去,我看了下大概就是下面这样的数据结构,就是一个 JSON 数组,然后里面有 children

[
	{
		"name": "1001",
		"path": "/1001",
		"component": "1001.base",
		"meta": {
			"title": "1001",
			"i18nKey": "1001.base",
			"order": 1
		},
		"children": [
			{
				"name": "100101",
				"path": "/1001/01",
				"component": "1001.01",
				"meta": {
					"title": "100101",
					"i18nKey": "1001.01"
				},
				"children": [
					{
						"name": "10010101",
						"path": "/1001/01/01",
						"component": "1001.01.01",
						"meta": {
							"title": "10010101",
							"i18nKey": "1001.01.01"
						}
					}
				]
			}
		]
	},
	{
		"name": "1002",
		"path": "/1002",
		"component": "1002.base",
		"meta": {
			"title": "1002",
			"i18nKey": "1002.base",
			"order": 1
		},
		"children": [
			{
				"name": "100201",
				"path": "/1002/01",
				"component": "1002.01",
				"meta": {
					"title": "100201",
					"i18nKey": "1002.01"
				}
			}
		]
	}
]

然后写了方法用来解析他给我的文本,这里因为里面就一个JSON格式的字符串,我直接把后缀改成了 .json,通过 JsonNode 再递归获取数据

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.File;
import java.sql.*;
import java.util.*;

public class MenuParser {
    private static final String DB_URL = "jdbc:mysql://192.168.1.119:3306/ceshi?useUnicode=true&characterEncoding=utf-8&useSSL=false";
    private static final String DB_USER = "admin";
    private static final String DB_PASSWORD = "px123456";

    public static void main(String[] args) {
        try {
            // 读取 JSON 文件
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode rootNode = objectMapper.readTree(new File("C:\\Users\\72364\\Desktop\\fsdownload\\menu.json"));

            // 存储菜单项,使用 tempId 作为 key
            Map<String, MenuItem> menuMap = new LinkedHashMap<>();
            parseMenu(rootNode, null, menuMap); // 递归解析

            // 插入数据到数据库,并更新 parentId
            insertMenusIntoDB(menuMap);

            System.out.println("✅ 数据插入成功,所有层级已正确关联!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * **递归解析 JSON,分配临时 ID,并维护父子关系**
     * @param nodeList JSON 菜单数据
     * @param parentTempId 父级的临时 ID
     * @param menuMap 存储解析后的菜单项
     */
    private static void parseMenu(JsonNode nodeList, String parentTempId, Map<String, MenuItem> menuMap) {
        for (JsonNode node : nodeList) {
            MenuItem menu = new MenuItem(node);
            String tempId = UUID.randomUUID().toString(); // 生成临时 ID
            menu.setTempId(tempId);
            menu.setParentTempId(parentTempId); // 关联父级的 tempId
            menuMap.put(tempId, menu);

            // 递归解析子菜单
            JsonNode children = node.get("children");
            if (children != null && children.isArray()) {
                parseMenu(children, tempId, menuMap);
            }
        }
    }

    /**
     * **插入菜单数据,并更新 parentId**
     * @param menuMap 存储解析后的菜单项
     */
    private static void insertMenusIntoDB(Map<String, MenuItem> menuMap) {
        String insertSQL = "INSERT INTO qy_platform_menu (parent_id, status, menu_type, menu_name, route_name, " +
                "route_path, component, `order`, i18nKey, icon, hide_in_menu, keep_alive, create_time, update_time, del_flag) " +
                "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW(), ?)";

        String updateSQL = "UPDATE qy_platform_menu SET parent_id = ? WHERE id = ?";

        Map<String, Long> tempIdToDbId = new HashMap<>(); // 记录 tempId → 数据库 ID

        try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD)) {
            conn.setAutoCommit(false); // 开启事务

            // **第一遍插入数据库**
            try (PreparedStatement pstmt = conn.prepareStatement(insertSQL, Statement.RETURN_GENERATED_KEYS)) {
                for (MenuItem menu : menuMap.values()) {
                    pstmt.setObject(1, null); // 先插入,parentId 设为 null
                    pstmt.setInt(2, 1);
                    pstmt.setString(3, menu.getMenuType());
                    pstmt.setString(4, menu.getMenuName());
                    pstmt.setString(5, menu.getRouteName());
                    pstmt.setString(6, menu.getRoutePath());
                    pstmt.setString(7, menu.getComponent());
                    pstmt.setInt(8, menu.getOrder() != null ? menu.getOrder() : 0);
                    pstmt.setString(9, menu.getI18nKey());
                    pstmt.setString(10, menu.getIcon());
                    pstmt.setInt(11, 0);
                    pstmt.setInt(12, 0);
                    pstmt.setInt(13, 0);

                    pstmt.executeUpdate();

                    // 获取新插入的 ID
                    try (ResultSet rs = pstmt.getGeneratedKeys()) {
                        if (rs.next()) {
                            long newId = rs.getLong(1);
                            tempIdToDbId.put(menu.getTempId(), newId);
                            menu.setId(newId);
                        }
                    }
                }
            }

            // **第二遍:更新 parentId**
            try (PreparedStatement updateStmt = conn.prepareStatement(updateSQL)) {
                for (MenuItem menu : menuMap.values()) {
                    if (menu.getParentTempId() != null && tempIdToDbId.containsKey(menu.getParentTempId())) {
                        long parentId = tempIdToDbId.get(menu.getParentTempId());
                        long menuId = menu.getId();

                        updateStmt.setLong(1, parentId);
                        updateStmt.setLong(2, menuId);
                        updateStmt.executeUpdate();
                    }
                }
            }

            conn.commit(); // 提交事务
            System.out.println("✅ 数据插入完成,parentId 关联成功!");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * **执行插入 SQL 并获取生成的 ID**
     */
    private static long insertMenuAndGetId(PreparedStatement pstmt, MenuItem menu) throws SQLException {
        pstmt.setObject(1, menu.getParentId());
        pstmt.setInt(2, 1);
        pstmt.setString(3, menu.getMenuType());
        pstmt.setString(4, menu.getMenuName());
        pstmt.setString(5, menu.getRouteName());
        pstmt.setString(6, menu.getRoutePath());
        pstmt.setString(7, menu.getComponent());
        pstmt.setInt(8, menu.getOrder() != null ? menu.getOrder() : 0);
        pstmt.setString(9, menu.getI18nKey());
        pstmt.setString(10, menu.getIcon());
        pstmt.setInt(11, 0);
        pstmt.setInt(12, 0);
        pstmt.setInt(13, 0);

        pstmt.executeUpdate();

        try (ResultSet rs = pstmt.getGeneratedKeys()) {
            if (rs.next()) {
                return rs.getLong(1);
            }
        }
        return -1;
    }
}

这里加了个临时 ID 用来处理上下级的父子关联

import com.fasterxml.jackson.databind.JsonNode;
import lombok.Data;

@Data
public class MenuItem {
    private Long id;             // 数据库 ID
    private Long parentId;       // 真实 parent_id
    private String tempId;       // 临时 ID
    private String parentTempId; // 临时 parent_id

    private Integer status;
    private String menuType;
    private String menuName;
    private String routeName;
    private String routePath;
    private String component;
    private Integer order;
    private String i18nKey;
    private String icon;

    public MenuItem(JsonNode node) {
        if (node.get("name") != null) this.routeName = node.get("name").asText();
        if (node.get("path") != null) this.routePath = node.get("path").asText();
        if (node.get("component") != null) this.component = node.get("component").asText();
        if (node.get("meta") != null) {
            if (node.get("meta").get("order") != null) this.order = node.get("meta").get("order").asInt();
            if (node.get("meta").get("title") != null) this.menuName = node.get("meta").get("title").asText();
            if (node.get("meta").get("i18nKey") != null) this.i18nKey = node.get("meta").get("i18nKey").asText();
            if (node.get("meta").get("icon") != null) this.icon = node.get("meta").get("icon").asText();
        }
    }
}

可以看到数据正常存进去了

在这里插入图片描述


http://www.kler.cn/a/594168.html

相关文章:

  • 软考中级-软件设计师 准备
  • 【redis】AOF 的基本工作机制,顺序写入,文件同步,重写机制
  • JAVA URL和URI差异对比
  • 星型组网和路由器组网的区别
  • UMA架构下的GPU 显存
  • CSS 用于图片的样式属性
  • 基于微信小程序的充电桩管理系统
  • vector和list的区别是什么
  • OpenCV第1课OpenCV 介绍及其树莓派下环境的搭建
  • 如何用日事清做研发目标、需求、规划、迭代、Bug、效能、复盘、绩效一站式管理
  • 前后端联调解决跨域问题的方案
  • 基于springboot的房产销售系统(016)
  • Linux 一步部署DHCP服务
  • mysql5.6忘记密码怎么重置mysql密码
  • rust学习笔记16-206.反转链表(递归)
  • 第7章 类与面向对象
  • Kotlin v2.1.20 发布,标准库又有哪些变化?
  • 使用Java爬虫根据关键词获取Shopee商品列表?
  • 渲染模式、基础组件、矢量图、样式设置——微信小程序学习笔记
  • 14-图论-多源最短路径Floyd算法