[记录] 树结构转换工具类

util

/**
 * 适配 element-ui 的树结构工具类
 *
 * @Author zbinyds
 * @Create 2023-07-19 20:32
 */

public class TreeUtil {

    /**
     * 日志
     */
    private static final Logger log = LoggerFactory.getLogger(TreeUtil.class);

    /**
     * 根节点id
     */
    public static final Long rootId = 0L;

    /**
     * 递归深层遍历, 获取树结构(已弃用)
     *
     * @param source 资源列表(非树结构)
     * @return List<E>  树结构
     * @deprecated please see TreeUtil.toTree(List<E> source)
     */
    @Deprecated
    @SuppressWarnings("unchecked")
    public static <E extends TreeNode<E, T>, T> List<E> buildTree(List<E> source) {
        return source.stream()
                .filter(TreeUtil::isRootNode)
                .peek(treeNode -> treeNode.setChildren(isNotEmpty(buildChildrenTree(treeNode, source)) ? (List<TreeNode<E, T>>) buildChildrenTree(treeNode, source) : null))
                .collect(Collectors.toList());
    }

    /**
     * 获取当前节点下的所有节点, 最终返回树结构(已弃用)
     *
     * @param currentNode 当前节点
     * @param source      资源列表(非树结构)
     * @return List<E>    树结构
     * @deprecated please see TreeUtil.toTree(TreeNode<E, T> currentNode, List<E> source)
     */
    @Deprecated
    @SuppressWarnings("unchecked")
    public static <E extends TreeNode<E, T>, T> List<E> buildChildrenTree(TreeNode<E, T> currentNode, List<E> source) {
        if (currentNode == null || isNotValid(source)) {
            log.error("currentNode is not be null or source is not be null and parentId, id is not be null!");
            throw new IllegalArgumentException("currentNode is not be null or source is not valid!");
        }

        return source.stream()
                .filter(treeNode -> Objects.equals(currentNode.getId(), treeNode.getParentId()))
                .peek(treeNode -> treeNode.setChildren(isNotEmpty(buildChildrenTree(treeNode, source)) ? (List<TreeNode<E, T>>) buildChildrenTree(treeNode, source) : null))
                .collect(Collectors.toList());
    }

    /**
     * 将目标资源列表转换为树结构
     *
     * @param source 资源列表(非树结构)
     * @return List<T> 树结构
     */
    public static <E extends TreeNode<E, T>, T> List<E> toTree(List<E> source) {
        if (isNotValid(source)) {
            log.error("source is not be null and parentId, id is not be null!");
            throw new IllegalArgumentException("source is not valid!");
        }
        Map<T, List<TreeNode<E, T>>> treeNodeMap = source.stream().collect(Collectors.groupingBy(TreeNode::getParentId, LinkedHashMap::new, Collectors.toList()));
        return source.stream().filter(Objects::nonNull).peek(node -> node.setChildren(treeNodeMap.get(node.getId()))).filter(TreeUtil::isRootNode).collect(Collectors.toList());
    }

    /**
     * 获取包括当前节点在内的所有节点, 最终返回树结构
     *
     * @param currentNodeId 当前节点id
     * @param source        资源列表(非树结构)
     * @return List<T>      树结构
     * @TODO 这里可以提供开关, 是否需要包含当前节点
     */
    public static <E extends TreeNode<E, T>, T> List<E> toTree(T currentNodeId, List<E> source) {
        if (currentNodeId == null || isNotValid(source)) {
            log.error("currentNodeId is not be null or source is not be null and parentId, id is not be null!");
            throw new IllegalArgumentException("currentNodeId is not be null or source is not valid!");
        }
        Map<T, List<TreeNode<E, T>>> treeNodeMap = source.stream().collect(Collectors.groupingBy(TreeNode::getParentId, LinkedHashMap::new, Collectors.toList()));
        return source.stream().filter(Objects::nonNull).peek(node -> node.setChildren(treeNodeMap.get(node.getId()))).filter(node -> Objects.equals(node.getId(), currentNodeId)).collect(Collectors.toList());
    }

    /**
     * 获取不包括当前节点在内的所有父节点, 最终返回树结构
     *
     * @param currentNodeId 当前节点id
     * @param source        资源列表(非树结构)
     * @return List<T>    树结构
     * @TODO 这里可以提供开关, 是否需要包含当前节点
     */
    public static <E extends TreeNode<E, T>, T> List<E> parentTree(T currentNodeId, List<E> source) {
        if (currentNodeId == null || isNotValid(source)) {
            log.error("currentNodeId is not be null or source is not be null and parentId, id is not be null!");
            throw new IllegalArgumentException("currentNodeId is not be null or source is not valid!");
        }
        // list to map
        Map<T, E> nodeMap = source.stream().collect(Collectors.toMap(E::getId, Function.identity()));
        // 当前节点不存在
        E currentNode = nodeMap.get(currentNodeId);
        if (currentNode == null) {
            return Collections.emptyList();
        }
        // 获取当前节点的所有父节点
        List<E> parents = new ArrayList<>();
        E parentNode = nodeMap.get(currentNode.getParentId());
        while (parentNode != null) {
            parents.add(parentNode);
            parentNode = nodeMap.get(parentNode.getParentId());
        }
        // toTree
        return toTree(parents);
    }

    /**
     * 是否为树的根节点
     *
     * @param treeNode 节点
     * @return boolean
     */
    public static <E, T> boolean isRootNode(TreeNode<E, T> treeNode) {
        return treeNode.getParentId().equals(rootId);
    }

    /**
     * 是否非 树的根节点
     *
     * @param treeNode 节点
     * @return boolean
     */
    public static <E, T> boolean isNotRootNode(TreeNode<E, T> treeNode) {
        return !isRootNode(treeNode);
    }

    /**
     * 判断目标资源是否不合法
     *
     * @param source 资源列表(非树结构)
     * @return boolean(false - 合法, true - 不合法)
     */
    public static <E extends TreeNode<E, T>, T> boolean isNotValid(List<E> source) {
        return source == null || source.stream().anyMatch(e ->
                Objects.isNull(e.getParentId()) || Objects.isNull(e.getId()) || Objects.equals(e.getId(), e.getParentId()));
    }

    /**
     * 判断给定资源列表是否为空
     *
     * @param source 资源列表
     * @return boolean
     */
    public static boolean isEmpty(Collection<?> source) {
        return source == null || source.isEmpty();
    }

    /**
     * 判断给定资源列表是否不为空
     *
     * @param source 资源列表
     * @return boolean
     */
    public static boolean isNotEmpty(Collection<?> source) {
        return !isEmpty(source);
    }
}

TreeNode

/**
 * TreeUtil-节点, 继承此类传入id, parentId即可
 *
 * @Author zbinyds@126.com
 * @Create 2023-07-19 19:33
 */

@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
public abstract class TreeNode<E, T> implements Serializable{

    private static final long serialVersionUID = 8817694414118390415L;

    /**
     * 当前节点id
     */
    private T id;

    /**
     * 父节点id
     */
    private T parentId;

    /**
     * 节点名称
     */
    private String label;

    /**
     * 额外携带的字段
     */
    private Map<String, Object> extra;

    /**
     * 子节点列表
     */
    private List<TreeNode<E, T>> children;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值