一、数据库父子结构数据设计
大部分采用 parentId的形式来存储父id,并且只存储父id,祖父Id不存储。也可以添加存储层级级别或者层级关系等字段。
CREATE TABLE `t_resource` (
`id` varchar(255) NOT NULL COMMENT '主键',
`parent_id` varchar(255) DEFAULT NULL COMMENT '父ID',
`name` varchar(255) DEFAULT NULL COMMENT '名称',
`url` varchar(255) DEFAULT NULL COMMENT '资源url',
`level` varchar(255) DEFAULT NULL COMMENT '层级级别',
`decode` varchar(255) DEFAULT NULL COMMENT '层级ID的关系,用”_“分割',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
二、将有父子关系的数据转换成树形结构数据
mapper层获取数据库数据和 controller层处理很简单,将有父子关系的数据转换成树形结构数据交给 service层处理。
@PostMapping("/getMuneTree")
@ResponseBody
public ResponseEntity<Map<String, Object>> getMuneTree(){
Map<String, Object> map = new HashMap<>();
map.put("menuList", resourceDOService.getMuneTree());
return ResponseEntity.ok(map);
}
1、方式一:递归:从树的最顶级获取子级,然后子级获取其子级。
返回时,需要哪些字段值就添加哪些字段值到 map中。结果图如上
/**
* 将有父子关系的数据转换成树形结构数据
*
* @return 最终的树状结构的集合数据
*/
@Override
public List<Map<String, Object>> getMuneTree() {
// 获取数据库中带有有父子关系的数据
List<ResourceDO> data = resourceDOMapper.selectAll();
//创建一个List集合来存放最终的树状结构数据
List<Map<String, Object>> menuList = new ArrayList<>();
// 先存入最顶级的树(0代表没有父级,即最顶级),然后通过最顶级的id递归获取子级
for (ResourceDO entity : data) {
Map<String, Object> map = new HashMap<>();
if ("0".equals(entity.getParentId())) {
map.put("id", entity.getId());
map.put("parentId", entity.getParentId());
map.put("name", entity.getName());
map.put("children", getChildren(data, entity.getId()));
menuList.add(map);
}
}
return menuList;
}
/**
* 递归处理:通过id获取子级,查询子级下的子级
*
* @param data 数据库的原始数据
* @param id 主id
* @return 该id下得子级
*/
public List<Map<String, Object>> getChildren(List<ResourceDO> data, String id) {
List<Map<String, Object>> list = new ArrayList<>();
if (data == null || data.size() == 0 || id == null) {
return list;
}
for (ResourceDO entity : data) {
Map<String, Object> map = new HashMap<>();
//如果本级id与数据的父id相同,就说明是子父级关系
if (id.equals(entity.getParentId())) {
map.put("id", entity.getId());
map.put("parentId", entity.getParentId());
map.put("name", entity.getName());
//查询子级下的子级
map.put("children", getChildren(data, entity.getId()));
list.add(map);
}
}
return list;
}
2、方式二:组装带有children关联性的对象
在实体列中定义一个 children集合:
private List<ResourceDO> children = new ArrayList<>();
返回的是实体类对象的所有值,这里操作的都是集合存储对象的引用
/**
* 将有父子关系的数据转换成树形结构数据
*
* @return 最终的树状结构的集合数据
*/
@Override
public List<ResourceDO> getMuneTree2() {
// 获取数据库中带有有父子关系的数据
List<ResourceDO> data = resourceDOMapper.selectAll();
// 复制data数据
List<ResourceDO> menuList = new ArrayList<>(data);
// 遍历两次data来组装带有children关联性的对象,如果找到子级就删除menuList的数据
for (ResourceDO entity : data) {
for (ResourceDO entity2 : data) {
//如果本级id与数据的父id相同,就说明是子父级关系
if (entity.getId().equals(entity2.getParentId())) {
entity.getChildren().add(entity2);
menuList.remove(entity2);
}
}
}
return menuList;
}
ends~