2021-07-15


通过指定code,parentCode 支持对不同

点击查询最近更新的工具类

转换方法

package org.fffnfg.util.convert.enhancen;

import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.fffnfg.util.check.collect.CollectionUtils;

import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

@Slf4j
public class ConvertTreeUtils<T> {

    /**
     * 是否为根节点
     */
    @Setter
    private Predicate<T> isRoot;
    private Function<T, String> code;
    private Function<T, String> parent;
    private Function<TreeDTO<T>, Integer> order;
    private List<T> list;

    public ConvertTreeUtils(Function<T, String> code, Function<T, String> parent, Function<TreeDTO<T>, Integer> order) {
        this.code = code;
        this.parent = parent;
        this.order = order;
    }

    /**
     * 转换为树结构
     *
     * @param list 元数据列表
     * @return 树结构
     */
    public List<TreeDTO<T>> getTreeList(List<T> list) {
        if (Objects.isNull(isRoot)) {
            log.debug("未自定义根节点判断方法,父节点为空<==>根节点");
        }
        this.list = list;
        if (!CollectionUtils.isEmpty(list)) {
            Map<String, TreeDTO<T>> resultMap = new HashMap<>(8);
            for (T node : list) {
                setMenus(node, resultMap);
            }
            return seekRootTrees(resultMap);
        }
        return new ArrayList<>(0);
    }

    /**
     * 为当前节点设置层级关系
     *
     * @param node      当前节点
     * @param resultMap 结果集
     */
    private void setMenus(final T node, final Map<String, TreeDTO<T>> resultMap) {
        setMenus(node, resultMap, 1);
    }

    private void setMenus(final T node, final Map<String, TreeDTO<T>> resultMap, int level) {
        if (log.isDebugEnabled()) {
            StringBuilder step = new StringBuilder();
            for (int i = 0; i < level; i++) {
                step.append("|--");
            }
            log.debug("{}", step.append(node));
        }
        if (Objects.isNull(node)) {
            log.info("node 不能为空!");
            return;
        } else if (Objects.nonNull(code.apply(node)) && code.apply(node).equals(parent.apply(node))) {
            log.error("不能指向自身;{}", node);
            return;
        }
        TreeDTO<T> treeNode = resultMap.get(code.apply(node));
        if (Objects.isNull(treeNode)) {
            treeNode = getTreeDTO(node);
        }
        // 如果是根节点
        if (isRootNode(node)) {
            TreeDTO<T> parentApply = resultMap.get(parent.apply(node));
            if (Objects.isNull(parentApply)) {
                resultMap.put(code.apply(node), treeNode);
            }
        }
        // 父节点不存在
        else if (Objects.isNull(resultMap.get(parent.apply(node)))) {
            // 获取父节点
            T parentNode = getByCode(parent.apply(node));
            if (Objects.nonNull(parentNode)) {
                setMenus(parentNode, resultMap, ++level);
                // 设置当前节点
                TreeDTO<T> parentTree = getTreeDTO(parentNode);
                parentTree.getChildren().add(treeNode);
                resultMap.put(code.apply(parentNode), parentTree);
            } else {
                log.info("无父节点: {}", node);
            }
        } else {
            TreeDTO<T> parentTree = resultMap.get(parent.apply(node));
            // 设置当前节点
            parentTree.getChildren().add(treeNode);
            resultMap.put(code.apply(node), treeNode);
        }
    }

    /**
     * 是否为根节点
     *
     * @param node 当前节点
     * @return 是否为根节点
     */
    private boolean isRootNode(T node) {
        return Objects.isNull(isRoot) ? Objects.isNull(parent.apply(node)) : isRoot.test(node);
    }

    /**
     * 在list中找到code对应的值
     *
     * @param code 节点编码
     * @return 列表中的节点
     */
    private T getByCode(String code) {
        for (T t : list) {
            if (code.equals(this.code.apply(t))) {
                return t;
            }
        }
        return null;
    }

    /**
     * @param node 节点
     * @param <T>  节点类
     * @return 包装树形结构
     */
    private <T> TreeDTO<T> getTreeDTO(T node) {
        TreeDTO<T> tree = new TreeDTO<>();
        tree.setNode(node);
        if (Objects.isNull(tree.getChildren())) {
            tree.setChildren(new ArrayList<>(8));
        }
        return tree;
    }

    /**
     * 字节点排序
     *
     * @param tTreeDTO 当前节点
     */
    private void sort(TreeDTO<T> tTreeDTO) {
        List<TreeDTO<T>> children = tTreeDTO.getChildren();
        if (!CollectionUtils.isEmpty(children) && children.size() > 1) {
            children.sort(Comparator.comparing(order));
            for (TreeDTO<T> subChildren : children) {
                sort(subChildren);
            }
        }
    }

    /**
     * 从根节点开始寻找
     *
     * @param resultMap 结果集合
     * @return 根节点列表
     */
    private List<TreeDTO<T>> seekRootTrees(Map<String, TreeDTO<T>> resultMap) {
        // map 转List 重排序
        List<TreeDTO<T>> result = new ArrayList<>(resultMap.values());
        result = result.stream().filter(tree -> Objects.isNull(isRoot) ?
                Objects.isNull(parent.apply(tree.getNode())) :
                isRoot.test(tree.getNode())).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(result) && result.size() > 1) {
            result.sort(Comparator.comparing(order));
            //子节点重排序
            for (TreeDTO<T> tTreeDTO : result) {
                sort(tTreeDTO);
            }
        }
        return result;
    }
}

树形结构实体类

package org.fffnfg.util.convert.enhancen;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.util.List;

@Setter
@Getter
@ToString
public class TreeDTO<T> {
    T node;
    List<TreeDTO<T>> children;
}

使用方法

package org.fffnfg.util.convert.enhancen;

import com.alibaba.fastjson.JSONObject;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

/**
 * @author peng0806@foxmail.com
 * @Date 2021/7/14 下午9:34
 */
public class ConvertTreeUtilsTest1 {
    @Test
    public void GetTreeList() {
        Function<Node, String> code = node -> node.code;
        Function<Node, String> parentCode = node -> node.parentCode;
        Function<TreeDTO<Node>, Integer> order = node -> node.getNode().getOrder();

        ConvertTreeUtils<Node> convertTreeUtils = new ConvertTreeUtils<>(code, parentCode, order);
        int total = 50;
        List<Node> list = new ArrayList<>(total);
        setList(list);
//        for (Node node : list) {
//            System.out.println(JSONObject.toJSON(node));
//        }
//
        List<TreeDTO<Node>> res = convertTreeUtils.getTreeList(list);
        System.out.println("========= total\t" + res.size());
        System.out.println(JSONObject.toJSON(res));
//        for (TreeDTO<Node> re : res) {
//        }
    }

    private void setList(List<Node> list) {
        Node node9 = new Node();
        node9.setId(9);
        node9.setCode("left9");
        node9.setParentCode("sub8");
        node9.setName("code1");
        node9.setOrder(1);
        Node node8 = new Node();
        node8.setId(8);
        node8.setCode("sub8");
        node8.setParentCode("group4");
        node8.setName("code1");
        node8.setOrder(3);
        Node node7 = new Node();
        node7.setId(7);
        node7.setCode("sub7");
        node7.setParentCode("sub6");
        node7.setName("code1");
        node7.setOrder(1);
        Node node6 = new Node();
        node6.setId(6);
        node6.setCode("sub6");
        node6.setParentCode("group3");
        node6.setName("code1");
        node6.setOrder(1);
        Node node5 = new Node();
        node5.setId(5);
        node5.setCode("group5");
        node5.setParentCode("group3");
        node5.setName("code1");
        node5.setOrder(1);
        Node node4 = new Node();
        node4.setId(4);
        node4.setCode("group4");
        node4.setParentCode("group3");
        node4.setName("group1");
        node4.setOrder(1);
        Node node3 = new Node();
        node3.setId(3);
        node3.setCode("group3");
        node3.setParentCode("root1");
        node3.setName("root3");
        node3.setOrder(1);
        Node node2 = new Node();
        node2.setId(2);
        node2.setCode("root2");
        node2.setParentCode(null);
        node2.setName("root2");
        node2.setOrder(1);
        Node node1 = new Node();
        node1.setId(1);
        node1.setCode("root1");
        node1.setParentCode(null);
        node1.setName("root1");
        node1.setOrder(1);
        Node node = new Node();
        node.setId(0);
        node.setCode("root0");
        node.setParentCode(null);
        node.setName("root0");
        node.setOrder(1);
        list.add(node7);
        list.add(node8);
        list.add(node9);
        list.add(node4);
        list.add(node5);
        list.add(node6);
        list.add(node);
        list.add(node1);
        list.add(node2);
        list.add(node3);
    }


}

测试使用的待转换类


package org.fffnfg.util.convert.enhancen;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
public class Node {
    Integer id;
    String name;
    String code;
    String parentCode;
    Integer order;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值