使用场景
在开发实现用户的职位、职务列表展示,后台管理页面用户的菜单目录展示。
一、效果展示
1. 数据库结构:
例如:电子产品/笔记本电脑/联想笔记本 生成一个三级目录
2. 数据处理返回:
{
"code": 200,
"msg": "操作成功",
"data": [
{
"id": "1",
"name": "电子产品",
"parentId": "0",
"type": 1,
"childList": [
{
"id": "5",
"name": "笔记本电脑",
"parentId": "1",
"type": 2,
"childList": [
{
"id": "21",
"name": "联想笔记本",
"parentId": "5",
"type": 3,
"childList": []
},
{
"id": "22",
"name": "外星人笔记本",
"parentId": "5",
"type": 3,
"childList": []
},
{
"id": "23",
"name": "戴尔笔记本",
"parentId": "5",
"type": 3,
"childList": []
}
]
},
{
"id": "6",
"name": "手机",
"parentId": "1",
"type": 2,
"childList": [
{
"id": "24",
"name": "苹果手机",
"parentId": "6",
"type": 3,
"childList": []
},
{
"id": "25",
"name": "菠萝手机",
"parentId": "6",
"type": 3,
"childList": []
}
]
},
{
"id": "7",
"name": "耳机",
"parentId": "1",
"type": 2,
"childList": []
},
{
"id": "8",
"name": "电子烟",
"parentId": "1",
"type": 2,
"childList": []
}
]
},
{
"id": "2",
"name": "生活用品",
"parentId": "0",
"type": 1,
"childList": [
{
"id": "10",
"name": "椅子",
"parentId": "2",
"type": 2,
"childList": []
},
{
"id": "11",
"name": "床",
"parentId": "2",
"type": 2,
"childList": []
},
{
"id": "19",
"name": "牙膏",
"parentId": "2",
"type": 2,
"childList": []
},
{
"id": "20",
"name": "牙刷",
"parentId": "2",
"type": 2,
"childList": []
},
{
"id": "9",
"name": "桌子",
"parentId": "2",
"type": 2,
"childList": []
}
]
},
{
"id": "3",
"name": "卫生用品",
"parentId": "0",
"type": 1,
"childList": [
{
"id": "12",
"name": "卫生纸",
"parentId": "3",
"type": 2,
"childList": []
},
{
"id": "13",
"name": "湿巾",
"parentId": "3",
"type": 2,
"childList": []
}
]
},
{
"id": "4",
"name": "学习用品",
"parentId": "0",
"type": 1,
"childList": [
{
"id": "14",
"name": "电子书",
"parentId": "4",
"type": 2,
"childList": []
},
{
"id": "15",
"name": "听力光盘",
"parentId": "4",
"type": 2,
"childList": []
},
{
"id": "16",
"name": "实体书",
"parentId": "4",
"type": 2,
"childList": []
},
{
"id": "17",
"name": "钢笔",
"parentId": "4",
"type": 2,
"childList": []
},
{
"id": "18",
"name": "笔记本子",
"parentId": "4",
"type": 2,
"childList": []
}
]
}
]
}
二、实现思路
- 获取所有的分类。
- 获取所有分类的id集合。使用stream()实现,stream使用教程
- 获取一级分类信息。同样使用stream()实现。
- 循环一级分类,在循环中将一级分类添加子分类,并且将一级分类加入返回的树结构中(备注:不加入返回的树结构中也行,直接返回步骤3的分类信息一样)。
- 重点是步骤4中将一级分类添加子分类,并且子分类在添加子子分类,子子分类再添加子子子分类··········等等,实现过程使用递归即可。
- 步骤5的实现过程:写一个递归方法,往当前节点添加子节点,首先获取当前节点的字节点集合,然后把这个集合放入到当前节点子节点属性中,接着再次调用当前递归的方法,把刚获取到的子节点当成新当前节点,获取新当前节点的新子节点,注意再次调用当前递归的方法,把刚获取到的子节点当成新当前节点之前首先判断新当前节点有没有子节点(判断方法:获取当前节点的字节点数组,根据数组的size()>0?判断是否有子节点),如果没有就不用递归。
- 总结:1-4是数据准备,5-6是实现递归(当前节点添加子节点的递归)。
三、代码展示
1. 主要思路代码
@GetMapping("/list")
public Result list() {
//所有的分类
List<Category> categoryList = categoryService.list();
//所有分类id集合
List<String> idList = categoryList.stream().map(Category::getId).collect(Collectors.toList());
//返回的树分类结果
List<Category> treeCategory = new ArrayList<>();
//一级分类目录
List<Category> categories = categoryList.stream().filter(category -> !idList.contains(category.getParentId())).collect(Collectors.toList());
//循环当前一级分类目录
for (Category category : categories) {
//给当前分类节点 添加 子分类节点
addChild(categoryList,category);
//当前分类添加完子节点分类之后,添加到返回的树结构中
treeCategory.add(category);
}
//把返回的树结构返回
return Result.success(categories);
}
/**
* 给当前分类节点 添加 子分类节点
* @param categoryList 所有的分类
* @param category 当前分类节点
*/
public void addChild( List<Category> categoryList,Category category){
//循环所有的分类,获取当前节点的所有子节点
List<Category> categoryListChild = categoryList.stream().filter(category1 -> category1.getParentId().equals(category.getId())).collect(Collectors.toList());
//把当前分类的子节点添加到当前分类
category.setChildList(categoryListChild);
//再次调用本方法,把当前节点的子节点当成当前节点,继续添加子节点,备注:这样会造成一直循环
categoryListChild.forEach(category1 -> {
//添加一步,判断当前节点是否有子节点,没有就不循环递归
if (haveChild(categoryList,category1)){
addChild(categoryList,category1);
}
});
}
/**
* 判断当前节点 是否存在 子节点
* @param categoryList 所有的分类
* @param category 当前节点
*/
public boolean haveChild( List<Category> categoryList,Category category){
//获取当前节点的子节点
List<Category> categoryListChild = categoryList.stream().filter(category1 -> category1.getParentId().equals(category.getId())).collect(Collectors.toList());
//子节点大于0则存在,否则不存在
return categoryListChild.size()>0?true:false;
}
2. 实体类代码展示
备注:实体类代码中一定要有一个子节点数组。实体类对用最上面的实体类图片
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class Category implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.ID_WORKER_STR)
private String id;
/**
* 类别名称
*/
private String name;
/**
* 上级id
*/
private String parentId;
/**
* 分类级别
*/
private Integer type;
/**
* 子节点数组
*/
@TableField(exist = false)
private List<Category> childList;
}