根據id,parentid將資料封裝成樹,利用jdk1.8的BigConsumer
阿新 • • 發佈:2018-11-12
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