java递归处理树形结构数据

实战开发中常需处理树形菜单等业务,数据库设计建议用id<----->parentId结构,前端显示多用hightChart或Echart插件。本文介绍以递归方式将数据库结构化数据处理成treeJson格式,还说明了用Echarts处理最终效果的操作方法。

在实战开发中经常有需要处理树形菜单、树形目录等等等业务需求。而对于这种产品,在设计数据库时也建议使用id<----->parentId的结构来做。但是最终前端显示多用hightChart或者Echart插件来实现。所以在给前端数据时,最好的做法就是把数据库结构话的数据处理成treeJson格式。本文就简单介绍以递归方式处理此数据。

数据库表结构

idnametypeparentId
1root10
2a11
3b11
4c11
5d12
6e12
7f13
8g17

最终想要的效果

image.png

java 递归实现代码

package com.br.usercenter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.collections.map.HashedMap;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author jack cooper
 * @create 2017-09-15 16:53
 */
public class TreeRecursion {

    public static void main(String[] args) {

        Map<String,Node> nodes = new HashedMap();
        //模拟数据库存储树结构
        nodes.put("1",new Node("1","root",1,"0"));
        nodes.put("2",new Node("2","a",1,"1"));
        nodes.put("3",new Node("3","b",1,"1"));
        nodes.put("4",new Node("4","c",1,"1"));
        nodes.put("5",new Node("5","d",1,"2"));
        nodes.put("6",new Node("6","e",1,"2"));
        nodes.put("7",new Node("7","f",1,"3"));
        nodes.put("8",new Node("8","g",1,"7"));
        System.out.println("result:" + JSON.toJSONString(getNodeJson("0",nodes)));
    }

    /**
     * 递归处理   数据库树结构数据->树形json
     * @param nodeId
     * @param nodes
     * @return
     */
    public static JSONArray getNodeJson(String nodeId, Map<String,Node> nodes){

        //当前层级当前node对象
        Node cur = nodes.get(nodeId);
        //当前层级当前点下的所有子节点(实战中不要慢慢去查,一次加载到集合然后慢慢处理)
        List<Node> childList = getChildNodes(nodeId,nodes);

        JSONArray childTree = new JSONArray();
        for (Node node : childList) {
            JSONObject o = new JSONObject();
            o.put("name", node.getName());
            o.put("type", node.getType());
            JSONArray childs = getNodeJson(node.getId(),nodes);  //递归调用该方法
            if(!childs.isEmpty()) {
                o.put("children",childs);
            }
            childTree.fluentAdd(o);
        }
        return childTree;
    }

    /**
     * 获取当前节点的所有子节点
     * @param nodeId
     * @param nodes
     * @return
     */
    public static List<Node> getChildNodes(String nodeId, Map<String,Node> nodes){
        List<Node> list = new ArrayList<>();
        for (String key : nodes.keySet() ) {
            if(nodes.get(key).getParentId().equals(nodeId)){
                list.add(nodes.get(key));
            }
        }
        return list;
    }

}


class Node{
    public String id ;
    public String name;
    public Integer type;
    public String parentId;

    public Node(String id, String name, Integer type, String parentId) {
        this.id = id;
        this.name = name;
        this.type = type;
        this.parentId = parentId;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getType() {
        return type;
    }

    public void setType(Integer type) {
        this.type = type;
    }

    public String getParentId() {
        return parentId;
    }

    public void setParentId(String parentId) {
        this.parentId = parentId;
    }
}

最终结果json

[
    {
        "children": [
            {
                "children": [
                    {
                        "children": [
                            {
                                "name": "g",
                                "type": 1
                            }
                        ],
                        "name": "f",
                        "type": 1
                    }
                ],
                "name": "b",
                "type": 1
            },
            {
                "children": [
                    {
                        "name": "d",
                        "type": 1
                    },
                    {
                        "name": "e",
                        "type": 1
                    }
                ],
                "name": "a",
                "type": 1
            },
            {
                "name": "c",
                "type": 1
            }
        ],
        "name": "root",
        "type": 1
    }
]

用echart处理最终效果

访问http://echarts.baidu.com/echarts2/doc/example/tree1.html
在左侧json中找到data节点,将value替换成上述json。点击刷新即可。



作者:jackcooper
链接:https://www.jianshu.com/p/7da6c1182d69
来源:简书

### Java递归生成树形结构数据时缺少root节点的解决方案 在Java中,递归生成树形结构数据时如果没有明确指定根节点(root),可能会导致生成的树结构不完整或无法正确表示层级关系。为了解决这个问题,可以通过以下方式确保树形结构的完整性。 #### 1. 确保数据源包含根节点信息 在生成树形结构之前,需要确保数据源中每个节点都有一个`parentId`字段来标识其父节点。对于根节点,`parentId`通常设置为`null`或一个特殊的值(如`-1`)。通过这种方式,可以区分出哪些节点是根节点[^1]。 #### 2. 使用过滤逻辑提取根节点 在递归生成树形结构之前,可以先从数据源中筛选出所有根节点。例如,假设数据源是一个包含多个节点的列表,每个节点都有`id`和`parentId`字段,可以通过以下代码提取根节点: ```java List<Node> rootNodeList = nodeList.stream() .filter(node -> node.getParentId() == null || node.getParentId().equals(-1)) .collect(Collectors.toList()); ``` 这段代码使用了Java 8的流式操作,将`parentId`为`null`或`-1`的节点提取出来作为根节点[^2]。 #### 3. 递归构建子节点 在提取出根节点后,可以递归地为每个节点构建子节点。以下是一个示例代码: ```java public class Node { private Integer id; private Integer parentId; private List<Node> children; // Getter and Setter methods } public List<Node> buildTree(List<Node> nodeList) { Map<Integer, Node> nodeMap = nodeList.stream() .collect(Collectors.toMap(Node::getId, node -> node)); List<Node> rootNodes = new ArrayList<>(); for (Node node : nodeList) { if (node.getParentId() == null || !nodeMap.containsKey(node.getParentId())) { rootNodes.add(node); } else { Node parentNode = nodeMap.get(node.getParentId()); if (parentNode.getChildren() == null) { parentNode.setChildren(new ArrayList<>()); } parentNode.getChildren().add(node); } } return rootNodes; } ``` 上述代码首先将所有节点存储到一个`Map`中以便快速查找父节点,然后遍历每个节点,将其添加到对应的父节点的`children`列表中。如果某个节点没有父节点,则将其视为根节点并添加到`rootNodes`列表中。 #### 4. 处理特殊情况 在实际应用中,可能会遇到一些特殊情况,例如循环引用或孤立节点。为了确保树形结构的正确性,可以在递归过程中添加检查逻辑,避免无限递归或错误的层级关系[^3]。 --- ### 示例代码 以下是一个完整的示例代码,展示了如何递归生成树形结构数据: ```java import java.util.*; import java.util.stream.Collectors; class Node { private Integer id; private Integer parentId; private List<Node> children; public Node(Integer id, Integer parentId) { this.id = id; this.parentId = parentId; this.children = new ArrayList<>(); } public Integer getId() { return id; } public Integer getParentId() { return parentId; } public List<Node> getChildren() { return children; } public void setChildren(List<Node> children) { this.children = children; } @Override public String toString() { return "Node{id=" + id + ", children=" + children + "}"; } } public class TreeBuilder { public static List<Node> buildTree(List<Node> nodeList) { Map<Integer, Node> nodeMap = nodeList.stream() .collect(Collectors.toMap(Node::getId, node -> node)); List<Node> rootNodes = new ArrayList<>(); for (Node node : nodeList) { if (node.getParentId() == null || !nodeMap.containsKey(node.getParentId())) { rootNodes.add(node); } else { Node parentNode = nodeMap.get(node.getParentId()); parentNode.getChildren().add(node); } } return rootNodes; } public static void main(String[] args) { List<Node> nodeList = Arrays.asList( new Node(1, null), new Node(2, 1), new Node(3, 1), new Node(4, 2), new Node(5, 2) ); List<Node> tree = buildTree(nodeList); System.out.println(tree); } } ``` --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值