|
@@ -20,14 +20,13 @@ package org.hswebframework.web.commons.entity;
|
|
|
|
|
|
|
|
|
import org.hswebframework.web.id.IDGenerator;
|
|
|
-import org.hswebframwork.utils.RandomUtil;
|
|
|
-import org.hswebframwork.utils.StringUtils;
|
|
|
+import org.hswebframework.utils.RandomUtil;
|
|
|
|
|
|
+import java.math.BigDecimal;
|
|
|
import java.util.*;
|
|
|
-import java.util.function.BiConsumer;
|
|
|
-import java.util.function.Function;
|
|
|
-import java.util.function.Predicate;
|
|
|
+import java.util.function.*;
|
|
|
import java.util.stream.Collectors;
|
|
|
+import java.util.stream.Stream;
|
|
|
|
|
|
public interface TreeSupportEntity<PK> extends GenericEntity<PK> {
|
|
|
|
|
@@ -49,11 +48,6 @@ public interface TreeSupportEntity<PK> extends GenericEntity<PK> {
|
|
|
|
|
|
void setLevel(Integer level);
|
|
|
|
|
|
- default void setLevelFromPath() {
|
|
|
- if (getPath() != null)
|
|
|
- setLevel(getPath().split("-").length);
|
|
|
- }
|
|
|
-
|
|
|
<T extends TreeSupportEntity<PK>> List<T> getChildren();
|
|
|
|
|
|
/**
|
|
@@ -67,6 +61,15 @@ public interface TreeSupportEntity<PK> extends GenericEntity<PK> {
|
|
|
return path.substring(0, path.length() - 5);
|
|
|
}
|
|
|
|
|
|
+ static <T extends TreeSupportEntity> void forEach(Collection<T> list, Consumer<T> consumer) {
|
|
|
+ list.forEach(node -> {
|
|
|
+ consumer.accept(node);
|
|
|
+ if (node.getChildren() != null) {
|
|
|
+ forEach(node.getChildren(), consumer);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 将树形结构转为列表结构,并填充对应的数据。<br>
|
|
|
* 如树结构数据: {name:'父节点',children:[{name:'子节点1'},{name:'子节点2'}]}<br>
|
|
@@ -82,7 +85,14 @@ public interface TreeSupportEntity<PK> extends GenericEntity<PK> {
|
|
|
List<T> children = parent.getChildren();
|
|
|
if (parent.getPath() == null) {
|
|
|
parent.setPath(RandomUtil.randomChar(4));
|
|
|
- parent.setLevelFromPath();
|
|
|
+ if (parent.getPath() != null)
|
|
|
+ parent.setLevel(parent.getPath().split("-").length);
|
|
|
+ if (parent instanceof SortSupportEntity) {
|
|
|
+ Long index = ((SortSupportEntity) parent).getSortIndex();
|
|
|
+ if (null == index) {
|
|
|
+ ((SortSupportEntity) parent).setSortIndex(1L);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
if (children != null) {
|
|
|
PK pid = parent.getId();
|
|
@@ -93,11 +103,15 @@ public interface TreeSupportEntity<PK> extends GenericEntity<PK> {
|
|
|
for (int i = 0; i < children.size(); i++) {
|
|
|
T child = children.get(i);
|
|
|
if (child instanceof SortSupportEntity && parent instanceof SortSupportEntity) {
|
|
|
- ((SortSupportEntity) child).setSortIndex(StringUtils.toLong(((SortSupportEntity) parent).getSortIndex() + "0" + (i + 1)));
|
|
|
+ Long index = ((SortSupportEntity) parent).getSortIndex();
|
|
|
+ if (null == index) {
|
|
|
+ ((SortSupportEntity) parent).setSortIndex(index = 1L);
|
|
|
+ }
|
|
|
+ ((SortSupportEntity) child).setSortIndex(new BigDecimal(index + "0" + (i + 1)).longValue());
|
|
|
}
|
|
|
child.setParentId(pid);
|
|
|
child.setPath(parent.getPath() + "-" + RandomUtil.randomChar(4));
|
|
|
- child.setLevelFromPath();
|
|
|
+ child.setLevel(child.getPath().split("-").length);
|
|
|
target.add(child);
|
|
|
expandTree2List(child, target, idGenerator);
|
|
|
}
|
|
@@ -108,54 +122,87 @@ public interface TreeSupportEntity<PK> extends GenericEntity<PK> {
|
|
|
* 集合转为树形结构,返回根节点集合
|
|
|
*
|
|
|
* @param dataList 需要转换的集合
|
|
|
- * @param childAccepter 设置子节点回调
|
|
|
- * @param <T> 树节点类型
|
|
|
+ * @param childConsumer 设置子节点回调
|
|
|
+ * @param <N> 树节点类型
|
|
|
* @param <PK> 主键类型
|
|
|
* @return 树形结构集合
|
|
|
*/
|
|
|
- static <T extends TreeSupportEntity<PK>, PK> List<T> list2tree(Collection<T> dataList, BiConsumer<T, List<T>> childAccepter) {
|
|
|
- return list2tree(dataList, childAccepter, (Function<RootNodePredicate<T, PK>, Predicate<T>>) predicate -> node -> node == null || predicate.getNode(node.getParentId()) == null);
|
|
|
+ static <N extends TreeSupportEntity<PK>, PK> List<N> list2tree(Collection<N> dataList, BiConsumer<N, List<N>> childConsumer) {
|
|
|
+ return list2tree(dataList, childConsumer, (Function<TreeHelper<N, PK>, Predicate<N>>) predicate -> node -> node == null || predicate.getNode(node.getParentId()) == null);
|
|
|
}
|
|
|
|
|
|
- static <T extends TreeSupportEntity<PK>, PK> List<T> list2tree(Collection<T> dataList,
|
|
|
- BiConsumer<T, List<T>> childAccepter,
|
|
|
- Predicate<T> rootNodePredicate) {
|
|
|
- return list2tree(dataList, childAccepter, (Function<RootNodePredicate<T, PK>, Predicate<T>>) predicate -> rootNodePredicate);
|
|
|
+ static <N extends TreeSupportEntity<PK>, PK> List<N> list2tree(Collection<N> dataList,
|
|
|
+ BiConsumer<N, List<N>> childConsumer,
|
|
|
+ Predicate<N> rootNodePredicate) {
|
|
|
+ return list2tree(dataList, childConsumer, (Function<TreeHelper<N, PK>, Predicate<N>>) predicate -> rootNodePredicate);
|
|
|
}
|
|
|
|
|
|
- static <T extends TreeSupportEntity<PK>, PK> List<T> list2tree(Collection<T> dataList,
|
|
|
- BiConsumer<T, List<T>> childAccepter,
|
|
|
- Function<RootNodePredicate<T, PK>, Predicate<T>> predicateFunction) {
|
|
|
- // id,obj
|
|
|
- Map<PK, T> cache = new HashMap<>();
|
|
|
+ /**
|
|
|
+ * 列表结构转为树结构,并返回根节点集合
|
|
|
+ *
|
|
|
+ * @param dataList 数据集合
|
|
|
+ * @param childConsumer 子节点消费接口,用于设置子节点
|
|
|
+ * @param predicateFunction 根节点判断函数,传入helper,获取一个判断是否为跟节点的函数
|
|
|
+ * @param <N> 元素类型
|
|
|
+ * @param <PK> 主键类型
|
|
|
+ * @return 根节点集合
|
|
|
+ */
|
|
|
+ static <N extends TreeSupportEntity<PK>, PK> List<N> list2tree(final Collection<N> dataList,
|
|
|
+ final BiConsumer<N, List<N>> childConsumer,
|
|
|
+ final Function<TreeHelper<N, PK>, Predicate<N>> predicateFunction) {
|
|
|
+ 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<PK, N> cache = new HashMap<>();
|
|
|
// parentId,children
|
|
|
- Map<PK, List<T>> treeCache = dataList.parallelStream()
|
|
|
+ Map<PK, List<N>> treeCache = streamSupplier.get()
|
|
|
.peek(node -> cache.put(node.getId(), node))
|
|
|
.collect(Collectors.groupingBy(TreeSupportEntity::getParentId));
|
|
|
|
|
|
- Predicate<T> rootNodePredicate = predicateFunction.apply(new RootNodePredicate<T, PK>() {
|
|
|
+ Predicate<N> rootNodePredicate = predicateFunction.apply(new TreeHelper<N, PK>() {
|
|
|
@Override
|
|
|
- public List<T> getChildren(PK parentId) {
|
|
|
+ public List<N> getChildren(PK parentId) {
|
|
|
return treeCache.get(parentId);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public T getNode(PK id) {
|
|
|
+ public N getNode(PK id) {
|
|
|
return cache.get(id);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
- return dataList.parallelStream()
|
|
|
+ return streamSupplier.get()
|
|
|
//设置每个节点的子节点
|
|
|
- .peek(node -> childAccepter.accept(node, treeCache.get(node.getId())))
|
|
|
+ .peek(node -> childConsumer.accept(node, treeCache.get(node.getId())))
|
|
|
//获取根节点
|
|
|
.filter(rootNodePredicate)
|
|
|
.collect(Collectors.toList());
|
|
|
}
|
|
|
|
|
|
- interface RootNodePredicate<T, PK> {
|
|
|
+ /**
|
|
|
+ * 树结构Helper
|
|
|
+ *
|
|
|
+ * @param <T> 节点类型
|
|
|
+ * @param <PK> 主键类型
|
|
|
+ */
|
|
|
+ interface TreeHelper<T, PK> {
|
|
|
+ /**
|
|
|
+ * 根据主键获取子节点
|
|
|
+ *
|
|
|
+ * @param parentId 节点ID
|
|
|
+ * @return 子节点集合
|
|
|
+ */
|
|
|
List<T> getChildren(PK parentId);
|
|
|
|
|
|
+ /**
|
|
|
+ * 根据id获取节点
|
|
|
+ *
|
|
|
+ * @param id 节点ID
|
|
|
+ * @return 节点
|
|
|
+ */
|
|
|
T getNode(PK id);
|
|
|
}
|
|
|
}
|