List集合转化为Tree父子节点结构数据的demo实现

4 篇文章 0 订阅
1 篇文章 0 订阅

在这里插入图片描述

前言说明

此文章是衔接MySQL根据父子节点向上/向下递归查询SQL实现Demo的后续,在上篇文章中我们知道了怎么在数据库中去通过递归函数,向上或者向下递归查询节点数据,那么这篇文章是一个比较完整讲解了从数据库出来的数据,怎么转化为Tree结构的数据返回给前端,效果图可见下图。

效果图

  1. 根据父节点递归查子节点数据库查询图和代码转化为Tree结构数据图
    在这里插入图片描述
    在这里插入图片描述
  2. 根据子节点递归向上查父节点数据库图和代码转化为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}{咱们来日方长,有缘江湖再见,告辞!} 咱们来日方长,有缘江湖再见,告辞!

在这里插入图片描述

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值