正常项目开发中很多地方都需要用到树形结构,如分类,用户,权限等。而在数据库中,通常是使用一个parent_id这样一个字段来记录当前数据行的父节点id。由于我们从数据库中查出来的数据是个list,所以我们需要使用代码手动将list转成tree的结构了。这里提供2种方法实现列表到树形结构的转换。
举一个用户的例子,用户实体User结构如下:
@Data
@ToString
public class User {
/**
* 用户id
*/
private Long id;
/**
* 用户名
*/
private String name;
/**
* 父id,即上级id
*/
private Long parentId;
/**
* 子节点列表,即直系下级列表
*/
private List<User> children;
/**
* 构造函数
* @param id
* @param name
* @param parentId
*/
public User(Long id, String name, Long parentId) {
this.id = id;
this.name = name;
this.parentId = parentId;
}
}
接下来我们需要造一些模拟数据,这里展示下用户间的层级结构,造数据的代码就不展示了:
我们这里对树的根节点判断是通过parentId是否为null或者0来判断,且允许有多个根节点,即多棵树。
方法一:使用for循环嵌套遍历list数据
public List<User> listToTree1() {
List<User> list = list();
List<User> tree = new ArrayList<>();
for (User user : list) {
//找到根节点
if (user.getParentId() == null || user.getParentId().equals(0L)) {
tree.add(user);
}
List<User> children = new ArrayList<>();
//再次遍历list,找到user的子节点
for (User node : list) {
if (node.getParentId().equals(user.getId())) {
children.add(node);
}
}
user.setChildren(children);
}
return tree;
}
原理:通过for循环嵌套遍历所有数据,第一层循环将根节点的数据加到树列表中,第二层循环通过parentId建立节点的父子关系。
方法二:使用递归
public List<User> listToTree2() {
List<User> list = list();
List<User> tree = new ArrayList<>();
for (User user : list) {
//找到根节点
if (user.getParentId() == null || user.getParentId().equals(0L)) {
tree.add(findChildren(user, list));
}
}
return tree;
}
/**
* 查找user的子节点
* @param user
* @param list
* @return
*/
private User findChildren(User user, List<User> list) {
List<User> children = new ArrayList<>();
for (User node : list) {
if (node.getParentId().equals(user.getId())) {
//递归调用
children.add(findChildren(node, list));
}
}
user.setChildren(children);
return user;
}
原理:递归使用了2个函数,第一个listToTree2函数作用仅仅只是为了找到根节点,递归的函数是findChildren,这个函数会从list中查找属于user的子节点列表并设置到user对象中。
使用web请求来获取转换之后的树形结果:
[
{
"id": 1,
"name": "董事长",
"parentId": 0,
"children": [
{
"id": 2,
"name": "赵经理",
"parentId": 1,
"children": [
{
"id": 4,
"name": "孙组长",
"parentId": 2,
"children": [
{
"id": 7,
"name": "小吴",
"parentId": 4,
"children": []
}
]
},
{
"id": 5,
"name": "李组长",
"parentId": 2,
"children": [
{
"id": 8,
"name": "小郑",
"parentId": 5,
"children": []
}
]
}
]
},
{
"id": 3,
"name": "钱经理",
"parentId": 1,
"children": [
{
"id": 6,
"name": "周组长",
"parentId": 3,
"children": []
}
]
}
]
}
]
完整代码参考:https://gitee.com/lqccan/blog-demo/tree/master/%E5%90%8E%E7%AB%AF/list-to-tree
测试接口:
http://localhost:8080/list
http://localhost:8080/tree1
http://localhost:8080/tree2