筛选树形菜单时关联其父节点和子节点

个人博客:无奈何杨(wnhyang)

个人语雀:wnhyang

共享语雀:在线知识共享

Github:wnhyang - Overview


树形菜单

在很多系统管理/菜单管理中经常会出现下面这样的树形菜单,它是通过前端的Tree组件来渲染的。

后端返回的树形结构数据如下图所示。

在已有的Elementant-vue等前端框架中这种组件都是有的,用起来也是非常简单。

Ant Design Vue

问题

现在需求是这样的,如上图菜单搜索有两个条件,状态和菜单名称,在查询菜单时需要通过模糊匹配菜单名称和精确匹配菜单状态来查询。这个本身很简单,问题是在树形菜单搜索时需要带上父菜单和子菜单,而不是只展示匹配到的菜单。

如:搜索“用户”时应该有下面的结果,在查询到相关节点后同时带上父节点和子节点返回。

Ant Design Vue在这里前端组件是有这样的实现的,如下。

前端是有这样的实现,而且很简单,那么有没有后端的实现方案呢?

如何实现

最直接的思路就是查询满足条件的菜单,然后去查这些菜单的父菜单和子菜单,讲起来很容易,但是这里要很注意重复节点和死循环。

重复节点问题:同级菜单具有相同的父节点,在查完第一个子节点的父节点,将父节点收集后,查第二就没有必要的,可以省去。

死循环:查子节点时不要再去查其父节点的子节点和父节点,有可能会死循环。

下面贴上了所有代码仅供参考。

查询菜单列表

public List<MenuTreeRespVO> getMenuTreeList(MenuListVO reqVO) {// 1、查询所有菜单List<MenuPO> all = menuMapper.selectList();// 2、查询满足条件的菜单List<MenuPO> menus = menuMapper.selectList(reqVO);Set<Long> menuIds = menus.stream().map(MenuPO::getId).collect(Collectors.toSet());Set<MenuPO> menuSet = findMenusWithParentsOrChildrenByIds(all, menuIds, true, true);// 3、形成树形结合return buildMenuTree(new ArrayList<>(menuSet), false);
}

查询菜单的父/子菜单

/*** 查找菜单的父/子菜单集合** @param all          所有菜单* @param menuIds      需要的菜单集合* @param withParent   是否包含父菜单* @param withChildren 是否包含子菜单* @return 结果*/
private Set<MenuPO> findMenusWithParentsOrChildrenByIds(List<MenuPO> all, Set<Long> menuIds, boolean withParent, boolean withChildren) {Map<Long, MenuPO> menuMap = new HashMap<>();for (MenuPO menu : all) {menuMap.put(menu.getId(), menu);}// 使用LinkedHashSet保持插入顺序Set<MenuPO> result = new LinkedHashSet<>();// 存储已处理过的菜单IDSet<Long> processedIds = new HashSet<>();for (Long menuId : menuIds) {if (withParent) {collectMenuParents(result, menuMap, menuId, processedIds);}if (withChildren) {collectMenuChildren(result, menuMap, menuId);}}return result;
}

递归查找当前菜单的所有父菜单

/*** 递归查找当前菜单的所有父菜单** @param resultSet    结果* @param menuMap      menuMap* @param menuId       需要的菜单id* @param processedIds 存储已处理过的菜单id*/
private void collectMenuParents(Set<MenuPO> resultSet, Map<Long, MenuPO> menuMap, Long menuId, Set<Long> processedIds) {if (processedIds.contains(menuId)) {return; // 如果已经处理过此菜单,则不再处理}processedIds.add(menuId);MenuPO menu = menuMap.get(menuId);if (menu != null) {resultSet.add(menu);// 如果当前菜单不是根节点(即parentId不为0),继续查找其父菜单if (!Objects.equals(menu.getParentId(), ID_ROOT) && !processedIds.contains(menu.getParentId())) {collectMenuParents(resultSet, menuMap, menu.getParentId(), processedIds);}}
}

递归查找当前菜单的所有子菜单

/*** 递归查找当前菜单的所有子菜单** @param resultSet 结果* @param menuMap   menuMap* @param menuId    需要的菜单id*/
private void collectMenuChildren(Set<MenuPO> resultSet, Map<Long, MenuPO> menuMap, Long menuId) {MenuPO menu = menuMap.get(menuId);if (menu != null) {resultSet.add(menu);// 添加当前菜单的所有子菜单for (MenuPO child : menuMap.values()) {if (child.getParentId().equals(menu.getId())) {collectMenuChildren(resultSet, menuMap, child.getId());}}}
}

构建菜单树

public List<MenuTreeRespVO> buildMenuTree(List<MenuPO> menuList, boolean removeButton) {if (removeButton) {// 移除按钮menuList.removeIf(menu -> menu.getType().equals(MenuType.BUTTON.getType()));}List<MenuTreeRespVO> convert = MenuConvert.INSTANCE.convert2TreeRespList(menuList);Map<Long, MenuTreeRespVO> menuTreeMap = new HashMap<>();for (MenuTreeRespVO menu : convert) {menuTreeMap.put(menu.getId(), menu);}menuTreeMap.values().stream().filter(menu -> !ID_ROOT.equals(menu.getParentId())).forEach(childMenu -> {MenuTreeRespVO parentMenu = menuTreeMap.get(childMenu.getParentId());if (parentMenu == null) {log.info("id:{} 找不到父菜单 parentId:{}", childMenu.getId(), childMenu.getParentId());return;}// 将自己添加到父节点中if (parentMenu.getChildren() == null) {parentMenu.setChildren(new ArrayList<>());}parentMenu.getChildren().add(childMenu);});return menuTreeMap.values().stream().filter(menu -> ID_ROOT.equals(menu.getParentId())).collect(Collectors.toList());
}

总结

基于以上后端查询树形菜单的代码就可以实现“筛选树形菜单时关联其父节点和子节点”了,效果还是可以的。

写在最后

拙作艰辛,字句心血,望诸君垂青,多予支持,不胜感激。


个人博客:无奈何杨(wnhyang)

个人语雀:wnhyang

共享语雀:在线知识共享

Github:wnhyang - Overview

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/585808.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何让光猫4个网口都有网络

一般情况光猫只有LAN1口有网络&#xff0c;LAN2、LAN3和LAN4口都是预留给电视用的&#xff0c;那么如何让这3个网口也有网络呢&#xff1f; 使用场景&#xff1a; 光猫在弱电箱内&#xff0c;弱电箱中有三根网线&#xff08;网线1、网线2和网线3&#xff09;分别接入到了三个房…

宝塔面板 -- 打包前端项目并部署提升访问速度

文章目录 前言一、打包前端项目二、添加PHP项目三、部署打包文件四、开通防火墙五、运行网站总结 前言 在前面写到的文章使用宝塔面板部署前端项目中&#xff0c;并没有将前端项目打包而是直接部署&#xff0c;导致网站访问速度非常慢&#xff0c;加载甚至要十几秒。因此&…

文献学习-25-综合学习和适应性教学:用于病理性胶质瘤分级的多模态知识蒸馏

Comprehensive learning and adaptive teaching: Distilling multi-modal knowledge for pathological glioma grading Authors: Xiaohan Xing , Meilu Zhu , Zhen Chen , Yixuan Yuan Source: Medical Image Analysis 91 (2024) 102990 Key words: 知识蒸馏、模态缺失、胶质瘤…

docker部署DOS游戏

下载镜像 docker pull registry.cn-beijing.aliyuncs.com/wuxingge123/dosgame-web-docker:latestdocker-compose部署 vim docker-compose.yml version: 3 services:dosgame:container_name: dosgameimage: registry.cn-beijing.aliyuncs.com/wuxingge123/dosgame-web-docke…

新增收货地址

目录 &#x1f9c2;1.创建controller层 &#x1f953;2.创建service层 &#x1f32d;3.注意细节 &#x1f37f;4.避免dao数据暴漏 1.创建controller层 controller不做逻辑操作&#xff0c;只接受前端的数据 1.添加Api设置swagger模块名称2.RestController以json形式返回…

Spring Boot项目启动速度优化

1、配置自动配置排除列表&#xff0c;减少启动自动配置扫描&#xff0c;配置项spring.autoconfigure.exclude 2、启动类添加索引注解Indexed&#xff0c;去除启动过程中 Components 的扫描步骤&#xff0c;直接从索引文件读取。 import org.springframework.stereotype.lndexe…

DXP学习3-单片机时钟显示系统的层次原理图设计

目录 一&#xff0c;自上而下的子母图设计 1&#xff0c;绘制层次式电路母图 1)工程及原理图创建和保存 2)开始绘制层次式母图main.SchDoc 2&#xff0c;绘制图纸符号 1&#xff09;properties选项卡 2&#xff09;designator标号 3&#xff09;filename文件名 4&…

双目测距项目 | 在Jetson-Nano平台上部署SGBM深度测距+YOLOv5目标检测算法

项目应用场景 面向在 Jetson Nano 平台上部署 SGBM 深度测距和基于 YOLOv5 的目标检测算法&#xff0c;实现双目测距的功能。 项目流程与效果&#xff1a; 项目细节 > 具体参见项目 README.md项目获取 https://download.csdn.net/download/weixin_42405819/89051043

直方图均衡化的本质

Rafael C. Gonzalez “Digital Image Processing”的错误 直方图均衡化的本质是灰度级分布的近邻映射&#xff0c;这部分的内容全错。总有些人崇洋媚外。 我修改了相关的内容&#xff0c;参阅禹晶、肖创柏、廖庆敏《数字图像处理&#xff08;面向新工科的电工电子信息基础课程…

android APP monkey 测试

monkey 测试 一、电脑ADB安装及使用详解1、什么是 Monkey 测试2、什么是ADB3、ADB的作用4、安装前提条件5、ADB下载6、ADB安装与配置 二、连接安卓手机检查是否连接上安卓手机windows端安装ADB驱动 三、 monkey测试操作指令演示指令APP包名查看方式测试效果 一、电脑ADB安装及使…

【WiFi开发全攻略】WIFI常用工具汇总

我的圈子&#xff1a; 高级工程师聚集地 我是董哥&#xff0c;高级嵌入式软件开发工程师&#xff0c;从事嵌入式Linux驱动开发和系统开发&#xff0c;曾就职于世界500强公司&#xff01; 创作理念&#xff1a;专注分享高质量嵌入式文章&#xff0c;让大家读有所得&#xff01; …

Python抓取京东、淘宝商品数据(属性详情,sku价格抓取)

抓取京东、淘宝等电商平台的商品数据&#xff08;包括属性详情、SKU价格等&#xff09;通常涉及到网络爬虫技术。这些平台都有自己的反爬虫机制&#xff0c;因此抓取数据需要谨慎操作&#xff0c;避免对平台造成不必要的负担或违反其使用条款。 公共参数 名称类型必须描述key…