list转为树,树拉平
- 业务需求
- oracle实现树结构
- 1、**Controller.java层** :前端调此处请求
- 2、**service层:** 逻辑结构 (zbjcpjService.java),重点:this.entityMapper.queryZbjcpjTree接口
- 3、**mapper层**:sql语句(数据库交互)(LwZbjcpjMapper.java---接口 )
- 4、**pjpc.md文件** 某业务相关sql语句
- pgsql实现树结构
- 1、**Controller.java层**
- 2、**service层**
- 3、**mapper层**无改变,接口名不修改
- 4、**pjpc.md文件**
- 树其他链接
业务需求
数据库原本为oracle后转为postgresql(后续简称为pgsql),原本使用start with …connect by prior在pgsql中无法使用,转为RECURSIVE但无法达到前者父子结构排序结果集(需求:查询所有子节点),sql语句转为java代码实现。
需求:打分:小项可打分,小项的父自动计算分数,前端要显示扁平list
界面如下:
开发语言:
springboot+beetsql+vue
oracle实现树结构
1、Controller.java层 :前端调此处请求
/*** 获取监测指标树形*/@RequestMapping(path = "${mda.model.name}/standard/entity/pjzbtx/lwPjdx/getZbjcpjTreeList", method = RequestMethod.POST)public IPage<LwZbjcpj> getZbjcpjTreeList(@RequestBody PageDTO<LwZbjcpj, LwZbjcpjQuery> request) {return zbjcpjService.getZbjcpjTreeList(request);}
2、service层: 逻辑结构 (zbjcpjService.java),重点:this.entityMapper.queryZbjcpjTree接口
public IPage<LwZbjcpj> getZbjcpjTreeList(PageDTO<LwZbjcpj, LwZbjcpjQuery> request) {Page<LwZbjcpj> page = new Page<>();page.setCurrent(request.getPageNo());page.setSize(request.getPageSize());String pjpcdxId = request.getSimpleCondition().getPjpcdxId();List<LwZbjcpj> zbjcpjTreeList = this.entityMapper.queryZbjcpjTree(pjpcdxId);page.setTotal(zbjcpjTreeList.size());page.setRecords(zbjcpjTreeList);return page;}
3、mapper层:sql语句(数据库交互)(LwZbjcpjMapper.java—接口 )
这里的queryZbjcpjTree接口对应pjpc.md中写的sql语句命名为queryZbjcpjTree
@Mapper
@SqlResource("pjpc")
public interface LwZbjcpjMapper extends BaseExtMapper<LwZbjcpj> {public List<LwZbjcpj> queryZbjcpjTree(@Param("pjpcdxId") String pjpcdxId);public List<String> queryZbjcpjParentId(@Param("pjpcdxId") String pjpcdxId, @Param("id") String id);}
4、pjpc.md文件 某业务相关sql语句
queryZbjcpjTree
===
*根据批次对象id查所有子节点
with query as(select zbjc.id,zbjc.pjzb_id,zbjc.pjpcdx_id,mxzb.zbmc,mxzb.sjzb,mxzb.zbcx,zbjc.pjfs,zbjc.xzfs,zbjc.zpfsfrom lw_zbjcpj zbjcleft join lw_pjmxzb mxzbon zbjc.pjzb_id = mxzb.idwhere zbjc.pjpcdx_id = #{pjpcdxId})select t.*, level,CONNECT_BY_ISLEAF AS isleaffrom query tstart with sjzb = '0'connect by prior pjzb_id = sjzbqueryZbjcpjParentId
===
*根据批次对象id和id查所有父节点id
with query as(select zbjc.id,zbjc.pjzb_id,zbjc.pjpcdx_id,mxzb.zbmc,mxzb.sjzb,mxzb.zbcx,zbjc.pjfs,zbjc.xzfs,zbjc.zpfsfrom lw_zbjcpj zbjcleft join lw_pjmxzb mxzbon zbjc.pjzb_id = mxzb.idwhere zbjc.pjpcdx_id = #{pjpcdxId})
select idfrom querystart with id = #{id}
connect by prior sjzb = pjzb_id
pgsql实现树结构
构造树节点类:尤其重要,树结构,关键属性:
private String id;
private String pid;
private String name;
private List<TreeNode> children;
@Data
@EqualsAndHashCode(callSuper = false)
public class ZbjcpjTreeNode {private String id;private String pjzbId; // 子private String sjzb; // 父private String zbmc;private String pjfs;private String xzfs;private String zpfs;private int level;private int isleaf;List<ZbjcpjTreeNode> children;
}
1、Controller.java层
/*** 获取监测指标树形*/@RequestMapping(path = "${mda.model.name}/standard/entity/pjzbtx/lwPjdx/getZbjcpjTreeList", method = RequestMethod.POST)public IPage<ZbjcpjTreeNode> getZbjcpjTreeList(@RequestBody PageDTO<LwZbjcpj, LwZbjcpjQuery> request) {return zbjcpjService.getZbjcpjTreeList(request);}
2、service层
解析:getTreeNode
把实体类转为有children的树结构;this.entityMapper.queryZbjcpjTree
pgsql查回的具有父子关系无树形的结果集;接下来遍历结果集转为树结构(含children的list);先序遍历树即可得到扁平数据列表
treeToList
树转扁平list, flattenTree
先序递归,有子则继续遍历
/*** 转为树节点* @param lwZbjcpj* @return*/private ZbjcpjTreeNode getTreeNode(LwZbjcpj lwZbjcpj) {ZbjcpjTreeNode treeNode = new ZbjcpjTreeNode();try {BeanUtils.copyProperties(treeNode, lwZbjcpj);} catch (IllegalAccessException | InvocationTargetException e) {// TODO Auto-generated catch blocke.printStackTrace();}return treeNode;}/*** 根据pjpcdxId查所有子节点 * @param request* @return*/public IPage<ZbjcpjTreeNode> getZbjcpjTreeList(PageDTO<LwZbjcpj, LwZbjcpjQuery> request) {Page<ZbjcpjTreeNode> page = new Page<>();page.setCurrent(request.getPageNo());page.setSize(request.getPageSize());String pjpcdxId = request.getSimpleCondition().getPjpcdxId();List<LwZbjcpj> zbjcpjTreeList = this.entityMapper.queryZbjcpjTree(pjpcdxId);
// 存储 子元素Map<String, ZbjcpjTreeNode> childMap = new LinkedHashMap<>();for (LwZbjcpj zbjcpj : zbjcpjTreeList) {ZbjcpjTreeNode zbjcNode = this.getTreeNode(zbjcpj);childMap.put(zbjcpj.getPjzbId(), zbjcNode);}// 树结构List<ZbjcpjTreeNode> tree = new ArrayList<ZbjcpjTreeNode>();for (String zbid: childMap.keySet()) {ZbjcpjTreeNode treeNode = childMap.get(zbid);if (treeNode.getSjzb() == null || "0".equals(treeNode.getSjzb())) { // 根节点tree.add(treeNode);} else { // 子节点ZbjcpjTreeNode parentNode = childMap.get(treeNode.getSjzb());if (parentNode.getChildren()==null) {parentNode.setChildren(new ArrayList<>());}parentNode.getChildren().add(treeNode);}}
// 将树形结构转换为列表List<ZbjcpjTreeNode> flattenedList = treeToList(tree);page.setTotal(flattenedList.size());page.setRecords(flattenedList);return page;}private List<ZbjcpjTreeNode> treeToList(List<ZbjcpjTreeNode> tree) {List<ZbjcpjTreeNode> flattenedList = new ArrayList<ZbjcpjTreeNode>();for (ZbjcpjTreeNode node:tree) {
// 拉平树flattenTree(node, flattenedList);}return flattenedList;}// 递归先序遍历转为扁平数据结构private void flattenTree(ZbjcpjTreeNode node, List<ZbjcpjTreeNode> flattenedList) {flattenedList.add(node);if (node.getChildren() != null) {for(ZbjcpjTreeNode child:node.getChildren()) {flattenTree(child, flattenedList);}}}
3、mapper层无改变,接口名不修改
4、pjpc.md文件
queryZbjcpjTree
与queryZbjcpjParentId
两个pgsql语句
queryZbjcpjTree
===
*根据批次对象id查所有子节点
WITH RECURSIVE query AS (SELECT zbjc.id,zbjc.pjzb_id,zbjc.pjpcdx_id,mxzb.zbmc,mxzb.sjzb,mxzb.zbcx,zbjc.pjfs,zbjc.xzfs,zbjc.zpfsFROM lw_zbjcpj zbjcLEFT JOIN lw_pjmxzb mxzb ON zbjc.pjzb_id = mxzb.idWHERE zbjc.pjpcdx_id = #{pjpcdxId}
),
tree AS (SELECT t.*, 1 AS levelFROM query tWHERE sjzb = '0'UNION ALLSELECT q.*, tree.level + 1FROM query qJOIN tree ON q.sjzb = tree.pjzb_id
)
SELECT tree.*, CASE WHEN EXISTS (SELECT 1 FROM query q WHERE q.sjzb = tree.pjzb_id) THEN 0 ELSE 1 END AS isleafFROM tree;queryZbjcpjParentId
===
*根据批次对象id和id查所有父节点id
WITH RECURSIVE query AS (SELECT zbjc.id,zbjc.pjzb_id,zbjc.pjpcdx_id,mxzb.zbmc,mxzb.sjzb,mxzb.zbcx,zbjc.pjfs,zbjc.xzfs,zbjc.zpfsFROM lw_zbjcpj zbjcLEFT JOIN lw_pjmxzb mxzb ON zbjc.pjzb_id = mxzb.idWHERE zbjc.pjpcdx_id = #{pjpcdxId}
),
tree AS (SELECT id, pjzb_id, sjzbFROM queryWHERE id = #{id}UNION ALLSELECT q.id, q.pjzb_id, q.sjzbFROM query qJOIN tree ON q.pjzb_id = tree.sjzb
)
SELECT id FROM tree;
queryZbjcpjTree的结果集为:level为1在一起,level为2气候,依次往后排,无法达到oracle使用start with…connect by prior就能达到排序的效果,因此使用java代码实现扁平数据树形展示
总结:俩要点,第一:结果集转为带children的树结构;第二:将树转为list扁平结构;算法使用到递归与迭代。
树其他链接
前后端构建侧边栏多级动态导航栏—树形结构