package com.estate.expert.admin.utils.tree;
|
|
import com.estate.expert.admin.enums.BizResultCode;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import lombok.Getter;
|
import lombok.Setter;
|
import lombok.extern.slf4j.Slf4j;
|
import org.apache.commons.lang3.StringUtils;
|
|
import javax.persistence.Transient;
|
import java.util.*;
|
|
/**
|
* 树根节点
|
*/
|
@Getter
|
@Setter
|
@Slf4j
|
public abstract class TreeRoot<T> {
|
|
// 保存所有的节点, 用于快速查找
|
@JsonIgnore
|
@Transient
|
private HashMap<String, TreeNode<T>> nodeMap = new HashMap<>();
|
|
@JsonIgnore
|
@Transient
|
private HashMap<String, TreeNode<T>> namePathMap = new HashMap<>();
|
|
/*
|
* 获取树的根节点
|
* 数据放到具体的实现类中
|
* 例如DepartmentStore
|
* 以便于可读性和字段控制
|
*/
|
public abstract TreeNode<T> root() ;
|
|
public TreeNode<T> getByNamePath(String namePath) {
|
return namePathMap.get(namePath);
|
}
|
|
public TreeNode<T> get(String path) {
|
return get(path, true);
|
}
|
|
public TreeNode<T> get(String path, boolean recursive) {
|
var node = nodeMap.get(path);
|
if (node == null) {
|
return null;
|
}
|
if (recursive) {
|
return node;
|
}
|
|
return node.ShadowNode();
|
}
|
|
public void edit(String path, String name, T data) {
|
var node = get(path);
|
BizResultCode.HIERARCHY_NODE_NOT_FOUND.check(node == null);
|
|
if(node.getParent()!= null) {
|
for (TreeNode<T> child : node.getParent().getChildren().values()) {
|
BizResultCode.HIERARCHY_NODE_NAME_ALREADY_EXISTS.check(child.getName().equals(name) && !child.getId().equals(node.getId()));
|
}
|
}
|
node.setName(name);
|
node.setData(data);
|
}
|
|
public void remove(String path) {
|
var node = get(path);
|
if (node == null) {
|
return;
|
}
|
nodeMap.remove(path);
|
namePathMap.remove(node.getNamePath());
|
|
var parent = node.getParent();
|
if (parent == null) {
|
return;
|
}
|
parent.getChildren().remove(node.getId());
|
}
|
|
public TreeNode<T> addChild(String parentPath, String name, T data) {
|
var parent = get(parentPath);
|
BizResultCode.HIERARCHY_PARENT_NOT_FOUND.check(parent == null);
|
var child = parent.addChild(name, data);
|
nodeMap.put(child.getPath(), child);
|
namePathMap.put(child.getNamePath(), child);
|
return child;
|
}
|
|
// copy节点
|
// public TreeNode<T> copy(String path) {
|
// var node = get(path);
|
// BizResultCode.HIERARCHY_NODE_NOT_FOUND.check(node == null);
|
// var parent = node.getParent();
|
// BizResultCode.HIERARCHY_PARENT_NOT_FOUND.check(parent == null);
|
//
|
//// TreeHelper.convertTree(node, )
|
// }
|
|
/*
|
* 设置树的父子关系
|
* 同时将所有的节点放入nodeMap中
|
* 便于快速查找
|
*/
|
public TreeRoot<T> buildTree() {
|
nodeMap.clear();
|
|
if(root() == null)
|
return this;
|
root().buildPath();
|
nodeMap.put(root().getPath(), root());
|
namePathMap.clear();
|
namePathMap.put(root().getNamePath(), root());
|
|
setParent(root());
|
return this;
|
}
|
|
// 设置所有的节点的父节点引用, 并将节点放入nodeMap中
|
private void setParent(TreeNode<T> node) {
|
for (TreeNode<T> child : node.getChildren().values()) {
|
child.setParent(node);
|
child.buildPath();
|
nodeMap.put(child.getPath(), child);
|
namePathMap.put(child.getNamePath(), child);
|
setParent(child);
|
}
|
}
|
|
public List<TreeNode<T>> children(String path){
|
return children(path, null);
|
}
|
|
public List<TreeNode<T>> children(String path, String keyword) {
|
var result = new ArrayList<TreeNode<T>>();
|
var node = get(path);
|
|
BizResultCode.HIERARCHY_NODE_NOT_FOUND.check(node == null);
|
// 不包含子节点
|
for (var child : node.getChildren().values()) {
|
if(StringUtils.isBlank(keyword) || child.getName().contains(keyword))
|
result.add(child.ShadowNode());
|
}
|
return result;
|
}
|
|
public List<String> findAllPaths(List<String> hierarchyPaths) {
|
var nodes = hierarchyPaths.stream()
|
.map(h -> get(h, true))
|
.filter(Objects::nonNull)
|
.toList();
|
|
// 归总并过滤掉相同的path
|
var pathMap = new TreeSet<String>();
|
nodes.forEach(n -> pathMap.addAll( n.allPaths()));
|
return new ArrayList<>(pathMap);
|
}
|
|
}
|