你能看到很多人都在介绍如何实现多级菜单的效果,但是都有一个共同的缺点,那就是没有解决代码会重复开发的问题。如果我需要实现多级评论呢,是否又需要自己再写一遍?
为了简化开发过程并提高代码的可维护性,我们可以创建一个统一的工具类来处理这些需求。在本文中,我将介绍如何使用SpringBoot创建一个返回多级菜单、多级评论、多级部门、多级分类的统一工具类。
基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
-
项目地址:https://github.com/YunaiV/ruoyi-vue-pro
-
视频教程:https://doc.iocoder.cn/video/
数据库设计
「主要是介绍是否需要tree_path字段。」
多级节点的数据库大家都知道,一般会有id,parentId字段,但是对于
tree_path
字段,这个需要根据设计者来定。
优点:
-
如果你对数据的读取操作比较频繁,而且需要快速查询某个节点的所有子节点或父节点,那么使用
tree_path
字段可以提高查询效率。
-
tree_path
字段可以使用路径字符串表示节点的层级关系,例如使用逗号分隔的节点ID列表。这样,可以通过模糊匹配
tree_path
字段来查询某个节点的所有子节点或父节点,而无需进行递归查询。
-
你可以使用模糊匹配的方式,找到所有以该节点的
tree_path
开头的子节点,并将它们删除。而无需进行递归删除。
缺点:
-
每次插入时,需要更新tree_path 字段,这可能会导致性能下降。
-
tree_path 字段的长度可能会随着树的深度增加而增加,可能会占用更多的存储空间。
因此,在设计数据库评论字段时,需要权衡使用treepath字段和父评论ID字段的优缺点,并根据具体的应用场景和需求做出选择。如果你更关注读取操作的效率和查询、删除的灵活性,可以考虑使用
tree_path
字段。如果你更关注写入操作的效率和数据一致性,并且树的深度不会很大,那么使用父评论ID字段来实现多级评论可能更简单和高效。
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
-
项目地址:https://github.com/YunaiV/yudao-cloud
-
视频教程:https://doc.iocoder.cn/video/
对于有 lombok 的小伙伴,实现这个方法很简单,只需要加上@Data即可
/**
* @Description: 固定属性结构属性
* @Author: yiFei
*/
public interface ITreeNode<T> {
/**
* @return 获取当前元素Id
*/
Object getId();
/**
* @return 获取父元素Id
*/
Object getParentId();
/**
* @return 获取当前元素的 children 属性
*/
List getChildren();
/**
* ( 如果数据库设计有tree_path字段可覆盖此方法来生成tree_path路径 )
*
* @return 获取树路径
*/
default Object getTreePath() { return ""; }
}
其中我们需要实现能将一个List元素构建成熟悉结构
我们需要实现生成
tree_path
字段
我们需要优雅的实现该方法
/**
* @Description: 树形结构工具类
* @Author: yiFei
*/
public class TreeNodeUtil {
private static final Logger log = LoggerFactory.getLogger(TreeNodeUtil.class);
public static final String PARENT_NAME = "parent";
public static final String CHILDREN_NAME = "children";
public static final List
这样我们就完成了
TreeNodeUtil
统一工具类,首先我们将元素分为父子两类,让其构建出一个小型树,然后我们将构建的子元素和下次遍历的父节点传入,递归的不断进行,这样就构建出了我们最终的想要实现的效果。
定义一个类实现 ITreeNode
/**
* @Description: 测试子元素工具类
* @Author: yiFei
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@AllArgsConstructor
public class TestChildren implements ITreeNode<TestChildren> {
private Long id;
private String name;
private String treePath;
private Long parentId;
public TestChildren(Long id, String name, String treePath, Long parentId) {
this.id = id;
this.name = name;
this.treePath = treePath;
this.parentId = parentId;
}
@TableField(exist = false)
private List children = new ArrayList<>();
}
测试基本功能
测试基本功能代码:
public static void main(String[] args) {
List testChildren = new ArrayList<>();
testChildren.add(new TestChildren(1L, "父元素", "", 0L));
testChildren.add(new TestChildren(2L, "子元素1", "1", 1L));
testChildren.add(new TestChildren(3L, "子元素2", "1", 1L));
testChildren.add(new TestChildren(4L, "子元素2的孙子元素", "1,3", 3L));
testChildren = TreeNodeUtil.buildTree(testChildren);
System.out.println(JSONUtil.toJsonStr(Result.success(testChildren)));
}
返回结果:
{
"code": "00000",
"msg": "操作成功",
"data": [{
"id": 1,
"name": "父元素",
"treePath": "",
"parentId": 0,
"children": [{
"id": 2,
"name": "子元素1",
"treePath": "1",
"parentId": 1,
"children": []
}, {
"id": 3,
"name": "子元素2",
"treePath": "1",
"parentId": 1,
"children": [{
"id": 4,
"name": "子元素2的孙子元素",
"treePath": "1,3",
"parentId": 3,
"children": []
}]
}]
}]
}
测试过滤以及重构数据
测试代码:
public static void main