Java生成树形数据(思路见代码)

package com.company.tree;

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

/**
 * 基础树属性字段
 * todo 可以在此基础上扩展基础字段
 *
 * @author ldb
 * @ClassName BaseTree.java
 * @Data 2022-02-25 11:00
 */
public class BaseTree<T> {
    /**
     * id
     */
    String id;
    /**
     * 上级id
     */
    String ParentId;
    /**
     * 菜单等级
     */
    Integer level;
    /**
     * 子菜单
     */
    List<T> Children;
    /**
     * 菜单名称
     */
    String name;
    /**
     * 排序编号
     */
    Integer orderId;
    /**
     * id链
     */
    List<String> ids = new ArrayList<>();

    public String getId() {
        return id;
    }

    public List<String> getIds() {
        return ids;
    }

    public void setIds(List<String> ids) {
        this.ids = ids;
    }

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

    public String getParentId() {
        return ParentId;
    }

    public void setParentId(String parentId) {
        ParentId = parentId;
    }

    public Integer getLevel() {
        return level;
    }

    public void setLevel(Integer level) {
        this.level = level;
    }

    public List<T> getChildren() {
        return Children;
    }

    public void setChildren(List<T> children) {
        Children = children;
    }

    public String getName() {
        return name;
    }

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

    public Integer getOrderId() {
        return orderId;
    }

    public void setOrderId(Integer orderId) {
        this.orderId = orderId;
    }
}
package com.company.tree;

import java.io.Serializable;

/**
 * 菜单
 * todo 这个类是给用户显示数据的类,可以扩展额外属性
 *
 * @author ldb
 * @ClassName Menu.java
 * @Data 2022-02-25 9:54
 */
public class Menu extends BaseTree implements Serializable {

    public Menu(String id, String name, String parentId, Integer level, Integer orderId) {
        this.id = id;
        this.name = name;
        this.ParentId = parentId;
        this.level = level;
        this.orderId = orderId;
    }

}
package com.company.tree;

import com.alibaba.fastjson.JSON;

import java.util.*;

/**
 * 树工具类
 * 具体业务思路:
 * 新增:如果有上级节点,则找到上级并将当前等级加一即可
 * 修改: 主要修改的是上级节点和等级,同新增差不多
 * 删除: 删除当前节点,其子节点也会被删除(可以先查询该节点有没有下级id链)
 * 查询: 查询id链(这里可以通过递归查询)
 * 需要依赖:fastjson.jar
 *
 * @author ldb
 * @ClassName TreeTest.java
 * @Data 2022-02-25 9:57
 */
public class TreeUtil {
    public static List<Menu> menuTree = new ArrayList<>();

    static {
        menuTree.add(new Menu("1", "用户管理", "", 0, 0));
        menuTree.add(new Menu("2", "用户新增", "1", 1, 0));
        menuTree.add(new Menu("3", "用户修改", "1", 1, 0));
        menuTree.add(new Menu("4", "用户删除", "1", 1, 0));
        menuTree.add(new Menu("5", "用户删除-批量删除", "4", 2, 0));
        menuTree.add(new Menu("8", "用户删除-批量删除-全部删除", "5", 3, 0));
        menuTree.add(new Menu("6", "菜单管理", "", 0, 5));
        menuTree.add(new Menu("7", "系统管理", "", 0, 8));
    }

    public static void main(String[] args) {
        List<Menu> res = buildTree(menuTree);
        System.out.println("获取树形列表(通过集合获取):");
        System.out.println(JSON.toJSONString(res));
        System.out.println("在集合中查找id链(通过集合获取):");
        List<String> ids = findNodeIdsById(menuTree, "8");
        System.out.println(JSON.toJSONString(ids));
        System.out.println("在树中查找指定节点(通过树获取):");
        Menu node = findNodeById(res, "8");
        System.out.println(JSON.toJSONString(node));
    }

    /**
     * 构建树
     *
     * @param menuTree 集合列表
     * @return java.util.List<com.company.tree.Menu>
     * @author Ldb
     * @date 2022-02-25
     **/
    public static <T extends BaseTree> List<T> buildTree(List<T> menuTree) {
        // 初始化id链(这里的id链其实是可以提前就确定的)
        for (T t : menuTree) {
            t.setIds(findNodeIdsById(menuTree, t.getId()));
        }
        List<T> res = new ArrayList<>();
        Map<String, T> menuMap = new HashMap<>(5);
        // 集合转map
        for (T menu : menuTree) {
            menuMap.put(menu.getId(), menu);
        }
        // 再将一级菜单下的子菜单找到并放入到集合中
        for (Map.Entry<String, T> node : menuMap.entrySet()) {
            for (T menu : menuTree) {
                String parentId = menu.getParentId();
                if (!isEmpty(parentId) && parentId.equals(node.getKey())) {
                    T firth = node.getValue();
                    // 为空验证
                    if (null == firth.getChildren()) {
                        firth.setChildren(new ArrayList<>());
                    }
                    firth.getChildren().add(menu);
                    menuMap.put(firth.getId(), firth);
                }
            }
        }
        // 最后获取所有一级菜单
        for (Map.Entry<String, T> node : menuMap.entrySet()) {
            if (node.getValue().getLevel().equals(0)) {
                res.add(node.getValue());
            }
        }
        return res;
    }

    /**
     * 查询树中某个节点(从顶级依次递归查找)
     *
     * @param menuTree 树型数据
     * @param id       要查找的id
     * @author Ldb
     * @date 2022-02-26
     **/
    public static <T extends BaseTree> T findNodeById(List<T> menuTree, String id) {
        for (T curNode : menuTree) {
            // 从第一层开始查找,如果是就直接返回该对象
            if (curNode.getId().equals(id)) {
                return curNode;
            }
            // 如果第一层没有找到,则看下面有没有子节点,如果有子节点则递归查找
            if (null != curNode.getChildren() && curNode.getChildren().size() > 0) {
                return (T) findNodeById(curNode.getChildren(), id);
            }
        }
        // 如果没有找到任何节点,则默认返回空(当前层可能出现并没有找到得情况,所以上面也要return)
        return null;
    }

    /**
     * 查询某一个节点的id链
     *
     * @param list 集合列表
     * @param id   节点id
     * @return java.util.List<java.lang.String>
     * @author Ldb
     * @date 2022-02-26
     **/
    public static <T extends BaseTree> List<String> findNodeIdsById(List<T> list, String id) {
        Map<String, T> treeMaps = new HashMap<>(5);
        // 将所有列表添加到Map集合中
        for (T t : list) {
            treeMaps.put(t.getId(), t);
        }
        // 获取ids链
        List<String> ids = findIds(treeMaps, id, new ArrayList<>());
        if (ids == null) {
            return null;
        }
        // 因为id链是从尾部开始查找的,所以这里需要进行反转
        Collections.reverse(ids);
        return ids;
    }

    /**
     * 递归查找id链
     *
     * @param treeMaps 菜单列表Map
     * @param id       要找的节点
     * @param ids      id链
     * @return java.util.List<java.lang.String>
     * @author Ldb
     * @date 2022-02-26
     **/
    private static <T extends BaseTree> List<String> findIds(Map<String, T> treeMaps, String id, List<String> ids) {
        // 将当前id添加到集合中
        T t = treeMaps.get(id);
        if (t == null) {
            return null;
        }
        ids.add(t.getId());
        if (!isEmpty(t.getParentId())) {
            // 如果当前id有上级id则继续添加
            return findIds(treeMaps, t.getParentId(), ids);
        }
        // 获取结束后返回
        return ids;
    }

    /**
     * 判断字符串是否为空
     *
     * @param str 字符串
     * @return boolean
     * @author Ldb
     * @date 2022-02-26
     **/
    public static boolean isEmpty(String str) {
        if (null == str || str.trim().equals("")) {
            return true;
        }
        return false;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值