前言说明
此文章是衔接MySQL根据父子节点向上/向下递归查询SQL实现Demo的后续,在上篇文章中我们知道了怎么在数据库中去通过递归函数,向上或者向下递归查询节点数据,那么这篇文章是一个比较完整讲解了从数据库出来的数据,怎么转化为Tree结构的数据返回给前端,效果图可见下图。
效果图
- 根据父节点递归查子节点数据库查询图和代码转化为Tree结构数据图
- 根据子节点递归向上查父节点数据库图和代码转化为Tree结构数据图
数据库脚本
表结构
CREATE TABLE `school` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
`parent_id` int(11) NOT NULL COMMENT '父层级id',
`sname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '名称',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
初始化数据
INSERT INTO `test`.`school`(`id`, `parent_id`, `sname`) VALUES (1, -1, '大学');
INSERT INTO `test`.`school`(`id`, `parent_id`, `sname`) VALUES (2, 1, '高中');
INSERT INTO `test`.`school`(`id`, `parent_id`, `sname`) VALUES (3, 2, '小学');
INSERT INTO `test`.`school`(`id`, `parent_id`, `sname`) VALUES (4, 3, '学前班');
INSERT INTO `test`.`school`(`id`, `parent_id`, `sname`) VALUES (5, 3, '一年级');
INSERT INTO `test`.`school`(`id`, `parent_id`, `sname`) VALUES (6, 3, '二年级');
INSERT INTO `test`.`school`(`id`, `parent_id`, `sname`) VALUES (7, 1, '国中');
INSERT INTO `test`.`school`(`id`, `parent_id`, `sname`) VALUES (8, 7, '国一');
INSERT INTO `test`.`school`(`id`, `parent_id`, `sname`) VALUES (9, 4, '幼儿园');
代码实现
bean
package com.自己的包名.bean;
import lombok.Data;
import java.util.List;
@Data
public class SchoolVo {
private Integer id;
private Integer parentId;
private String sname;
private SchoolVo parent;
private List<SchoolVo> child;
}
dao
package com.自己的包名.dao.test3;
import com.自己的包名.bean.SchoolVo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface SchoolMapper {
/**
* @Author
* @Description 根据父节点id找出所有子节点
* @Date 14:21 2020/11/6
* @param parentId:
**/
List<SchoolVo> getChild(@Param("parentId") Integer parentId);
/**
* @Author
* @Description 根据子节点id找出所有父节点
* @Date 14:29 2020/11/6
* @param childId:
**/
List<SchoolVo> getParent(@Param("childId")Integer childId);
}
mapper
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.自己的包名.dao.SchoolMapper">
<resultMap id="BaseResultMap" type="com.自己的包名.bean.SchoolVo">
<id column="id" jdbcType="INTEGER" property="id"/>
<result column="parent_id" jdbcType="INTEGER" property="parentId"/>
<result column="sname" jdbcType="VARCHAR" property="sname"/>
</resultMap>
<select id="getChild" resultMap="BaseResultMap">
WITH RECURSIVE r_t AS (
SELECT
s1.id,
s1.parent_id,
s1.sname
FROM
school s1
WHERE
s1.id = #{parentId} UNION ALL
SELECT
s2.id,
s2.parent_id,
s2.sname
FROM
school s2
INNER JOIN r_t ON r_t.id = s2.parent_id
) SELECT
*
FROM
r_t
</select>
<select id="getParent" resultMap="BaseResultMap">
WITH RECURSIVE r_t AS (
SELECT
s1.id,
s1.parent_id,
s1.sname
FROM
school s1
WHERE
s1.id = #{childId} UNION ALL
SELECT
s2.id,
s2.parent_id,
s2.sname
FROM
school s2
INNER JOIN r_t ON r_t.parent_id = s2.id
) SELECT
*
FROM
r_t
</select>
</mapper>
转化Tree的工具类
package com.自己的包名.util;
import com.自己的包名.bean.School;
import com.自己的包名.bean.SchoolVo;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
/**
* @Author:
* @Date: 2020/11/6 14:30
* @Description:
*/
public class StringUtils {
/**
* @Author
* @Description 转化父的tree结构
* @Date 16:34 2020/11/6
* @param schoolVos:
**/
public static SchoolVo converTreeByParent(List<SchoolVo> schoolVos){
//已知集合中第一个元素就是最大父节点 然后循环去设置子节点
schoolVos.forEach(schoolVo -> {
schoolVo.setChild(getChild(schoolVos,schoolVo));
});
return schoolVos.get(0);
}
/**
* @Author
* @Description 给父节点设置子节点内容
* @Date 16:34 2020/11/6
* @param schoolVos:
* @param parent:
**/
public static List<SchoolVo> getChild(List<SchoolVo> schoolVos,SchoolVo parent){
List<SchoolVo> schoolVoList = new LinkedList<>();
schoolVos.stream().forEach(schoolVo -> {
if (schoolVo.getParentId().equals(parent.getId())){
schoolVoList.add(schoolVo);
getChild(schoolVoList,schoolVo);
}
});
parent.setChild(schoolVoList);
return schoolVoList;
}
/**
* @Author
* @Description 转换子节点的tree
* @Date 16:50 2020/11/6
* @param schoolVos:
**/
public static SchoolVo converTreeByChild(List<SchoolVo> schoolVos, SchoolVo child){
//已知集合中的第一个元素就是最小的子节点
//如果是最大的父节点时直接返回
if (child.getParentId() == -1){
return child;
}
List<SchoolVo> collect = schoolVos.stream()
.filter(schoolVo -> schoolVo.getId().equals(child.getParentId()))
.collect(Collectors.toList());
child.setParent(converTreeByChild(schoolVos,collect.get(0)));
return child;
}
}
service
package com.自己的包名.service;
public interface TreeService {
/**
* @Author
* @Description 根据父节点获取子节点
* @Date 18:06 2020/11/5
* @param id:
**/
Object getChild(Integer id);
/**
* @Author
* @Description 根据子节点查找父节点
* @Date 18:07 2020/11/5
* @param id:
**/
Object getParent(Integer id);
}
serviceImpl
package com.自己的包名.service.impl;
import com.自己的包名.bean.SchoolVo;
import com.自己的包名.dao.test3.SchoolMapper;
import com.自己的包名.service.TreeService;
import com.自己的包名.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @Author:
* @Date: 2020/11/5 18:05
* @Description:
*/
@Service
public class TreeServiceImpl implements TreeService {
@Autowired
SchoolMapper schoolMapper;
@Override
public Object getChild(Integer id) {
List<SchoolVo> schoolVoList = schoolMapper.getChild(id);
SchoolVo schoolVo = StringUtils.converTreeByParent(schoolVoList);
return schoolVo;
}
@Override
public Object getParent(Integer id) {
List<SchoolVo> schoolVoList = schoolMapper.getParent(id);
//数据库递归向上查询第一个是要查的子节点
return StringUtils.converTreeByChild(schoolVoList,schoolVoList.get(0));
}
}
controller
package com.自己的包名.controller;
import com.自己的包名.service.TreeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author:
* @Date: 2020/11/5 17:56
* @Description:
*/
@RestController
@RequestMapping("/tree")
public class TreeController {
@Autowired
TreeService treeService;
@GetMapping("/getChild/{id}")
public Object getChild(
@PathVariable("id")Integer id
){
return treeService.getChild(id);
}
@GetMapping("/getParent/{id}")
public Object getParent(
@PathVariable("id")Integer id
){
return treeService.getParent(id);
}
}
访问接口
- 父查子:http://localhost:8080/tree/getChild/1
- 子查父:http://localhost:8080/tree/getParent/4
这样就能得到和效果图一样的数据结构了~
就先说到这
\color{#008B8B}{ 就先说到这}
就先说到这
在下
A
p
o
l
l
o
\color{#008B8B}{在下Apollo}
在下Apollo
一个爱分享
J
a
v
a
、生活的小人物,
\color{#008B8B}{一个爱分享Java、生活的小人物,}
一个爱分享Java、生活的小人物,
咱们来日方长,有缘江湖再见,告辞!
\color{#008B8B}{咱们来日方长,有缘江湖再见,告辞!}
咱们来日方长,有缘江湖再见,告辞!