前言
由于之前在写树结构遍历的时候都是 copy
的别人的代码,想着把功能完成就行,并没有真正理解如何实现的遍历的,又怎么递归。前几天尝试着自己写一个遍历树结构 List,其实很简单,所以能自己动手,决不要 copy
。先记录一个查询,增、删、改后续补上。
正文
实现思路
1. 先从数据库根据相应条件获取出树结构 List
2. 遍历获取到的数据将根节点取出
3. 遍历刚取出的列表,调用递归方法将子节点数据存放到根节点里
4. 就是这么 easy,直接贴上代码,细品
/** 从一个简单的DTO文件开始 */
public class TestDTO {
// 自身 ID
private Long id;
// 名称
private String name;
// 父节点 ID
private Long parentId;
// 子节点集合
private List<TestDTO> children;
// 其他属性
......
// setter and getter 方法
......
}
/** 实现类 */
@Service
public class TestServiceImpl implements TestService {
// Repository 当然是获取数据啦...
private final TestRepository testRepository;
// 这个是构造方法
public TestServiceImpl(TestRepository testRepository) {
this.testRepository = testRepository;
}
// 获取树结构数据
public List<TestDTO> getList() {
try {
// 从数据库里获取 List 数据,如果有条件,则根据相应条件获取,总之这里是一个树结构的 list
List<Test> tests = testRepository.findAll();
// ??? 为什么不是 TestDTO 类型?这里 Test 是 Entity,从数据库获取的数据当前是用 Entity 类型接收啦!
// 没关系的,可以转DTO
// 定义一个空数组,用来存放最终的树结构数据
List<TestDTO> result = new ArrayList<>();
// 第一步遍历获取到的数据,将根节点数据存放 result 里
for (Test test: tests) {
// 判断是否是根节点,就是 parentId,这里是从 0 开始,如果 parentId 为 0 ,则表示根节点
if (test.getParentId() == 0) {
// 这里可以将 entity 转为 DTO 存放
// 如果字段不多可以直接使用 set get 方法来存取,就像这样
TestDTO testDTO = new TestDTO();
testDTO.setId(test.getId);
testDTO.setName(test.getName);
testDTO.setParentId(test.getParentId);
// 如果字段太多,超过5个以上,还是建议使用 mapper 方法来转哦,具体如何使用 mapper 将 Entity 转为 DTO 请移步下方链接
result.add(testDTO);
}
}
// 根节点添加完就需要添加每个节点的子节点了,这里需要调用 递归方法 getChildren();
// 遍历根节点数据,为其设置子节点集合
for (TestDTO test: result) {
// 获取子节点数据,传入 当前节点 id 和 所有 list
List<TestDTO> childList = getChildren(test.getId(), tests);
// 将获取到的子节点集合添加到根节点里
test.setChildren(childList);
}
// 将一层一层的树结构数据返回吧!
return result;
} catch(Exception e) {
// 这里可以抛个异常
}
}
/**
* 获取子节点数据
* @param id 父节点 ID
* @param List<Test> tests 所有节点集合
* @return 返回子节点列表
*/
private List<TestDTO> getChildren(Long id, List<Test> tests) {
// 存在子节点数据
List<TestDTO> childList = new ArrayList<>();
// 遍历所有节点数据
for (Test item : tests) {
// 如果当前节点 ID 与父节点 ID 一致,表示当前数据是该节点的子节点
if (item.getParentId().equals(String.valueOf(id))) {
TestDTO testDTO = new TestDTO();
testDTO.setId(test.getId);
testDTO.setName(test.getName);
testDTO.setParentId(test.getParentId);
// 如果字段太多,超过5个以上,还是建议使用 mapper 方法来转哦,具体如何使用 mapper 将 Entity 转为 DTO 请移步下方链接
childList.add(testDTO);
}
}
// 重点来了,递归调用
for (TestDTO item : childList) {
// 调用自身方法,依次添加子节点数据
item.setChildren(getChildren(item.getId(), tests));
}
// 如果当前节点无子节点数据添加空数据,递归退出
if (childList.size() == 0) {
return new ArrayList<>();
}
// 返回最终的子节点数据
return childList;
}
}
链接:利用 mapper 方法将 Entity 转 DTO(以后再补上)