1、常规表结构设计
tree_meta_data
字段名 | 描述 | 备注 |
id | 主键Id |
|
name | 名称 |
|
parent_id | 父Id |
|
path | 路径等 |
|
id_path | id路径 | 可以通过id_path快速查找 |
2、构建树结构
2.1 思想
- 从数据库表tree_meta_data获取元数据;
- 根据parentId=0,遍历找到所有父节点;
- 遍历找到的父节点,递归找到每个父节点的所有子节点;
2.2 对象类
(1)元数据
/**
* 树元数据(表中数据)
*
* @author xingnana
* @create 12/14/20
*/
@Data
@AllArgsConstructor
public class TreeMetaData {
private Long id;
private String name;
private Long parentId;
private String path;
private String idPath;
}
(2)定义node对象
/**
* 树节点
*
* @author xingnana
* @create 12/14/20
*/
@Data
@NoArgsConstructor
public class TreeNode {
private Long id;
private String name;
private List<TreeNode> children = new ArrayList<>(); //子模块列表
/**
* 是否勾选
*/
private Boolean isCheck;
/**
* 模块路径
*/
private String path;
public TreeNode(Long id, String name) {
this.id = id;
this.name = name;
this.isCheck = false;
}
}
2.3 构建完整树主要逻辑
/**
* 构建树
*/
private List<TreeNode> buildTree(List<TreeMetaData> dataList) {
List<TreeNode> treeNodeList = new ArrayList<>();
if (!CollectionUtils.isEmpty(dataList)) {
Iterator<TreeMetaData> iterator = dataList.iterator();
/** 找到所有父节点*/
while (iterator.hasNext()) {
TreeMetaData eachDO = iterator.next();
if (eachDO.getParentId() == 0) { //找到父节点
TreeNode parentNode = new TreeNode(eachDO.getId(), eachDO.getName());
parentNode.setPath(eachDO.getPath());
treeNodeList.add(parentNode);
iterator.remove();
}
}
//找所有父节点的子节点
if (!treeNodeList.isEmpty()) {
for (TreeNode parent : treeNodeList) {
findChildren(parent, dataList);
}
}
}
return treeNodeList;
}
/**
* 找到父节点的所有子节点
*
* @param parent
* @param doList
*/
private void findChildren(TreeNode parent, List<TreeMetaData> doList) {
Iterator<TreeMetaData> iterator = doList.iterator();
while (iterator.hasNext()) {
TreeMetaData eachDO = iterator.next();
if (Objects.equals(parent.getId(), eachDO.getParentId())) {
TreeNode nodeVO = new TreeNode(eachDO.getId(), eachDO.getName());
nodeVO.setPath(eachDO.getPath());
parent.getChildren().add(nodeVO);
iterator.remove();
}
}
for (TreeNode child : parent.getChildren()) {
findChildren(child, doList);
}
}
2.4 根据选中节点,构建选中节点树
/**
* 根据选中的树结点构造树
*/
private List<TreeNode> buildCheckedTree(List<TreeMetaData> dataList, List<Long> checkedIds) {
List<TreeNode> treeNodeList = new ArrayList<>();
if (dataList != null) {
Iterator<TreeMetaData> iterator = dataList.iterator();
/** 找到所有父节点*/
while (iterator.hasNext()) {
TreeMetaData eachDO = iterator.next();
/** 父节点parentId=0*/
if (eachDO.getParentId() == 0) {
TreeNode parentNode = new TreeNode(eachDO.getId(), eachDO.getName());
parentNode.setIsCheck(false);
parentNode.setPath(eachDO.getPath());
treeNodeList.add(parentNode);
iterator.remove();
}
}
/** 找到父节点的所有子节点*/
if (!treeNodeList.isEmpty()) {
for (TreeNode parent : treeNodeList) {
findCheckedChildren(parent, dataList, checkedIds);
}
}
/** 找到父节点的所有子节点*/
if (!treeNodeList.isEmpty()) {
for (TreeNode parent : treeNodeList) {
findCheckedChildren(parent, dataList, checkedIds);
}
}
}
return treeNodeList;
}
/**
* 根据选中的树结点查找子节点
*
* @param parent 父节点
* @param dataList
* @param checkedIds 选中节点的id
*/
private void findCheckedChildren(TreeNode parent, List<TreeMetaData> dataList, List<Long> checkedIds) {
Iterator<TreeMetaData> iterator = dataList.iterator();
while (iterator.hasNext()) {
TreeMetaData eachDO = iterator.next();
/** 循环 找子节点*/
if (Objects.equals(parent.getId(), eachDO.getParentId())) {
TreeNode nodeVO = new TreeNode(eachDO.getId(), eachDO.getName());
nodeVO.setIsCheck(checkedIds.contains(nodeVO.getId()) ? true : false);
nodeVO.setPath(eachDO.getPath());
parent.getChildren().add(nodeVO);
iterator.remove();
}
}
boolean isAllCheck = true;
/** 找到父节点的所有子节点 且 若子节点全部选中,则选中父节点 */
for (TreeNode child : parent.getChildren()) {
findCheckedChildren(child, dataList, checkedIds);
if (!child.getIsCheck()) {
isAllCheck = false;
}
}
if (!CollectionUtils.isEmpty(parent.getChildren())) {
parent.setIsCheck(isAllCheck);
} else if (checkedIds.contains(parent.getId())) {
parent.setIsCheck(true);
}
}