构建树形结构两种方法
我们在日常系统使用几乎都会遇到组织机构和行政区划的树形结构,那么如何返回树形结构给前端呢,下面是我构建行政区划树形所使用的两种方法,组织机构与其同理,数据库使用的是国产达梦数据库(同oracle)。
实体类
@Data
public class AreaTree {
private String id;
private String cname;
private String pid;
private List<AreaTree> treeList;
}
1、使用mybatis自带的递归方法
使用mybatis自带递归方法配合resultMap返回树形结构,这个方法同时适用无限层级的下钻。
(1)、sqlMapper.xml
<resultMap id="areaTreeMaps" type="com.lingxu.module.earlyWarn.vo.AreaTree">
<id property="id" column="id" jdbcType="VARCHAR"/>
<result property="pid" column="pid" jdbcType="VARCHAR" />
<result property="cname" column="cname" jdbcType="VARCHAR"/>
<collection property="treeList" select="findRegionTreeByPid"
ofType="com.lingxu.module.earlyWarn.vo.AreaTree" column="{pid=id}">
</collection>
</resultMap>
<select id="findRegionTree" resultMap="areaTreeMaps">
SELECT ID,CNAME,PID FROM SYS_CITY WHERE ID = '320000'
</select>
<select id="findRegionTreeByPid" resultMap="areaTreeMaps">
SELECT ID,CNAME,PID FROM SYS_CITY WHERE PID = #{pid}
</select>
(2)、sqlMapper.java
将第一个sql查询结果中的pid作为参数传值给第二个sql
List<AreaTree> findRegionTree();
List<AreaTree> findRegionTreeByPid(String pid);
(3)、sqlService.java
service直接调用第一个方法即可,返回的就是树形结构
public Result findRegionTree() {
try {
List<AreaTree> areaTrees = issueManageMapper.findRegionTree();
return Result.ok(areaTrees,"查询成功");
}catch (Exception e){
log.error("数据查询异常",e);
return Result.error("查询异常");
}
}
2、使用Java递归查询
使用Java递归方法需要修改查询sql,将所有的数据全部查询出来,然后根据根节点的pid值进行分组递归处理。
(1)、sqlMapper.xml
注:with as 语法在mysql8.0版本以下无法使用
<select id="findRegionTree" resultType="com.lingxu.module.earlyWarn.vo.AreaTree">
WITH CTE_TEMP(ID,PID,CNAME) AS (
SELECT ID,PID,CNAME FROM SYS_CITY WHERE PID = '320000' OR SYS_CITY.ID = '320000'
UNION ALL
SELECT A.ID,A.PID,A.CNAME FROM SYS_CITY A
INNER JOIN CTE_TEMP B ON A.PID = B.ID
)
SELECT DISTINCT * FROM CTE_TEMP ORDER BY ID
</select>
(2)、sqlMapper.java
List<AreaTree> findRegionTree();
(3)、sqlService.java
参数ids就是树形结构作为根节点的pid值,我这边是0,按照自己需要的值修改即可。
public Result findRegionTree() {
try {
List<AreaTree> areaTrees = issueManageMapper.findRegionTree();
return Result.ok(buildTreeList(areaTrees,"0"),"查询成功");
}catch (Exception e){
log.error("数据查询异常",e);
return Result.error("查询异常");
}
}
//处理行政区划树
private static List<AreaTree> buildTreeList(List<AreaTree> treeList, String ids){
//获取parentId的根节点
List<AreaTree> areaTrees = treeList.stream().filter(item -> item.getPid().equals(ids)).collect(Collectors.toList());
//根据parentId进行分组
Map<String,List<AreaTree>> map = treeList.stream().collect(Collectors.groupingBy(AreaTree::getPid));
recursionFnTree(areaTrees,map);
return areaTrees;
}
private static void recursionFnTree(List<AreaTree> areaTrees,Map<String,List<AreaTree>> map){
for(AreaTree areaTree : areaTrees){
List<AreaTree> childList = map.get(areaTree.getId());
areaTree.setTreeList(childList);
if (null != childList && 0 < childList.size()){
recursionFnTree(childList,map);
}else {
areaTree.setTreeList(new ArrayList<>());
}
}
}
返回结构样式
至此使用两种构建树形结构的方法就结束了,第一种方法需要递归查询数据库,这样就导致效率变低。本地测试第一种方法返回大概需要3s左右,而第二种方法返回需要90ms,所以更推荐第二种方法。
本篇文章是个人一些见解,如有不足之处还请指出。