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

news2024/11/12 15:56:02

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.zpfs
      from lw_zbjcpj zbjc
      left join lw_pjmxzb mxzb
        on zbjc.pjzb_id = mxzb.id
     where zbjc.pjpcdx_id = #{pjpcdxId})
  select t.*, level,CONNECT_BY_ISLEAF AS isleaf
    from query t
   start with sjzb = '0'
  connect by prior pjzb_id = sjzb
  
queryZbjcpjParentId
===
*根据批次对象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.zpfs
    from lw_zbjcpj zbjc
    left join lw_pjmxzb mxzb
      on zbjc.pjzb_id = mxzb.id
   where zbjc.pjpcdx_id =  #{pjpcdxId})
select id
  from query
 start 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 block
				e.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.zpfs
     FROM lw_zbjcpj zbjc
     LEFT JOIN lw_pjmxzb mxzb ON zbjc.pjzb_id = mxzb.id
    WHERE zbjc.pjpcdx_id = #{pjpcdxId}
),
tree AS (
   SELECT t.*, 1 AS level
     FROM query t
    WHERE sjzb = '0'
   UNION ALL
   SELECT q.*, tree.level + 1
     FROM query q
     JOIN 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 isleaf
  FROM 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.zpfs
     FROM lw_zbjcpj zbjc
     LEFT JOIN lw_pjmxzb mxzb ON zbjc.pjzb_id = mxzb.id
    WHERE zbjc.pjpcdx_id = #{pjpcdxId}
),
tree AS (
   SELECT id, pjzb_id, sjzb
     FROM query
    WHERE id = #{id}
   UNION ALL
   SELECT q.id, q.pjzb_id, q.sjzb
     FROM query q
     JOIN 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.coloradmin.cn/o/1919386.html

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

相关文章

opc ua设备数据 转MQTT项目案例

目录 1 案例说明 1 2 VFBOX网关工作原理 1 3 准备工作 2 4 配置VFBOX网关采集OPC UA的数据 2 5 用MQTT协议转发数据 4 6 配置参数说明 4 7 上报内容配置 5 8 其他说明 8 9 案例总结 8 1 案例说明 设置网关采集OPC UA设备数据把采集的数据转成MQTT协议转发给其他系统。 2 VFB…

【备战秋招】——算法题目训练和总结day3

【备战秋招】——算法题目训练和总结day3&#x1f60e; 前言&#x1f64c;BC149简写单词题解思路分析代码分享&#xff1a; dd爱框框题解思路分析代码分享&#xff1a; 除2&#xff01;题解思路分析代码分享&#xff1a; 总结撒花&#x1f49e; &#x1f60e;博客昵称&#xff…

Chromium源码阅读(7):了解WTF的静态字符串机制

在浏览器的实现中&#xff0c;处理HTML和CSS涉及大量的字符串操作&#xff0c;这些操作通常包括字符串的比较、查找和匹配。如果使用普通的字符串对这些进行操作&#xff0c;在面临大量DOM元素和CSS规则时会导致效率低下。 例如&#xff0c;当解析CSS时&#xff0c;属性名如col…

05_TypeScript 中的数据类型

TypeScript 中的数据类型 一、概述二、详解布尔类型&#xff08;boolean&#xff09; true / false数字类型&#xff08;number&#xff09;字符串类型&#xff08;string&#xff09;数组类型&#xff08;array&#xff09;元组类型&#xff08;tuple&#xff09; 属于数组的一…

【Qt 初识 Test】用图形化和代码的方式实现简单的Qt程序

文章目录 1. 通过图形化的方式实现&#x1f34e;2. 通过代码的方式实现 1. 通过图形化的方式实现&#x1f34e; 在界面创建出一个控件&#xff0c;显示 hello world&#xff0c;通过拖拽的方式实现&#xff1b; widget.ui文件如下&#xff1a;&#x1f50d; 生成的 ui_widget.…

【Java16】多态

向上类型转换 对于引用变量&#xff0c;在程序中有两种形态&#xff1a;一种是编译时类型&#xff0c;这种引用变量的类型在声明它的时候就决定了&#xff1b;另一种则是运行时类型&#xff0c;这种变量的类型由实际赋给它的对象决定。 当一个引用变量的编译时类型和运行时类…

mybatis日志记录方案

首先对指定表进行监控 对表进行监控,那么就要使用的是statementInterceptor 拦截器 使用拦截器那么就要写intercepts写拦截条件进行拦截 监控只对与增删改 查询不进行监控 对于字段的监控,是谁修改了字段,那么就进行报警,或者提醒 消息提醒使用钉钉机器人进行消息提醒 P…

AGI 之 【Hugging Face】 的【文本摘要】的 [评估PEGASUS ] / [ 微调PEGASUS ] / [生成对话摘要] 的简单整理

AGI 之 【Hugging Face】 的【文本摘要】的 [评估PEGASUS ] / [ 微调PEGASUS ] / [生成对话摘要] 的简单整理 目录 AGI 之 【Hugging Face】 的【文本摘要】的 [评估PEGASUS ] / [ 微调PEGASUS ] / [生成对话摘要] 的简单整理 一、简单介绍 二、文本摘要 三、在CNN/Daily…

【接口设计】如何设计统一 RESTful 风格的数据接口

如何设计统一 RESTful 风格的数据接口 1.版本控制1.1 通过 URL1.2 通过自定义请求头1.3 通过 Accept 标头 2.过滤信息3.确定 HTTP 的方法4.确定 HTTP 的返回状态5.定义统一返回的格式 近年来&#xff0c;随着移动互联网的发展&#xff0c;各种类型的客户端层出不穷。如果不统一…

347. 前 K 个高频元素(中等)

347. 前 K 个高频元素 1. 题目描述2.详细题解3.代码实现3.1 Python3.2 Java 1. 题目描述 题目中转&#xff1a;347. 前 K 个高频元素 2.详细题解 寻找出现频率前 k k k高的元素&#xff0c;因此需要先统计各个元素出现的次数&#xff0c;该步骤时间复杂度为 O ( n ) O(n) O(n)…

javaweb中的请求与响应--基于postman工具的应用(附带postman的详细安装步骤)

一、前言 后端的第一天感觉难度就上来了&#xff0c;可能是基础太过薄弱了吧。目前看视频已经有点跟不上了&#xff0c;果然15天想要拿下还是太勉强了点。30天还差不多。不知道读者们有没有好好的去学这方面的知识&#xff0c;没有什么是学不会的&#xff0c;关键是坚持。 Po…

【C语言】C语言-学生籍贯信息记录系统(源码+论文)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

C#Winform窗体中嵌入exe文件

1&#xff0c;效果以嵌入Modbus Slave为例&#xff1a; 2&#xff0c;代码&#xff1a; public partial class Form1 : Form{//设置嵌入exe的常量private const int nIndex -16;private const int dwNewLong 0x10000000;Process m_AppProcess;public Form1(){InitializeCompo…

了解AsyncRotationController

概述 基于android 15.0, 以从强制横屏App上滑退回桌面流程来分析 frameworks/base/services/core/java/com/android/server/wm/AsyncRotationController.javaAsyncRotationController 是一种控制器&#xff0c;用于处理设备显示屏旋转时非活动窗口的异步更新。这种控制器通过…

【记录】CSS|Tailwind 的主题定义的颜色的使用方法(--color啥的)

文章目录 【记录】CSS&#xff5c;Tailwind 的主题定义的颜色的使用方法&#xff08;--color 啥的&#xff09;省流版GPT 详细解释版Tailwind CSS 配置文件示例使用自定义颜色定义 CSS 变量总结 附赠个 Tips 【记录】CSS&#xff5c;Tailwind 的主题定义的颜色的使用方法&#…

【Python】已解决:ModuleNotFoundError: No module named ‘sklearn.cross_validation

文章目录 一、问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 &#xff08;机器学习分割数据问题&#xff09;解决“ModuleNotFoundError: No module named ‘sklearn.cross_validation’” 一、问题背景 在机器学习的实践中&#xff0c;数据分割是…

聚鼎装饰画:现在做装饰画能不能相信

在艺术的殿堂中&#xff0c;装饰画以其多变的风格和独特的魅力占据了一席之地。它们或清新淡雅&#xff0c;或浓烈奔放&#xff0c;总能为现代家居带来一丝生气与美感。然而&#xff0c;在这美丽的背后&#xff0c;却隐藏着一个令人困惑的问题&#xff1a;现在做装饰画&#xf…

[EasilyOpenJCL] 使用 Java 调用显卡 计算 和Java调用 CPU 进行计算 的基准测试!

设备环境介绍 easily-openJCL 是一个轻量级的 Java 语言下的 GPU 显卡 计算库&#xff0c;它提供了一套简单易用的 API&#xff0c;让用户能够轻松实现 GPU 计算操作。 通过 Java 调用 GPU 计算的一个库&#xff0c;使用非常简单的API就可以轻松应付 Java 数据类型在 GPU 中的…

程序使用多进程,打包.exe后,程序陷入死循环

最近写了一个深度学习程序&#xff0c;用cxfreezee打包exe后&#xff0c;在本地运行突然出现死循环&#xff0c;明明在pycharm运行一切正常。 排查了问题&#xff0c;怀疑是多进程的原因&#xff0c;解决办法&#xff1a; 在你的主程序前添加一行代码&#xff1a; if __name_…

Typescript 模块小知识-global scope

问题表现 在编写ts代码的时候遇到一个问题, 表现为, 如果在某个ts工程中, 如果多个文件里面没有任何导出export或者是export default, 那么这些文件如果有const或者是let定义相同的声明都会报错如下 无法重新声明块范围变量 a/a.ts 和 index.ts 和 index2.ts 都没有进行expor…