需求需要接口返回树状结构并且支持检索。实现效果如图所示

返回DTO结构应该这样
java
public class TreeDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "编码")
private String code;
@ApiModelProperty(value = "子树列表")
private List<TreeDTO> children;
public void updateChildren(List<CrtCategoryTreeDTO> children) {
this.children = children;
}
}
也曾咨询过大模型,感觉设计的比较复杂,实现困难。后面参考了同事的思路。在此基础上,增加了全路经的code来支持检索功能。
数据库对象设计
java
@Data
public class TreeEntity{
private String code;
//直接上级节点编码
private String parentCode;
//记录该节点在树上的完整路径
private List<String> fullPath
}
- fullPath:记录该节点在树上的完整路径
构建树的思路
- 首先把所有节点检索出来,这时候它们是平级的节点
- 根据parentCode找出各个节点的子孙节点
- 通过 递归 方式组装成树
查询所有节点
java
private List<TreeDTO> searchNodeByName(String searchName) {
//查找所有树相关节点
List<TreeEntity> allList = this.list(new LambdaQueryWrapper<TreeEntity>()
.eq(TreeEntity::getDeleted, false));
//获取符合条件节点的全路径,这里是只要名称模糊匹配searchName即可
Set<String> fullCode = buildFullCode(searchName, allList);
//根据全路径过滤出所有符合条件的节点
List<TreeDTO> allTreeDTO = allList.stream()
.filter(e -> fullCode.contains(e.getCode()))
.map(Convertor::toTreeDTO)
.toList();
//组装成树
return allTreeDTO.stream()
//找到种子节点也就是根节点作为启动节点
.filter(each -> StrUtil.isBlank(each.getParentCode()))
//递归查找子孙节点
.peek(rootDTO -> rootDTO.updateChildren(findChildren(rootDTO, allTreeDTO)))
.toList();
}
查找子孙节点
java
private List<TreeDTO> findChildren(TreeDTO parentDTO, List<TreeDTO> allDTO) {
String parentCode = parentDTO.getCode();
return allDTO.stream()
.filter(dto -> Objects.equals(dto.getParentCode(), parentCode))
//递归为子节点找孙子节点
.peek(childDTO -> childDTO.updateChildren(findChildren(childDTO, allDTO)))
.toList();
}
总结:
实现分类树说难也不难,说简单也不简单。关键是数据库实体必须有 直接上级节点编码(parentCode) 和 记录该节点在树上的完整路径(fullPath)