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

业务需求

数据库原本为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 方法处理每个根节点,列表 tree 拉平为扁平结构的列表;
flattenTree递归地进行先序遍历,将树节点按先序顺序添加到 flattenedList 中

/**
	 * 转为树节点
	 * @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扁平结构;算法使用到递归与迭代。

树其他链接

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值