Looly 5 years ago
parent
commit
d330c489b3

+ 1 - 1
CHANGELOG.md

@@ -13,7 +13,7 @@
 * 【core   】     XmlUtil增加xmlToBean和beanToXml方法
 * 【core   】     XmlUtil增加xmlToBean和beanToXml方法
 * 【db     】     设置全局忽略大小写DbUtil.setCaseInsensitiveGlobal(true)(issue#784@Github)
 * 【db     】     设置全局忽略大小写DbUtil.setCaseInsensitiveGlobal(true)(issue#784@Github)
 * 【core   】     增加CallerUtil.getCallerMethodName方法
 * 【core   】     增加CallerUtil.getCallerMethodName方法
-* 【core   】     Tree增加getParent方法,可以获取父节点
+* 【core   】     Tree增加getParent方法,可以获取父节点,抽象Node接口
 
 
 ### Bug修复
 ### Bug修复
 * 【core   】     修复TypeUtil无法获取泛型接口的泛型参数问题(issue#I1BRFI@Gitee)
 * 【core   】     修复TypeUtil无法获取泛型接口的泛型参数问题(issue#I1BRFI@Gitee)

+ 79 - 0
hutool-core/src/main/java/cn/hutool/core/lang/tree/Node.java

@@ -0,0 +1,79 @@
+package cn.hutool.core.lang.tree;
+
+/**
+ * 节点接口,提供节点相关的的方法定义
+ *
+ * @param <T> ID类型
+ * @author looly
+ * @since 5.2.4
+ */
+public interface Node<T> extends Comparable<Node<T>>{
+	/**
+	 * 获取ID
+	 *
+	 * @return ID
+	 */
+	T getId();
+
+	/**
+	 * 设置ID
+	 *
+	 * @param id ID
+	 */
+	Node<T> setId(T id);
+
+	/**
+	 * 获取父节点ID
+	 *
+	 * @return 父节点ID
+	 */
+	T getParentId();
+
+	/**
+	 * 设置父节点ID
+	 *
+	 * @param parentId 父节点ID
+	 * @return 父节点ID
+	 */
+	Node<T> setParentId(T parentId);
+
+	/**
+	 * 获取节点标签名称
+	 *
+	 * @return 节点标签名称
+	 */
+	CharSequence getName();
+
+	/**
+	 * 设置节点标签名称
+	 *
+	 * @param name 节点标签名称
+	 * @return this
+	 */
+	Node<T> setName(CharSequence name);
+
+	/**
+	 * 获取权重
+	 *
+	 * @return 权重
+	 */
+	Comparable<?> getWeight();
+
+	/**
+	 * 设置权重
+	 *
+	 * @param weight 权重
+	 * @return this
+	 */
+	Node<T> setWeight(Comparable<?> weight);
+
+	@SuppressWarnings({"unchecked", "rawtypes", "NullableProblems"})
+	default int compareTo(Node node) {
+		final Comparable weight = this.getWeight();
+		if (null != weight) {
+			final Comparable weightOther = node.getWeight();
+			return weight.compareTo(weightOther);
+		}
+		return 0;
+	}
+}

+ 26 - 54
hutool-core/src/main/java/cn/hutool/core/lang/tree/Tree.java

@@ -3,7 +3,6 @@ package cn.hutool.core.lang.tree;
 import cn.hutool.core.lang.Assert;
 import cn.hutool.core.lang.Assert;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.ObjectUtil;
 
 
-import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.List;
 
 
@@ -14,7 +13,7 @@ import java.util.List;
  * @author liangbaikai
  * @author liangbaikai
  * @since 5.2.1
  * @since 5.2.1
  */
  */
-public class Tree<T> extends LinkedHashMap<String, Object> implements Comparable<Tree<T>> {
+public class Tree<T> extends LinkedHashMap<String, Object> implements Node<T> {
 	private static final long serialVersionUID = 1L;
 	private static final long serialVersionUID = 1L;
 
 
 	private TreeNodeConfig treeNodeConfig;
 	private TreeNodeConfig treeNodeConfig;
@@ -54,21 +53,23 @@ public class Tree<T> extends LinkedHashMap<String, Object> implements Comparable
 	 * @since 5.2.4
 	 * @since 5.2.4
 	 */
 	 */
 	public Tree<T> getNode(T id) {
 	public Tree<T> getNode(T id) {
-		if (ObjectUtil.equal(id, getId())) {
-			return this;
-		}
-
-		// 查找子节点
-		Tree<T> node;
-		for (Tree<T> child : getChildren()) {
-			node = child.getNode(id);
-			if (null != node) {
-				return node;
-			}
-		}
+		return TreeUtil.getNode(this, id);
+	}
 
 
-		// 未找到节点
-		return null;
+	/**
+	 * 获取所有父节点名称列表
+	 *
+	 * <p>
+	 * 比如有个人在研发1部,他上面有研发部,接着上面有技术中心<br>
+	 * 返回结果就是:[研发一部, 研发中心, 技术中心]
+	 *
+	 * @param id 节点ID
+	 * @param includeCurrentNode 是否包含当前节点的名称
+	 * @return 所有父节点名称列表
+	 * @since 5.2.4
+	 */
+	public List<CharSequence> getParentsName(T id, boolean includeCurrentNode) {
+		return TreeUtil.getParentsName(getNode(id), includeCurrentNode);
 	}
 	}
 
 
 	/**
 	/**
@@ -83,17 +84,7 @@ public class Tree<T> extends LinkedHashMap<String, Object> implements Comparable
 	 * @since 5.2.4
 	 * @since 5.2.4
 	 */
 	 */
 	public List<CharSequence> getParentsName(boolean includeCurrentNode) {
 	public List<CharSequence> getParentsName(boolean includeCurrentNode) {
-		final List<CharSequence> result = new ArrayList<>();
-		if (includeCurrentNode) {
-			result.add(this.getName());
-		}
-
-		Tree<T> parent = getParent();
-		while (null != parent) {
-			result.add(parent.getName());
-			parent = parent.getParent();
-		}
-		return result;
+		return TreeUtil.getParentsName(this, includeCurrentNode);
 	}
 	}
 
 
 	/**
 	/**
@@ -110,55 +101,47 @@ public class Tree<T> extends LinkedHashMap<String, Object> implements Comparable
 		return this;
 		return this;
 	}
 	}
 
 
-	/**
-	 * 获取节点ID
-	 *
-	 * @return 节点ID
-	 */
+	@Override
 	@SuppressWarnings("unchecked")
 	@SuppressWarnings("unchecked")
 	public T getId() {
 	public T getId() {
 		return (T) this.get(treeNodeConfig.getIdKey());
 		return (T) this.get(treeNodeConfig.getIdKey());
 	}
 	}
 
 
-	/**
-	 * 设置节点ID
-	 *
-	 * @param id 节点ID
-	 * @return this
-	 */
+	@Override
 	public Tree<T> setId(T id) {
 	public Tree<T> setId(T id) {
 		this.put(treeNodeConfig.getIdKey(), id);
 		this.put(treeNodeConfig.getIdKey(), id);
 		return this;
 		return this;
 	}
 	}
 
 
-	/**
-	 * 获取父节点ID
-	 *
-	 * @return 父节点ID
-	 */
+	@Override
 	@SuppressWarnings("unchecked")
 	@SuppressWarnings("unchecked")
 	public T getParentId() {
 	public T getParentId() {
 		return (T) this.get(treeNodeConfig.getParentIdKey());
 		return (T) this.get(treeNodeConfig.getParentIdKey());
 	}
 	}
 
 
+	@Override
 	public Tree<T> setParentId(T parentId) {
 	public Tree<T> setParentId(T parentId) {
 		this.put(treeNodeConfig.getParentIdKey(), parentId);
 		this.put(treeNodeConfig.getParentIdKey(), parentId);
 		return this;
 		return this;
 	}
 	}
 
 
+	@Override
 	public CharSequence getName() {
 	public CharSequence getName() {
 		return (CharSequence) this.get(treeNodeConfig.getNameKey());
 		return (CharSequence) this.get(treeNodeConfig.getNameKey());
 	}
 	}
 
 
+	@Override
 	public Tree<T> setName(CharSequence name) {
 	public Tree<T> setName(CharSequence name) {
 		this.put(treeNodeConfig.getNameKey(), name);
 		this.put(treeNodeConfig.getNameKey(), name);
 		return this;
 		return this;
 	}
 	}
 
 
+	@Override
 	public Comparable<?> getWeight() {
 	public Comparable<?> getWeight() {
 		return (Comparable<?>) this.get(treeNodeConfig.getWeightKey());
 		return (Comparable<?>) this.get(treeNodeConfig.getWeightKey());
 	}
 	}
 
 
+	@Override
 	public Tree<T> setWeight(Comparable<?> weight) {
 	public Tree<T> setWeight(Comparable<?> weight) {
 		this.put(treeNodeConfig.getWeightKey(), weight);
 		this.put(treeNodeConfig.getWeightKey(), weight);
 		return this;
 		return this;
@@ -183,15 +166,4 @@ public class Tree<T> extends LinkedHashMap<String, Object> implements Comparable
 		Assert.notEmpty(key, "Key must be not empty !");
 		Assert.notEmpty(key, "Key must be not empty !");
 		this.put(key, value);
 		this.put(key, value);
 	}
 	}
-
-	@SuppressWarnings({"rawtypes", "unchecked", "NullableProblems"})
-	@Override
-	public int compareTo(Tree<T> tree) {
-		final Comparable weight = this.getWeight();
-		if (null != weight) {
-			final Comparable weightOther = tree.getWeight();
-			return weight.compareTo(weightOther);
-		}
-		return 0;
-	}
 }
 }

+ 12 - 56
hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeNode.java

@@ -6,9 +6,10 @@ package cn.hutool.core.lang.tree;
  * 在你的项目里它可以是部门实体、地区实体等任意类树节点实体
  * 在你的项目里它可以是部门实体、地区实体等任意类树节点实体
  * 类树节点实体: 包含key,父Key.不限于这些属性的可以构造成一颗树的实体对象
  * 类树节点实体: 包含key,父Key.不限于这些属性的可以构造成一颗树的实体对象
  *
  *
+ * @param <T> ID类型
  * @author liangbaikai
  * @author liangbaikai
  */
  */
-public class TreeNode<T> implements Comparable<Tree<T>> {
+public class TreeNode<T> implements Node<T> {
 
 
 	/**
 	/**
 	 * ID
 	 * ID
@@ -55,92 +56,47 @@ public class TreeNode<T> implements Comparable<Tree<T>> {
 
 
 	}
 	}
 
 
-	/**
-	 * 获取ID
-	 *
-	 * @return ID
-	 */
+	@Override
 	public T getId() {
 	public T getId() {
 		return id;
 		return id;
 	}
 	}
 
 
-	/**
-	 * 设置ID
-	 *
-	 * @param id ID
-	 */
-	public void setId(T id) {
+	@Override
+	public TreeNode<T> setId(T id) {
 		this.id = id;
 		this.id = id;
+		return this;
 	}
 	}
 
 
-	/**
-	 * 获取父节点ID
-	 *
-	 * @return 父节点ID
-	 */
+	@Override
 	public T getParentId() {
 	public T getParentId() {
 		return this.parentId;
 		return this.parentId;
 	}
 	}
 
 
-	/**
-	 * 设置父节点ID
-	 *
-	 * @param parentId 父节点ID
-	 * @return 父节点ID
-	 */
+	@Override
 	public TreeNode<T> setParentId(T parentId) {
 	public TreeNode<T> setParentId(T parentId) {
 		this.parentId = parentId;
 		this.parentId = parentId;
 		return this;
 		return this;
 	}
 	}
 
 
-	/**
-	 * 获取节点标签名称
-	 *
-	 * @return 节点标签名称
-	 */
+	@Override
 	public CharSequence getName() {
 	public CharSequence getName() {
 		return name;
 		return name;
 	}
 	}
 
 
-	/**
-	 * 设置节点标签名称
-	 *
-	 * @param name 节点标签名称
-	 * @return this
-	 */
+	@Override
 	public TreeNode<T> setName(CharSequence name) {
 	public TreeNode<T> setName(CharSequence name) {
 		this.name = name;
 		this.name = name;
 		return this;
 		return this;
 	}
 	}
 
 
-	/**
-	 * 获取权重
-	 *
-	 * @return 权重
-	 */
+	@Override
 	public Comparable<?> getWeight() {
 	public Comparable<?> getWeight() {
 		return weight;
 		return weight;
 	}
 	}
 
 
-	/**
-	 * 设置权重
-	 *
-	 * @param weight 权重
-	 * @return this
-	 */
+	@Override
 	public TreeNode<T> setWeight(Comparable<?> weight) {
 	public TreeNode<T> setWeight(Comparable<?> weight) {
 		this.weight = weight;
 		this.weight = weight;
 		return this;
 		return this;
 	}
 	}
-
-	@SuppressWarnings({"unchecked", "rawtypes", "NullableProblems"})
-	@Override
-	public int compareTo(Tree tree) {
-		final Comparable weight = this.getWeight();
-		if (null != weight) {
-			final Comparable weightOther = tree.getWeight();
-			return weight.compareTo(weightOther);
-		}
-		return 0;
-	}
 }
 }

+ 59 - 0
hutool-core/src/main/java/cn/hutool/core/lang/tree/TreeUtil.java

@@ -3,7 +3,9 @@ package cn.hutool.core.lang.tree;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.lang.tree.parser.DefaultNodeParser;
 import cn.hutool.core.lang.tree.parser.DefaultNodeParser;
 import cn.hutool.core.lang.tree.parser.NodeParser;
 import cn.hutool.core.lang.tree.parser.NodeParser;
+import cn.hutool.core.util.ObjectUtil;
 
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
@@ -117,4 +119,61 @@ public class TreeUtil {
 		}
 		}
 	}
 	}
 
 
+	/**
+	 * 获取ID对应的节点,如果有多个ID相同的节点,只返回第一个。<br>
+	 * 此方法只查找此节点及子节点,采用广度优先遍历。
+	 *
+	 * @param id ID
+	 * @return 节点
+	 * @since 5.2.4
+	 */
+	public static <T> Tree<T> getNode(Tree<T> node, T id) {
+		if (ObjectUtil.equal(id, node.getId())) {
+			return node;
+		}
+
+		// 查找子节点
+		Tree<T> childNode;
+		for (Tree<T> child : node.getChildren()) {
+			childNode = child.getNode(id);
+			if (null != childNode) {
+				return childNode;
+			}
+		}
+
+		// 未找到节点
+		return null;
+	}
+
+	/**
+	 * 获取所有父节点名称列表
+	 *
+	 * <p>
+	 * 比如有个人在研发1部,他上面有研发部,接着上面有技术中心<br>
+	 * 返回结果就是:[研发一部, 研发中心, 技术中心]
+	 *
+	 * @param <T> 节点ID类型
+	 * @param node 节点
+	 * @param includeCurrentNode 是否包含当前节点的名称
+	 * @return 所有父节点名称列表,node为null返回空List
+	 * @since 5.2.4
+	 */
+	public static <T> List<CharSequence> getParentsName(Tree<T> node, boolean includeCurrentNode) {
+		final List<CharSequence> result = new ArrayList<>();
+		if(null == node){
+			return result;
+		}
+
+		if (includeCurrentNode) {
+			result.add(node.getName());
+		}
+
+		Tree<T> parent = node.getParent();
+		while (null != parent) {
+			result.add(parent.getName());
+			parent = parent.getParent();
+		}
+		return result;
+	}
+
 }
 }