使用Java Stream将邻接表组装成树
描述
在关系型数据库中保存树形结构最简单、最广泛的设计方案是采用邻接表(Adjacency List),也就是在一行记录中,用一个parent_id字段来引用同一张表的其他记录,比如:
id | name | parent_id |
---|---|---|
0 | 中国 | null |
1 | 北京市 | 0 |
2 | 昌平区 | 1 |
3 | 顺义区 | 1 |
4 | 上海市 | 0 |
5 | 静安区 | 4 |
6 | 黄浦区 | 4 |
实现
1 | import org.springframework.web.bind.annotation.GetMapping; |
1 | // curl -ivv http://localhost:7777/cities |
解析
使用stream进行过滤后,将结果收集到一个List中,需要注意如果没有满足条件的数据,那么收集的结果就是一个空List,而不是null。
1 | all.stream().filter(m -> Objects.equals(m.getParentId(), item.getId())).peek(m -> m.setChildren(findChildren(m, all))).collect(Collectors.toList()); |
这样就会出现叶子节点的children属性是一个空List:[],接口约定成这样是没有问题的,但是如果是要对接一些成熟的前端树组件,它们的默认行为是当children为[]时,会在节点前面显示为一个可展开的加号+,但是点击之后展开又没有子节点。
而如果接口返回的叶子节点的children属性是null,或者干脆不返回这个children属性,才会只显示一个叶子节点名(没有前面的展开符号)。
为了应对这样的情况,使用stream的collect方法就比较麻烦,但是如果是用在Spring MVC就容易太多。如果你的controller方法返回一个对象,那么Spring Boot框架会调用jackson这个JSON库来将你的对象序列化为一个JSON Object或JSON Array。
需要做的仅仅是在children属性上添加一个@Include.NON_EMPTY注解,这样当这个children属性是空List时,就会被忽略,不参与到序列化中:
1 | .NON_EMPTY |
参考
树形表结构设计总结 · Kyle’s Notebook https://www.yipwinghong.com/2021/01/01/DB_tree-table-design-summary/#/%E9%97%AD%E5%8C%85%E8%A1%A8%EF%BC%88Closure-Table%EF%BC%89
jackson 实体转json 为NULL或者为空不参加序列化_赶路人儿的博客-CSDN博客_jackson null不序列化 https://blog.csdn.net/liuxiao723846/article/details/46043933