1. 程式人生 > >根據id,parentid將資料封裝成樹,利用jdk1.8的BigConsumer

根據id,parentid將資料封裝成樹,利用jdk1.8的BigConsumer

import java.math.BigDecimal;
import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public abstract class MyBaseTree implements BO,PO,Comparable<MyBaseTree> {

    //根ID預設是0
    //public static String DEFAULT_ROOT_ID = "0";
    public static String SPLIT = "-";

    public interface Property {
        String value       = "value";
        String parentId = "parentId";
        String path     = "path";
        String level    = "level";
        String enable   = "enable";
    }

    //主鍵
    private String  value;
    //父級類別
    private String  parentId;
    //樹結構編碼,用於快速查詢, 每一層由4位字元組成,用-分割
    //如第一層:0001 第二層:0001-0001 第三層:0001-0001-0001
    private String  path;
    //排序索引
    private Long    sortIndex;
    //層級
    private Integer level;
    //是否啟用
    private Byte    enable;


    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public String getParentId() {
        return parentId;
    }

    public void setParentId(String parentId) {
        this.parentId = parentId;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public Integer getLevel() {
        return level;
    }

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

    public Long getSortIndex() {
        return sortIndex;
    }

    public void setSortIndex(Long sortIndex) {
        this.sortIndex = sortIndex;
    }

    public Byte getEnable() {
        return enable;
    }

    public void setEnable(Byte enable) {
        this.enable = enable;
    }

    public abstract  <T extends MyBaseTree> List<T> getChildren() ;

    public abstract void setChildren(List<? extends MyBaseTree> children);



    public int compareTo(MyBaseTree support) {
        if (support == null) return -1;

        return Long.compare(getSortIndex() == null ? 0 : getSortIndex(), support.getSortIndex() == null ? 0 : support.getSortIndex());
    }

itw_xuyt02 20:57:45
    /**
     * 根據path獲取父節點的path
     *
     * @param path path
     * @return 父節點path
     */
    public static String getParentPath(String path) {
        if (path == null || path.length() < 4) return null;
        return path.substring(0, path.length() - 5);
    }



    /**
     * 將樹形結構轉為列表結構,並填充對應的資料。<br>
     * 如樹結構資料: {name:'父節點',children:[{name:'子節點1'},{name:'子節點2'}]}<br>
     * 解析後:[{id:'id1',name:'父節點',path:'<b>aoSt</b>'},{id:'id2',name:'子節點1',path:'<b>aoSt</b>-oS5a'},{id:'id3',name:'子節點2',path:'<b>aoSt</b>-uGpM'}]
     *
     * @param parent      樹結構的根節點
     * @param target      目標集合,轉換後的資料將直接新增({@link List#add(Object)})到這個集合.
     * @param <T>         繼承{@link MyBaseTree}的型別
     */
    public static <T extends MyBaseTree> void expandTree2List(T parent, List<T> target) {
        //包含自身
        target.add(parent);

        //設定主鍵
        String pid = parent.getValue();
        if (pid == null) {
            pid = BasePO.createUID();
            parent.setValue(pid);
        }

        //設定path
        if (parent.getPath() == null) {
            parent.setPath(parent.getValue());
        }
        //設定level
        if (parent.getPath() != null && parent.getLevel() == null) {
            parent.setLevel(parent.getPath().split(SPLIT).length);
        }

        //設定sortIndex
        Long parentIndex = parent.getSortIndex();
        if (null == parentIndex) {
            parent.setSortIndex(IdHelper.genLongWorkerId());
        }

        //處理子孫
        List<T> children = parent.getChildren();
        if (children != null) {
            for (int i = 0; i < children.size(); i++) {
                T child = children.get(i);
                if(StringHelper.isEmpty(child.getValue())){
                    child.setValue(BasePO.createUID());
                }
                //
                if (child instanceof MyBaseTree && parent instanceof MyBaseTree) {
                    ((MyBaseTree)child).setSortIndex(new BigDecimal(parentIndex + "0" + (i + 1)).longValue());
                }
                child.setParentId(pid);
                //路徑為父親path-父親ID
                child.setPath (parent.getPath() + SPLIT + child.getValue());
                child.setLevel(child.getPath().split(SPLIT).length);
                expandTree2List(child, target);
            }
        }
    }
itw_xuyt02 20:59:48
    //遞迴的消費某棵樹
    public static <T extends MyBaseTree> void forEach(Collection<T> list, Consumer<T> consumer ) {
        list.forEach(node -> {
            consumer.accept(node);
            if (node.getChildren() != null) {
                forEach( node.getChildren(), consumer );
            }
        });
    }


    /**
     * 集合轉為樹形結構,返回根節點集合
     *
     * @param dataList      需要轉換的集合
     * @param childConsumer 設定子節點回調
     * @param <N>           樹節點型別
     * @return 樹形結構集合
     */
    public static <N extends MyBaseTree> List<N> list2tree(final Collection<N> dataList,
                                                           final BiConsumer<N, List<N>> childConsumer) {
        return list2tree(dataList, childConsumer, (Function<TreeHelper<N>, Predicate<N>>) predicate -> node -> node == null || predicate.getNode(node.getParentId()) == null);
    }

    public static <N extends MyBaseTree> List<N> list2tree(final Collection<N> dataList,
                                                           final BiConsumer<N, List<N>> childConsumer,
                                                           final Predicate<N> rootNodePredicate) {
        return list2tree(dataList, childConsumer, (Function<TreeHelper<N>, Predicate<N>>) predicate -> rootNodePredicate);
    }

    /**
     * 列表結構轉為樹結構,並返回根節點集合
     *
     * @param dataList          資料集合
     * @param childConsumer     子節點消費介面,用於設定子節點
     * @param predicateFunction 根節點判斷函式,傳入helper,獲取一個判斷是否為跟節點的函式
     * @param <N>               元素型別
     * @return 根節點集合
     */
    public static <N extends MyBaseTree> List<N> list2tree(final Collection<N> dataList,
                                                           final BiConsumer<N, List<N>> childConsumer,
                                                           final Function<TreeHelper<N>, Predicate<N>> predicateFunction) {
        if(dataList == null || dataList.isEmpty()){
            return new ArrayList();
        }
        //Objects.requireNonNull(dataList, "source list can not be null");
        Objects.requireNonNull(childConsumer, "child consumer can not be null");
        Objects.requireNonNull(predicateFunction, "root predicate function can not be null");

        Supplier<Stream<N>> streamSupplier = () -> dataList.size() < 1000 ? dataList.stream() : dataList.parallelStream();
        // id,node
        Map<String,N> cache = new HashMap<>();
        // parentId,children
        Map<String,List<N>> treeCache = streamSupplier.get()
                .peek(node -> cache.put(node.getValue(), node))
                .collect(Collectors.groupingBy(MyBaseTree::getParentId));

        Predicate<N> rootNodePredicate = predicateFunction.apply(new TreeHelper<N>() {
            @Override
            public List<N> getChildren(String parentId) {
                return treeCache.get(parentId);
            }

            @Override
            public N getNode(String id) {
                return cache.get(id);
            }
        });
        Stream<N> qwe = streamSupplier.get();
        qwe.forEach(
                node -> node.getValue()//1112
        );

        List<N> qwzxce = treeCache.get("1112");
        return streamSupplier.get()
                //設定每個節點的子節點
                .peek(node -> childConsumer.accept(node, null !=treeCache.get(node.getValue())?treeCache.get(node.getValue()):null  ))
                //獲取根節點
                .filter(rootNodePredicate)
                .collect(Collectors.toList());
    }
itw_xuyt02 21:00:18
    /**
     * 樹結構Helper
     *
     * @param <T>  節點型別
     */
    interface TreeHelper<T> {
        /**
         * 根據主鍵獲取子節點
         *
         * @param parentId 節點ID
         * @return 子節點集合
         */
        List<T> getChildren(String parentId);

        /**
         * 根據id獲取節點
         *
         * @param id 節點ID
         * @return 節點
         */
        T getNode(String id);
    }
}

呼叫時:

List<OrgTreeVO> orgTreeVOS = MyBaseTree.list2tree(orgTreeVOList, OrgTreeVO::setChildren, (Predicate<OrgTreeVO>) menuEntity ->
        // parentId為空或者為-1的選單則認為是根選單
        menuEntity.getParentId() == null || "".equals(menuEntity.getParentId()));

其中返回的VO類必須繼承MyBaseTree.java檔案:

public class OrgTreeVO extends MyBaseTree