在实际开发中,经常会遇到树形结构的查询,如:菜单树、公司组织机构树、地区区划树等等业务,这里写下两个接口设计方案以供日后使用。
1.表结构设计
//一般单表树形结构基本上都为以下结构:
id,name,parentId,其他业务指标
//多表树形同理,设计思路都是通过parentId关联在一起
2.树形返回类设计
@Data
public class TreeNodeNew implements Serializable {
private String id;
//名称
private String name;
//上级id
private String parentId;
//子节点
private List<TreeNodeNew> childrenTreeNode;
//其他业务字段...
}
3.树形方案一:递归获取全部父子节点(若数据量太大则不推荐用此方法)
//传入需查询的根节点
public List<TreeNodeNew> findTree(String node) {
if(StrUtil.isEmpty(node)){
node = 当前登录人所绑定的node节点
}
//LambdaQueryWrapper<TreeEntity>wrapper = new LambdaQueryWrapper<>();
//wrapper.likeRight(TreeEntity::getId,node);
//查出全部数据,这里可以优化:想办法只查询出需要的所有数据,比如51-5101-510101这种格式的结构like51就行
List<TreeEntity> treeList = list(wrapper);
//转为返回树形集合对象
List<TreeNodeNew> trees = treeList.stream().map(op -> {
TreeNodeNew tree = new TreeNodeNew();
tree.setId(op.getCode());
tree.setParentId(op.getParentId());
tree.setName(op.getName());
return tree;
}).collect(Collectors.toList());
//用传入的根节点做第一级,调用getChildren设置所有下属节点
List<TreeNodeNew> collect = trees .stream()
.filter(item -> node.equals(item.getId()))
.map(item -> {
item.setChildrenTreeNode(getChildren(item, trees));
return item;
}).sorted(Comparator.comparing(TreeNodeNew::getId)).
collect(Collectors.toList());
return collect;
}
//传入父节点和所有数据节点信息集合,先查出所有父节点id为传入父节点id的下属数据,再递归set下属数据的childrens
private static List<TreeNodeNew> getChildren(TreeNodeNew treeEntity, List<TreeNodeNew> treeEntityList) {
List<TreeNodeNew> collect = treeEntityList.stream()
.filter(item -> treeEntity.getId().equals(item.getParentId()))
.map(item -> {
item.setChildrenTreeNode(getChildren(item, treeEntityList));
return item;
}).sorted(Comparator.comparing(TreeNodeNew::getId))
.collect(Collectors.toList());
return collect;
}
4.树形方案二:懒加载
//懒加载实现:每次传入一个根节点,只需要返回所有parentId为传入根节点的数据集合即可,前端每次拿到数据
//显示在根节点下面,点一次不同根节点请求一次,渲染一次
public List<TreeEntity> findTree(String node) {
LambdaQueryWrapper<TreeEntity> wrapper = new LambdaQueryWrapper<>();
//当传入根节点为空时,为第一次进入,默认返回该根节点信息
if(StrUtil.isEmpty(node)){
node = "";//根节点id
wrapper.eq(TreeEntity::getId,node);
}else{
//否则返回所有父节点id为传入根节点id的下级信息
wrapper.eq(TreeEntity::getParentId,node);
}
List<TreeEntity> list = list(wrapper);
return list;
}
5.总结:用方案一递归返回,优点是前端可以一次性拿到所有数据节点信息,相比懒加载不用点一次下级请求一次,只是第一次请求时效率慢点,可以考虑加缓存,但也要维护缓存。缺点是在数据量特别大的时候效率相当慢,如全国行政区划这种就适合用方案二懒加载形式,以时间换空间,方案一则相反。方案二优点是接口设计简单,维护容易。缺点是需要频繁请求数据来渲染页面。
文章来源地址https://www.toymoban.com/news/detail-508488.html
文章来源:https://www.toymoban.com/news/detail-508488.html
到了这里,关于关于树形结构查询的接口设计的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!