Java递归拼接json树形结构

有个需求需要后端生成json树,找了一个大佬的文章,没看懂,自己写一个吧

java+mysql递归拼接树形JSON列表_鬼畜的稀饭的博客-CSDN博客

新建`TestNode.java`类

package info;

import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import java.util.List;

@Data
public class TestNode
{
    private String menuId;

    private String name;

    private String pid;

    private List<TestNode> subMenu;

    private String fullName;

    private Integer level;

    private Boolean hasKeyword;

    @Override
    public String toString()
    {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
    }
}

新建test类

import com.alibaba.fastjson.JSONArray;
import info.TestNode;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class FileTest
{
    private List<TestNode> nodes = new ArrayList<>();


    @Test
    public void testMenu()
    {
        String str = "[{\"menuId\":\"1001\",\"pid\":null,\"name\":\"商品类目\"}, {\"menuId\":\"1002\",\"pid\":\"1001\",\"name\":\"日用品\"}, {\"menuId\":\"1003\",\"pid\":\"1001\",\"name\":\"食品\"}, {\"menuId\":\"1004\",\"pid\":\"1002\",\"name\":\"洗发水\"}, {\"menuId\":\"1005\",\"pid\":\"1004\",\"name\":\"飘柔\"},{\"menuId\":\"1006\",\"pid\":\"1002\",\"name\":\"化妆品\"}]";
        nodes = JSONArray.parseArray(str, TestNode.class);
        List<TestNode> treeNodes = new ArrayList<>();
        for (int i = 0; i < nodes.size(); i++)
        {
            TestNode rootNode = nodes.get(i);
            rootNode.setSubMenu(getChildNodes(rootNode));
            treeNodes.add(rootNode);
            nodes.remove(rootNode);
            i --;
        }
        System.out.println(treeNodes);
    }

    private List<TestNode> getChildNodes(TestNode pNode)
    {
        List<TestNode> child = new LinkedList<>();
        for (int i = 0; i < this.nodes.size(); i++)
        {
            TestNode node = nodes.get(i);
            if (pNode.getMenuId().equals(node.getPid()))
            {
                node.setSubMenu(getChildNodes(node));
                child.add(node);
                this.nodes.remove(node);
                i --;
            }
        }
        return child;
    }
}

输出结果

[
    {
        "menuId": "1001",
        "name": "商品类目",
        "pid": null,
        "subMenu":
        [
            {
                "menuId": "1002",
                "name": "日用品",
                "pid": "1001",
                "subMenu":
                [
                    {
                        "menuId": "1004",
                        "name": "洗发水",
                        "pid": "1002",
                        "subMenu":
                        [
                            {
                                "menuId": "1005",
                                "name": "飘柔",
                                "pid": "1004",
                                "subMenu":
                                []
                            }
                        ]
                    },
                    {
                        "menuId": "1006",
                        "name": "化妆品",
                        "pid": "1002",
                        "subMenu":
                        []
                    }
                ]
            },
            {
                "menuId": "1003",
                "name": "食品",
                "pid": "1001",
                "subMenu":
                []
            }
        ]
    }
]

------------------------------------------------------------分隔符------------------------------------------------------------

package test;

import com.alibaba.fastjson.JSONArray;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;

import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;

public class TestNode2 {

    /**
     * 组装树形结构
     */
    @Test
    public void testMenu() {
        String str = "[{\"menuId\":\"1001\",\"pid\":null,\"name\":\"商品类目\"}, {\"menuId\":\"1002\",\"pid\":\"1001\",\"name\":\"日用品\"}, {\"menuId\":\"1003\",\"pid\":\"1001\",\"name\":\"食品\"}, {\"menuId\":\"1004\",\"pid\":\"1002\",\"name\":\"洗发水\"}, {\"menuId\":\"1005\",\"pid\":\"1004\",\"name\":\"飘柔\"},{\"menuId\":\"1006\",\"pid\":\"1002\",\"name\":\"化妆品\"}]";
        List<TestNode> nodes = JSONArray.parseArray(str, TestNode.class);
        //父级节点列表
        List<TestNode> parentList = nodes.stream().filter(v -> StringUtils.isBlank(v.getPid())).collect(Collectors.toList());
        //根据父元素分组
        Map<String, List<TestNode>> nodeMap = nodes.stream().filter(v -> StringUtils.isNotBlank(v.getPid())).collect(Collectors.groupingBy(TestNode::getPid));
        //根据menuId
        Map<String, TestNode> singleNodeMap = nodes.stream().collect(Collectors.toMap(TestNode::getMenuId, v -> v));
        for (TestNode node : nodes) {
            StringBuilder fullName = new StringBuilder();
            int level = setFullNameAddGetLevel(node, fullName, singleNodeMap, 0);
            node.setFullName(StringUtils.removeFirst(fullName.toString(), "-"));
            node.setLevel(level);
        }
        long start = System.currentTimeMillis();

        for (TestNode node : parentList) {
            getChildNodes(node, nodeMap);
        }

        System.out.println(parentList);
        System.out.println(System.currentTimeMillis() - start);
    }

    /**
     * 判断是否具有最底层节点
     */
    @Test
    public void testNullMenu() {
        String str = "[{\"menuId\":\"1001\",\"pid\":null,\"name\":\"商品类目\"}, {\"menuId\":\"1002\",\"pid\":\"1001\",\"name\":\"日用品\"}, {\"menuId\":\"1003\",\"pid\":\"1001\",\"name\":\"食品\"}, {\"menuId\":\"1004\",\"pid\":\"1002\",\"name\":\"洗发水\"}, {\"menuId\":\"1005\",\"pid\":\"1004\",\"name\":\"飘柔\"},{\"menuId\":\"1006\",\"pid\":\"1002\",\"name\":\"化妆品\"}]";
        List<TestNode> nodes = JSONArray.parseArray(str, TestNode.class);

        // 单map
        Map<String, TestNode> singleNodeMap = nodes.stream().collect(Collectors.toMap(TestNode::getMenuId, v -> v));
        for (TestNode node : nodes) {
            StringBuilder fullName = new StringBuilder();
            int level = setFullNameAddGetLevel(node, fullName, singleNodeMap, 0);
            node.setFullName(StringUtils.removeFirst(fullName.toString(), "-"));
            node.setLevel(level);
        }

        //https://blog.csdn.net/zhuhao717/article/details/47444763
        //HashMap是按照HashCode 排序,莫名其妙的顺序。 
        //TreeMap是按照自身的顺序排序,比如数字的话,按照数字升序,ascII等。 
        //LinkedHashMap是按照先进先出的顺序。
        TreeMap<Integer, List<TestNode>> levelMap = nodes.stream().collect(Collectors.groupingBy(TestNode::getLevel, TreeMap::new, Collectors.toList()));
        //获取最底层列表
        List<TestNode> maxLevelList = levelMap.get(levelMap.size());
        for (TestNode testNode : maxLevelList) {
            checkHasKeyword(testNode, singleNodeMap);
        }
        System.out.println(nodes);
    }

    private void checkHasKeyword(TestNode node, Map<String, TestNode> nodeMap) {
        node.setHasKeyword(true);
        if (StringUtils.isBlank(node.getPid())) {
            return;
        }
        TestNode parentNode = nodeMap.get(node.getPid());
        checkHasKeyword(parentNode, nodeMap);
    }

    private int setFullNameAddGetLevel(TestNode node, StringBuilder fullName, Map<String, TestNode> nodeMap, int level) {
        level++;
        fullName.insert(0, String.format("-%s", node.getName()));
        if (StringUtils.isBlank(node.getPid())) {
            return level;
        }
        TestNode parentNode = nodeMap.get(node.getPid());
        return setFullNameAddGetLevel(parentNode, fullName, nodeMap, level);
    }

    private void getChildNodes(TestNode pNode, Map<String, List<TestNode>> nodeMap) {
        List<TestNode> childNodes = nodeMap.get(pNode.getMenuId());
        if (childNodes == null) {
            return;
        }
        pNode.setSubMenu(childNodes);
        for (TestNode childNode : childNodes) {
            getChildNodes(childNode, nodeMap);
        }
    }
}

---------------------------------------------------------分隔符-------------------------------------------------------------

获取自己负责的团队及子团队

package com.hxg.core.test.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Team {
    /**
     * 团队uid
     */
    private String uid;

    /**
     * 团队名称
     */
    private String teamName;

    /**
     * 负责人uid
     */
    private String leaderUid;

    /**
     * 父团队uid
     */
    private String parentUid;
}
package test;

import com.hxg.core.test.model.Team;
import org.junit.Test;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class TestTeam {
    @Test
    public void test() {
        List<Team> teams = new ArrayList<>();
        Team team1 = new Team("1001", "团队1", "2001", "");
        Team team2 = new Team("1002", "团队2", "2002", "1001");
        Team team3 = new Team("1003", "团队3", "2003", "1001");
        Team team4 = new Team("1004", "团队4", "2004", "1002");
        Team team5 = new Team("1005", "团队5", "2005", "1004");
        Team team6 = new Team("1006", "团队6", "2001", "");
        Team team7 = new Team("1007", "团队7", "2002", "");
        Team team8 = new Team("1008", "团队8", "2005", "1005");
        Team team9 = new Team("1009", "团队9", "2006", "1007");
        teams.add(team1);
        teams.add(team2);
        teams.add(team3);
        teams.add(team4);
        teams.add(team5);
        teams.add(team6);
        teams.add(team7);
        teams.add(team8);
        teams.add(team9);
        Set<String> leaderTeamSet = new HashSet<>();
        leaderTeamSet.add("1001");
        //前提:父团队的uid比子团队的uid大
        for (Team team : teams) {
            if (leaderTeamSet.contains(team.getUid()) || leaderTeamSet.contains(team.getParentUid())) {
                leaderTeamSet.add(team.getUid());
                System.out.println(team.getTeamName());
            }
        }
    }
}

如果有隐藏bug或者性能优化建议,还请各位路过大佬不吝赐教。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值