如何查询树形结构的数据

canace
2023-04-14 / 0 评论 / 307 阅读 / 正在检测是否收录...

如何查询树形结构的数据

  1. 在遇到数据库保存的数据为树形结构,如多级分类列表或者评论等,此处以分类列表举例

image-20230414113216635

我们需要向前端返回如下部分数据

[
  {
    "id": "1-1",
    "name": "前端开发",
    "label": "前端开发",
    "parentid": "1",
    "isShow": 1,
    "orderby": 1,
    "isLeaf": 0,
    "childrenTreeNodes": [
      {
        "id": "1-1-1",
        "name": "HTML/CSS",
        "label": "HTML/CSS",
        "parentid": "1-1",
        "isShow": 1,
        "orderby": 1,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-1-10",
        "name": "其它",
        "label": "其它",
        "parentid": "1-1",
        "isShow": 1,
        "orderby": 10,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-1-2",
        "name": "JavaScript",
        "label": "JavaScript",
        "parentid": "1-1",
        "isShow": 1,
        "orderby": 2,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-1-3",
        "name": "jQuery",
        "label": "jQuery",
        "parentid": "1-1",
        "isShow": 1,
        "orderby": 3,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-1-4",
        "name": "ExtJS",
        "label": "ExtJS",
        "parentid": "1-1",
        "isShow": 1,
        "orderby": 4,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-1-5",
        "name": "AngularJS",
        "label": "AngularJS",
        "parentid": "1-1",
        "isShow": 1,
        "orderby": 5,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-1-6",
        "name": "ReactJS",
        "label": "ReactJS",
        "parentid": "1-1",
        "isShow": 1,
        "orderby": 6,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-1-7",
        "name": "Bootstrap",
        "label": "Bootstrap",
        "parentid": "1-1",
        "isShow": 1,
        "orderby": 7,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-1-8",
        "name": "Node.js",
        "label": "Node.js",
        "parentid": "1-1",
        "isShow": 1,
        "orderby": 8,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-1-9",
        "name": "Vue",
        "label": "Vue",
        "parentid": "1-1",
        "isShow": 1,
        "orderby": 9,
        "isLeaf": 1,
        "childrenTreeNodes": null
      }
    ]
  },
  {
    "id": "1-10",
    "name": "研发管理",
    "label": "研发管理",
    "parentid": "1",
    "isShow": 1,
    "orderby": 10,
    "isLeaf": 0,
    "childrenTreeNodes": [
      {
        "id": "1-10-1",
        "name": "敏捷开发",
        "label": "敏捷开发",
        "parentid": "1-10",
        "isShow": 1,
        "orderby": 1,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-10-2",
        "name": "软件设计",
        "label": "软件设计",
        "parentid": "1-10",
        "isShow": 1,
        "orderby": 2,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-10-3",
        "name": "软件测试",
        "label": "软件测试",
        "parentid": "1-10",
        "isShow": 1,
        "orderby": 3,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-10-4",
        "name": "研发管理",
        "label": "研发管理",
        "parentid": "1-10",
        "isShow": 1,
        "orderby": 4,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-10-5",
        "name": "其它",
        "label": "其它",
        "parentid": "1-10",
        "isShow": 1,
        "orderby": 5,
        "isLeaf": 1,
        "childrenTreeNodes": null
      }
    ]
  },
  {
    "id": "1-11",
    "name": "系统运维",
    "label": "系统运维",
    "parentid": "1",
    "isShow": 1,
    "orderby": 11,
    "isLeaf": 0,
    "childrenTreeNodes": [
      {
        "id": "1-11-1",
        "name": "Linux",
        "label": "Linux",
        "parentid": "1-11",
        "isShow": 1,
        "orderby": 1,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-11-10",
        "name": "其它",
        "label": "其它",
        "parentid": "1-11",
        "isShow": 1,
        "orderby": 10,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-11-2",
        "name": "Windows",
        "label": "Windows",
        "parentid": "1-11",
        "isShow": 1,
        "orderby": 2,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-11-3",
        "name": "UNIX",
        "label": "UNIX",
        "parentid": "1-11",
        "isShow": 1,
        "orderby": 3,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-11-4",
        "name": "Mac OS",
        "label": "Mac OS",
        "parentid": "1-11",
        "isShow": 1,
        "orderby": 4,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-11-5",
        "name": "网络技术",
        "label": "网络技术",
        "parentid": "1-11",
        "isShow": 1,
        "orderby": 5,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-11-6",
        "name": "路由协议",
        "label": "路由协议",
        "parentid": "1-11",
        "isShow": 1,
        "orderby": 6,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-11-7",
        "name": "无线网络",
        "label": "无线网络",
        "parentid": "1-11",
        "isShow": 1,
        "orderby": 7,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-11-8",
        "name": "Ngnix",
        "label": "Ngnix",
        "parentid": "1-11",
        "isShow": 1,
        "orderby": 8,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-11-9",
        "name": "邮件服务器",
        "label": "邮件服务器",
        "parentid": "1-11",
        "isShow": 1,
        "orderby": 9,
        "isLeaf": 1,
        "childrenTreeNodes": null
      }
    ]
  },
  {
    "id": "1-2",
    "name": "移动开发",
    "label": "移动开发",
    "parentid": "1",
    "isShow": 1,
    "orderby": 2,
    "isLeaf": 0,
    "childrenTreeNodes": [
      {
        "id": "1-2-1",
        "name": "微信开发",
        "label": "微信开发",
        "parentid": "1-2",
        "isShow": 1,
        "orderby": 1,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-2-2",
        "name": "iOS",
        "label": "iOS",
        "parentid": "1-2",
        "isShow": 1,
        "orderby": 2,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-2-3",
        "name": "手游开发",
        "label": "手游开发",
        "parentid": "1-2",
        "isShow": 1,
        "orderby": 3,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-2-4",
        "name": "Swift",
        "label": "Swift",
        "parentid": "1-2",
        "isShow": 1,
        "orderby": 4,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-2-5",
        "name": "Android",
        "label": "Android",
        "parentid": "1-2",
        "isShow": 1,
        "orderby": 5,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-2-6",
        "name": "ReactNative",
        "label": "ReactNative",
        "parentid": "1-2",
        "isShow": 1,
        "orderby": 6,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-2-7",
        "name": "Cordova",
        "label": "Cordova",
        "parentid": "1-2",
        "isShow": 1,
        "orderby": 7,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-2-8",
        "name": "其它",
        "label": "其它",
        "parentid": "1-2",
        "isShow": 1,
        "orderby": 8,
        "isLeaf": 1,
        "childrenTreeNodes": null
      }
    ]
  },
  {
    "id": "1-3",
    "name": "编程开发",
    "label": "编程开发",
    "parentid": "1",
    "isShow": 1,
    "orderby": 3,
    "isLeaf": 0,
    "childrenTreeNodes": [
      {
        "id": "1-3-1",
        "name": "C/C++",
        "label": "C/C++",
        "parentid": "1-3",
        "isShow": 1,
        "orderby": 1,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-3-2",
        "name": "Java",
        "label": "Java",
        "parentid": "1-3",
        "isShow": 1,
        "orderby": 2,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-3-3",
        "name": ".NET",
        "label": ".NET",
        "parentid": "1-3",
        "isShow": 1,
        "orderby": 3,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-3-4",
        "name": "Objective-C",
        "label": "Objective-C",
        "parentid": "1-3",
        "isShow": 1,
        "orderby": 4,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-3-5",
        "name": "Go语言",
        "label": "Go语言",
        "parentid": "1-3",
        "isShow": 1,
        "orderby": 5,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-3-6",
        "name": "Python",
        "label": "Python",
        "parentid": "1-3",
        "isShow": 1,
        "orderby": 6,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-3-7",
        "name": "Ruby/Rails",
        "label": "Ruby/Rails",
        "parentid": "1-3",
        "isShow": 1,
        "orderby": 7,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-3-8",
        "name": "其它",
        "label": "其它",
        "parentid": "1-3",
        "isShow": 1,
        "orderby": 8,
        "isLeaf": 1,
        "childrenTreeNodes": null
      }
    ]
  },
  {
    "id": "1-5",
    "name": "人工智能",
    "label": "人工智能",
    "parentid": "1",
    "isShow": 1,
    "orderby": 5,
    "isLeaf": 0,
    "childrenTreeNodes": [
      {
        "id": "1-5-1",
        "name": "机器学习",
        "label": "机器学习",
        "parentid": "1-5",
        "isShow": 1,
        "orderby": 1,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-5-2",
        "name": "深度学习",
        "label": "深度学习",
        "parentid": "1-5",
        "isShow": 1,
        "orderby": 2,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-5-3",
        "name": "语音识别",
        "label": "语音识别",
        "parentid": "1-5",
        "isShow": 1,
        "orderby": 3,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-5-4",
        "name": "计算机视觉",
        "label": "计算机视觉",
        "parentid": "1-5",
        "isShow": 1,
        "orderby": 4,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-5-5",
        "name": "NLP",
        "label": "NLP",
        "parentid": "1-5",
        "isShow": 1,
        "orderby": 5,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-5-6",
        "name": "强化学习",
        "label": "强化学习",
        "parentid": "1-5",
        "isShow": 1,
        "orderby": 6,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-5-7",
        "name": "其它",
        "label": "其它",
        "parentid": "1-5",
        "isShow": 1,
        "orderby": 7,
        "isLeaf": 1,
        "childrenTreeNodes": null
      }
    ]
  },
  {
    "id": "1-9",
    "name": "智能硬件/物联网",
    "label": "智能硬件/物联网",
    "parentid": "1",
    "isShow": 1,
    "orderby": 9,
    "isLeaf": 0,
    "childrenTreeNodes": [
      {
        "id": "1-9-1",
        "name": "无线通信",
        "label": "无线通信",
        "parentid": "1-9",
        "isShow": 1,
        "orderby": 1,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-9-10",
        "name": "物联网技术",
        "label": "物联网技术",
        "parentid": "1-9",
        "isShow": 1,
        "orderby": 10,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-9-11",
        "name": "其它",
        "label": "其它",
        "parentid": "1-9",
        "isShow": 1,
        "orderby": 11,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-9-2",
        "name": "电子工程",
        "label": "电子工程",
        "parentid": "1-9",
        "isShow": 1,
        "orderby": 2,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-9-3",
        "name": "Arduino",
        "label": "Arduino",
        "parentid": "1-9",
        "isShow": 1,
        "orderby": 3,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-9-4",
        "name": "体感技术",
        "label": "体感技术",
        "parentid": "1-9",
        "isShow": 1,
        "orderby": 4,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-9-5",
        "name": "智能硬件",
        "label": "智能硬件",
        "parentid": "1-9",
        "isShow": 1,
        "orderby": 5,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-9-6",
        "name": "驱动/内核开发",
        "label": "驱动/内核开发",
        "parentid": "1-9",
        "isShow": 1,
        "orderby": 6,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-9-7",
        "name": "单片机/工控",
        "label": "单片机/工控",
        "parentid": "1-9",
        "isShow": 1,
        "orderby": 7,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-9-8",
        "name": "WinCE",
        "label": "WinCE",
        "parentid": "1-9",
        "isShow": 1,
        "orderby": 8,
        "isLeaf": 1,
        "childrenTreeNodes": null
      },
      {
        "id": "1-9-9",
        "name": "嵌入式",
        "label": "嵌入式",
        "parentid": "1-9",
        "isShow": 1,
        "orderby": 9,
        "isLeaf": 0,
        "childrenTreeNodes": [
          {
            "id": "1-9-9-1",
            "name": "嵌入式基础",
            "label": "嵌入式基础",
            "parentid": "1-9-9",
            "isShow": 1,
            "orderby": 1,
            "isLeaf": 1,
            "childrenTreeNodes": null
          }
        ]
      }
    ]
  }
]
  1. 由于返回的是一个List集合,因此需要定义一个DTO类表示分类信息的模型类
@Data
public class CourseCategoryTreeDto extends CourseCategory {

    //子节点
    List<CourseCategoryTreeDto> childrenTreeNodes;
}
  1. 定义Controller类
@Resource
private CourseCategoryService categoryService;

@GetMapping("/course-category/tree-nodes")
 public List<CourseCategoryTreeDto> queryCatTreeNodes(){
   return categoryService.queryCatTreeNodes("1"); //此处1为根节点
}
  1. 定义Mapper
public interface CourseCategoryMapper extends BaseMapper<CourseCategory> {

    public List<CourseCategoryTreeDto> selectTreeNodes(String id);
}

写递归SQL(用于不确定有几级层级)

    <!-- SQL递归查询数据库树形结构 -->
    <select id="selectTreeNodes" parameterType="String" resultType="com.xuecheng.content.model.dto.CourseCategoryTreeDto">
        WITH recursive t1 as(
            SELECT * from course_category WHERE id = #{id}
            UNION ALL
            SELECT c2.* from course_category c2 INNER JOIN t1 on t1.id = c2.parentid
        )
        SELECT * from t1 order by t1.id, t1.orderby
    </select>

内连接查询(确定有多少级层级)

  select
       one.id            one_id,
       one.name          one_name,
       one.parentid      one_parentid,
       one.orderby       one_orderby,
       one.label         one_label,
       two.id            two_id,
       two.name          two_name,
       two.parentid      two_parentid,
       two.orderby       two_orderby,
       two.label         two_label
   from course_category one
            inner join course_category two on one.id = two.parentid
   where one.parentid = 1
     and one.is_show = 1
     and two.is_show = 1
   order by one.orderby,
            two.orderby
  1. Service和其实现类
//Service类
public interface CourseCategoryService extends IService<CourseCategory> {
    List<CourseCategoryTreeDto> queryCatTreeNodes(String id);
}



//实现类
@Service
public class CourseCategoryServiceImpl extends ServiceImpl<CourseCategoryMapper, CourseCategory> implements CourseCategoryService {

    @Resource
    CourseCategoryMapper courseCategoryMapper;

    /**
     * 根据id获取课程分类列表
     * @param id 根节点id
     * @return 课程分类列表
     */
    @Override
    public List<CourseCategoryTreeDto> queryCatTreeNodes(String id) {
        //执行SQL,获取查询数据
        List<CourseCategoryTreeDto> treeDtos = courseCategoryMapper.selectTreeNodes(id);

        //将结果转为map,便于后续找根节点,同时可以过滤当前id节点
       //.filter(item -> !id.equals(item.getId()))不显示根节点
        Map<String, CourseCategoryTreeDto> map = treeDtos.stream().filter(item -> !id.equals(item.getId())).collect(Collectors.toMap(CourseCategory::getId, value -> value, (key1, key2) -> key2));

        List<CourseCategoryTreeDto> list = new ArrayList<>();
        //遍历返回最终结果,排除根节点
        treeDtos.stream().filter(item -> !id.equals(item.getId())).forEach(item ->{
            //先将根节点的一级子节点放入数组
            if (item.getParentid().equals(id)){
                list.add(item);
            }

            //如果不为一级节点,就找到它的父节点,通过之前保存的map
            CourseCategoryTreeDto treeParent = map.get(item.getParentid());

            //如果存在父节点就将其放入它的父节点的list中
            if (treeParent != null){
                //如果它的父节点的子节点列表为空,就新建一个对象存储
                if (treeParent.getChildrenTreeNodes() == null){
                    treeParent.setChildrenTreeNodes(new ArrayList<>());
                }
                //不为空就放入子节点中
                //注意这里是需要获取子节点列表然后插入进入
                treeParent.getChildrenTreeNodes().add(item);
            }

        });

        return list;
    }
}
  1. 前端显示示例

image-20230414115947533

0

评论

博主关闭了所有页面的评论