【java实现结果集转为树结构,树转为扁平结构】

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.queryZbjcpjTreepgsql查回的具有父子关系无树形的结果集;接下来遍历结果集转为树结构(含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文件

queryZbjcpjTreequeryZbjcpjParentId两个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扁平结构;算法使用到递归与迭代。

树其他链接

前后端构建侧边栏多级动态导航栏—树形结构

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/45142.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【python算法学习1】用递归和循环分别写下 fibonacci 斐波拉契数列,比较差异

问题&#xff1a; fibonacci 斐波拉契数列&#xff0c;用递归和循环的方法分别写,比较递归和循环的思路和写法的差别 最直接的思路&#xff0c;是写递归方法 循环方法的稍微有点绕&#xff0c;我觉得问题主要是出在&#xff0c;总结循环的通项公式更麻烦&#xff0c;难在数学…

多目标螳螂搜索算法MOMSA求解无人机三维路径规划,可以自行修改障碍物位置(MATLAB代码)

无人机路径规划多目标优化求解是一个复杂的过程&#xff0c;涉及到多个目标的考量和优化算法的应用。以下是一些关键点和相关算法的概述&#xff1a; 1. **多目标优化策略**&#xff1a;在无人机路径规划中&#xff0c;需要同时考虑多个目标&#xff0c;如路径长度、安全性、飞…

关于delete和delete[ ]混用的未定义问题解释

我们知道delete用于释放一个动态空间&#xff0c;而delete[ ]用于释放多个动态空间&#xff0c;但是如果我们混用的话会导致什么问题&#xff1f;我在博客上看了许多文章&#xff0c;但不尽人意&#xff0c;因此写下这篇文章让你知其然知其所以然&#xff08;浅薄的解释&#x…

大数据学习之Spark基础

Spark基础 简述 1、spark作业执行的特点&#xff1a; &#xff08;1&#xff09;只有遇到行动算子的时候&#xff0c;整个spark作业才会被触发执行 &#xff08;2&#xff09;遇到几次&#xff0c;执行几次 2、RDD: 弹性分布式数据集 弹性&#xff1a;数据量可大可小 RDD类似…

插片式远程 I/O模块:Profinet总线耦合器在SIMATIC Manager配置

XD9000是Profinet总线耦合器&#xff0c;单个耦合器最多可扩展32个I/O模块&#xff01;本文将详细介绍如何在SIMATIC Manager中配置插片式远程 I/O模块的Profinet总线耦合器&#xff0c;帮助您更好地应用这一技术。 一、SIMATIC Manager软件组态步骤&#xff1a; 1、创建工程&…

MySQL8之mysql-community-icu-data-files的作用

MySQL8中的mysql-community-icu-data-files包主要提供国际组件&#xff08;ICU&#xff0c;International Components for Unicode&#xff09;的数据文件&#xff0c;这些文件对于MySQL数据库处理多语言数据和进行Unicode字符集转换至关重要。具体来说&#xff0c;mysql-commu…

什么是敏捷本地化

快速、敏捷的多语言产品和服务交付正逐渐成为众多行业的常态。在这种情况下&#xff0c;重点从传统的期望&#xff08;即在合理的时间框架内翻译大量内容&#xff09;转变为翻译工作量非常大的小片段&#xff0c;通常在2-3到12-24小时之间&#xff0c;通常在周末或假期。 Logr…

IntelliJ IDEA自定义菜单(Menus)、任务栏(toolbars)详细教程

一、自定义菜单 1、打开Settings&#xff0c;找到Menus and Toolbars 2、点击右边的Main Menu&#xff0c;点击号&#xff0c;选择Add Action 3、弹出Add Action弹窗&#xff0c;搜索或者选择你要添加的指令 二、自定义工具栏 1、右键IDEA上方的工具栏空白位置&#xff0c;选…

AIGC各个应用场景下的模型选择

需要注意的是&#xff0c;下述模型可以在不同任务和领域中灵活应用&#xff0c;它们的归属也会根据模型的设计和主要应用领域而有所变化&#xff0c;并不绝对。 自然语言处理模型 模型层中自然语言理解(Natural LanguageUnderstanding&#xff0c;NLU)和自然语言生成(NaturalL…

计算机网络体系结构解析

OSI参考模型 与 TCP/IP模型 如图所示 TCP/IP模型有几层 应用层&#xff1a;只需要专注于为用户提供应用功能 HTTP、SMTP、Telnet等&#xff0c;工作在操作系统中的用户态&#xff0c;传输层及以下工作在内核态传输层&#xff1a;为应用层提供网络支持&#xff08;TCP、UDP传…

vue3实现在style中使用响应式变量

vue2的时候需要在style模块中访问script模块中的响应式变量&#xff0c;为此不得不使用css变量去实现。现在vue3已经内置了这个功能啦&#xff0c;可以在style中使用v-bind指令绑定script模块中的响应式变量。 示例 <template><div><span>hello </span&…

内网穿透方案@远程串流控制方案@简单易用的虚拟组网方案

文章目录 串流控制和远程桌面控制相关概念 串流软件和方案商业软件方案开源方案Sunshinesunshine 自启设置 MoonLight 利用串流软件远程控制VPN 虚拟组网实现异地设备串流控制内网穿透关键概念 内网穿透方案简单易用相关服务软件使用Ngrok实现内网穿透开源软件方案Frp 串流控制…

40个高阶ChatGPT学术论文指令集(附GPT使用链接)

我精心挑选的40个顶尖ChatGPT学术论文指令集&#xff0c;无疑将成为你撰写论文和开展研究的珍贵资源&#xff0c;极力推荐你珍藏起来&#xff01;这些建议极具实用价值&#xff0c;能有效提高你的研究工作效率&#xff0c;使得论文撰写过程轻松许多。 在开始前&#xff0c;提示…

力扣 454四数相加

这个题给了四个数组&#xff0c;可以两两判断&#xff0c;就类比两数相加那道题了 对于num1 num2 用unordered_map存储&#xff0c;key是num1&#xff0c;num2中数字相加之和&#xff0c;value是值出现的次数 for(int a:num1) {for(int b:num2 {map[ab]; 最后要计算四个数…

8、matlab彩色图和灰度图的二值化算法汇总

1、彩色图和灰度图的二值化算法汇总原理及流程 彩色图和灰度图的二值化算法的原理都是将图像中的像素值转化为二值&#xff08;0或1&#xff09;&#xff0c;以便对图像进行简化或者特定的图像处理操作。下面分别介绍彩色图和灰度图的二值化算法的原理及流程&#xff1a; 1&a…

坑2.Date类型的请求参数

前端 <el-form-item label"结束日期" prop"endTime"><el-date-pickerv-model"dataForm.endTime"type"date"value-format"yyyy-MM-dd HH:mm:ss"placeholder"选择日期"></el-date-picker></el…

pip install xxx报错ERROR: No matching distribution found for openturns

目录 问题描述解决方案解决方案一&#xff1a;配置代理解决方案二&#xff1a;下载包后手动安装解决方案三&#xff1a;更新pip解决方案四&#xff1a;使用conda安装解决方案五&#xff1a;跳过代理综合步骤 问题描述 C:\Users\54867>pip install openturns WARNING: Ignor…

Python功能制作之获取CSDN所有发布文章的对应数据

大家好&#xff0c;今天我要分享的是一个实用的Python脚本&#xff0c;它可以帮助你批量获取CSDN博客上所有发布文章的相关数据&#xff0c;并将这些数据保存到Excel文件中。此外&#xff0c;脚本还会为每篇文章获取一个质量分&#xff0c;并将这个分数也记录在Excel中。让我们…

多周期路径的约束与设置原则

本节将回顾工具检查建立保持时间的原则&#xff0c;接下来介绍设置多周期后的检查原则。多周期命令是设计约束中常用的一个命令&#xff0c;用来修改默认的建立or保持时间的关系。基本语法如下 默认的建立时间与保持时间的检查方式 DC工具计算默认的建立保持时间关系是基于时钟…

Python实战:拥有设闹钟功能的可视化动态闹钟的实现

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…