• 树形工具类


    树形结构

    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);
        }
    }
    
  • 相关阅读:
    图文详解——将本地项目上传到码云(gitee)远程仓库
    mysql 查询正在执行的sql
    MySql 缓冲池(buffer pool) 和 写缓存(change buffer) 转
    SQLserver 查询某个表的字段及字段属性
    FastDFS 客户端(二)
    FastDFS 服务器(一)
    C# WPF 正常的项目突然提示 当前上下文中不存在名称“InitializeComponent”
    C# 程序自动重启的解决方法
    Array知识点总结(一)
    JavaScript中为false的情况归档
  • 原文地址:https://www.cnblogs.com/qiaozhuangshi/p/11086539.html
Copyright © 2020-2023  润新知