树形工具类

树形结构

1、根据父子结构生成Tree数据

tree_node 表结构
+-----------+-------------+------+-----+---------+-------+
| Field     | Type        | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| id        | int(11)     | NO   | PRI | NULL    |       |
| icon      | varchar(50) | YES  |     | NULL    |       |
| name      | varchar(50) | YES  |     | NULL    |       |
| parent_id | int(11)     | NO   |     | NULL    |       |
+-----------+-------------+------+-----+---------+-------+
表数据
+----------+------+-------+-----------+
| id       | icon | name  | parent_id |
+----------+------+-------+-----------+
|        1 | NULL | 根1     |         0 |
|        2 | NULL | 根2     |         0 |
|        3 | NULL | 根3     |         0 |
|    10001 | NULL | 子11    |         1 |
|    10002 | NULL | 子12    |         1 |
|    20001 | NULL | 子21    |         2 |
| 10001001 | NULL | 子111   |     10001 |
| 10001002 | NULL | 子112   |     10001 |
| 20001001 | NULL | 子211   |     20001 |
+----------+------+-------+-----------+

springboot连接

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springbootdemo
    username: root
    password: 123456

Dao层

public interface TreeNodeRepository extends JpaRepository<TreeNode, Integer> {
}

controller层

@RequestMapping("/getTreeNode")
public List<Tree> getTreeNode() {
    List<TreeNode> nodes = repository.findAll();
    List<Tree> treeNodes = new ArrayList<>();
    nodes.forEach(node -> {
        treeNodes.add(node);
    });
    return TreeUtil.getTree(treeNodes, 0);
}

Tree接口

public interface Tree {
    /** 当前节点id*/
    Integer id = 0;

    /** 父节点id*/
    Integer parentId = 0;

    /** 子节点集合*/
    List<Tree> childrens = null;

    Integer getId();

    void setId(Integer id);

    Integer getParentId();

    void setParentId(Integer id);

    List<Tree> getChildrens();

    void setChildrens(List<Tree> childrens);
}

TreeNode实现类

@Table(name = "tree_node")
@Entity
@Data
public class TreeNode implements Tree {

    /**
     * 当前节点id
     */
    @Id
    @Column(unique = true, length = 20, nullable = false)
    private Integer id;
    

    /**
     * 父节点
     */
    @Column(length = 20, nullable = false)
    private Integer parentId;

    /**
     * 节点图标
     */
    @Column(length = 50)
    private String icon;

    /**
     * 节点名称
     */
    @Column(length = 50)
    private String name;

    /**
     * 子节点
     */
    @Transient
    private List<Tree> childrens;
}

TreeUtil工具方法 主要是这个类

public class TreeUtil {

    /**
     * 生成树型数据
     * @param nodes     树的基础数据
     * @param rootId    根的唯一标识
     * @return
     */
    public static final List<Tree> getTree(List<Tree> nodes, Integer rootId) {
        List<Tree> treeList = new ArrayList<>();
        if (nodes == null || nodes.size() <= 0) {
            return treeList;
        }
        // 根点集合
        List<Tree> rootNodes = new ArrayList<>();
        // 子节点集合
        List<Tree> childNodes = new ArrayList<>();
        nodes.forEach(node-> {
            Integer parentId = node.getParentId();
            // 当父节点为0时  当前节点为根节点
            if (rootId.equals(parentId)) {
                rootNodes.add(node);
            } else {
                childNodes.add(node);
            }
        });

        rootNodes.forEach(rootNode -> {
            addChilds(rootNode, childNodes);
        });
        return rootNodes;
    }

    /**
     * 为父节点添加所有的子节点
     * 一次性获取父节点的所有子节点(然后遍历子节点,把当前子节点当作父节点,为该节点再添加子节点)
     * @param parentNode    当前节点
     * @param childNodes    所有的节点
     */
    private static void addChilds(Tree parentNode, List<Tree> childNodes) {
        List<Tree> childs = getChilds(parentNode, childNodes);
        if (childs.size() > 0) {
            parentNode.setChildrens(childs);
            //为每一个子节点获取所有的自己的子节点
            childs.forEach(p_node -> {
                addChilds(p_node, childNodes);
            });
        }
    }

    /**
     * 获取父节点的所有直接子节点
     */
    private static List<Tree> getChilds(Tree rootNode, List<Tree> childNodes) {
        Integer id = rootNode.getId();
        List<Tree> nextNodes = new ArrayList<>();
        childNodes.forEach(childNode -> {
            Integer parentId = childNode.getParentId();
            if (id.equals(parentId)) {
                nextNodes.add(childNode);
            }
        });
        return nextNodes;
    }

}

2、 根据目录字符串生成Tree结构

结构如下:

​ String[] paths = {"a/b/c/cc.xml", "a/b/bb.xml", "a/d/dd.xml", "e/e.xml"};

|--a
   |--b
	|--c
	  |--cc.xml
	|--bb.xml
   |-->d
  	  |-->dd.xml
|--e
   |-->e.xml

树节点实体

@Data
public class FTPDir {

    /**
     * 文件名
     */
    private String label;

    /**
     * 文件全路径
     */
    private String fullPath;

    /**
     * 子文件
     */
    private List<FTPDir> childrens;

    /**
     * 类型或者文件(可以使用枚举)
     */
    private String type;
}

生成操作

package per.qiao.util;

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

/**
 * Create by IntelliJ Idea 2018.2
 * 生成文件结构的树
 *
 * @author: qyp
 * Date: 2019-06-27 10:40
 */
public class TreeDir {

    private static final String FILE_TYPE = "file";
    private static final String DIR_TYPE = "dir";


    public static void main(String[] args) {
        Map<String, FTPDir> nodeMap = new HashMap<>();
        String[] paths = {"a/b/c/cc.xml", "a/b/bb.xml", "a/d/dd.xml", "e/e.xml"};
        loadDirs(paths, nodeMap);
        System.out.println(nodeMap);
    }

    public static void loadDirs(String[] paths, Map<String, FTPDir> exists) {
        List<String> existsList = new ArrayList<>();
        for (String p : paths) {

            int idx = p.lastIndexOf("/");
            if (idx > -1) {
                String parentPath = p.substring(0, idx);
                //加载父节点
                loadRoom(parentPath, exists, existsList);
            }
                //加载当前文件
            loadRoom(p, exists, existsList);
        }
    }

    /**
     * 加载一条路径下的所有节点
     * @param path  路径
     * @param nodeMap  节点集(最后的节点收集器)
     * @param exists    已经存在的节点路径(用来判断当前节点是否已经被添加过)
     */
    public static void loadRoom(String path, Map<String, FTPDir> nodeMap, List<String> exists) {

        //当前路径已经存在
        if (exists.contains(path)) {
            return;
        }
        // 含文件的路径
        if (path.contains(".")) {
            int idx = path.lastIndexOf("/");
            String parentPath = path.substring(0, idx);
            //当前节点的名字
            String nodeName = path.substring(idx + 1);
            if (exists.contains(parentPath)) {

                FTPDir fileNode = new FTPDir();
                fileNode.setFullPath(path);
                fileNode.setLabel(nodeName);
                fileNode.setType(FILE_TYPE);

                //获取目标父节点
                FTPDir parentNode = getNodeByPath(parentPath, nodeMap);

                List<FTPDir> childrens = parentNode.getChildrens();
                if (childrens == null) {
                    childrens = new ArrayList<>();
                    parentNode.setChildrens(childrens);
                }
                childrens.add(fileNode);
            }
        } else {  //文件夹路径
            String nodeName = null;
            FTPDir parentNode = null;
            if (path.contains("/")) {
                int idx = path.lastIndexOf("/");
                String parentPath = path.substring(0, idx);
                nodeName = path.substring(idx + 1);
                loadRoom(parentPath, nodeMap, exists);
                parentNode = getNodeByPath(parentPath, nodeMap);
            } else {
                nodeName = path;
            }

            FTPDir dirNode = new FTPDir();
            dirNode.setFullPath(path);
            dirNode.setLabel(nodeName);
            dirNode.setType(DIR_TYPE);

            //子节点添加到父节点
            if (parentNode != null) {
                List<FTPDir> childrens = parentNode.getChildrens();
                if (childrens == null) {
                    childrens = new ArrayList<>();
                    parentNode.setChildrens(childrens);
                }
                childrens.add(dirNode);
            } else {
                nodeMap.put(path, dirNode);
            }
            //目录节点
            exists.add(path);
        }

    }

    /**
     * 根据路径获取该路径对应的节点
     * @param path 节点的路径(id)
     * @param nodeMap 节点集
     * @return
     */
    private static FTPDir getNodeByPath(String path, Map<String, FTPDir> nodeMap) {

        //根节点直接返回,nodeMap中第一层都是根节点
        if (nodeMap.containsKey(path)) {
            return nodeMap.get(path);
        }

        String[] ps = path.split("/");
        //根节点
        FTPDir node = nodeMap.get(ps[0]);
        return getDirNode(path, node, ps, 1);

    }

    /**
     * 根据路径获取该路径对应的节点
     * @param path 需要查找的节点路径
     * @param node 该节点所在的根节点
     * @param ps   该节点每一层的名称(不包括第一层,也是就根节点)
     * @param idx  当前所在层
     * @return
     */
    private static FTPDir getDirNode(String path, FTPDir node, String[] ps, int idx) {
        List<FTPDir> childrens = node.getChildrens();
        if (childrens == null) {
            childrens = new ArrayList<>();
            node.setChildrens(childrens);
        }
        for (FTPDir c_node : childrens) {
            String name = c_node.getLabel();
            //去掉多余的遍历
            if (!ps[idx].equals(name)) {
                continue;
            }
            if (path.equals(c_node.getFullPath())) {
                return c_node;
            }
            FTPDir targetNode = getDirNode(path, c_node, ps, idx + 1);
            if (targetNode != null) {
                return targetNode;
            }
        }
        return null;
    }
}

下面贡献第二种写法

class TreeNode {
    private String id;
    private String name;
    private List<TreeNode> childrends;

    public TreeNode(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public static TreeNode getNode(String id, String name) {
        return new TreeNode(id, name);
    }


    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 List<TreeNode> getChildrends() {
        return childrends;
    }

    public void setChildrends(List<TreeNode> childrends) {
        this.childrends = childrends;
    }
}
public class FileTree {

    public static void main(String[] args) {
        String[] trees = {"a/b/c/cc.xml", "a/b/bb.xml", "a/d/dd.xml", "e/e.xml"};
        List<TreeNode> treeNodes = getTree(trees);
        System.out.println(treeNodes);
    }
    private static List<TreeNode> getTree (String[] trees) {
        Map<String, TreeNode> nodeMap = new HashMap<>(16);
        String pt = null;
        for (String tree : trees) {
            String[] split = tree.split("/");
            for (String s : split) {
                if (pt != null) {
                    pt += "/" + s;
                } else {
                    pt = s;
                }
                if (nodeMap.containsKey(pt)) {
                    continue;
                }
                loadTree(pt, nodeMap);
            }
            pt = null;
        }
        return nodeMap.entrySet().stream()
                .filter(me -> !me.getKey().contains("/"))
                .map(me -> me.getValue())
                .collect(Collectors.toList());

    }

    private static void loadTree(String path, Map<String, TreeNode> nodeMap) {
        String nodeName = path.substring(path.lastIndexOf("/") + 1);
        if (path.contains(".")) {
            addChildrens(path, TreeNode.getNode(path, nodeName), nodeMap);
        } else {
            //目录节点
            TreeNode node = TreeNode.getNode(path, nodeName);
            if (path.contains("/")) {
                //父节点路径
                addChildrens(path, node, nodeMap);
            }
            nodeMap.putIfAbsent(path, node);
        }
    }
    /**
     * 在父节点上挂载当前子节点
     * @param path 当前节点的路径
     * @param currentNode 当前节点
     * @param nodeMap 节点集合
     */
    private static void addChildrens(String path, TreeNode currentNode, Map<String, TreeNode> nodeMap) {
        // 父节点路径
        String parentNodePath = path.substring(0, path.lastIndexOf("/"));
        // 文件节点
        TreeNode treeNode = nodeMap.get(parentNodePath);
        List<TreeNode> childrends = treeNode.getChildrends();
        if (childrends == null) {
            childrends = new ArrayList<>();
            treeNode.setChildrends(childrends);
        }
        childrends.add(currentNode);
    }
}
posted @ 2019-06-25 20:49  复合式→展开式  阅读(375)  评论(0编辑  收藏  举报