三种常见的菜单路由封装方式详解
方式一:双重循环构建两级菜单
这种方式通过两层 for 循环分别处理父菜单和子菜单,实现相对直观简单。
private List<MenuRouterVO> getMenuRouterVOList(List<MenuEntity> menulist) {List<MenuRouterVO> menuRouterVOList = new ArrayList<>();// 遍历所有菜单,筛选顶级菜单(parentId=0)for (MenuEntity menu : menulist) {if (menu.getParentId() == 0) {MenuRouterVO menuRouterVO = new MenuRouterVO();BeanUtils.copyProperties(menu, menuRouterVO);// 设置meta信息MetaVo metaVo = new MetaVo();metaVo.setTitle(menu.getName());metaVo.setIcon(menu.getIcon());menuRouterVO.setMeta(metaVo);// 查找当前顶级菜单的子菜单List<ChildrenMenuRouterVO> children = new ArrayList<>();for (MenuEntity child : menulist) {if (child.getParentId() == menu.getMenuId()) {ChildrenMenuRouterVO childMenuRouterVO = new ChildrenMenuRouterVO();BeanUtils.copyProperties(child, childMenuRouterVO);MetaVo childMetaVo = new MetaVo();childMetaVo.setTitle(child.getName());childMetaVo.setIcon(child.getIcon());childMenuRouterVO.setMeta(childMetaVo);children.add(childMenuRouterVO);}}menuRouterVO.setChildren(children);menuRouterVOList.add(menuRouterVO);}}return menuRouterVOList;
}
特点分析:
- 实现简单直接,容易理解
- 仅支持两级菜单结构,不支持多级嵌套
- 时间复杂度为 O (n²),数据量大时效率较低
- 适合简单的两级菜单场景
方式二:递归构建多级菜单树
通过递归调用的方式,可以灵活构建任意层级的菜单结构。
@Override
public Map MenuList() {Map<String, Object> result = new HashMap<>();// 查询所有菜单项List<MenuEntity> AllMenuEntity = menuMapper.selectList(null);// 筛选顶级菜单(parentId=0)并构建菜单树List<MenuVO> TopMenu = new ArrayList<>();for (MenuEntity menuEntity : AllMenuEntity) {if (menuEntity.getParentId().equals(0)) {MenuVO menuVO = new MenuVO();BeanUtils.copyProperties(menuEntity,menuVO);menuVO.setId(menuEntity.getMenuId());// 递归构建当前顶级菜单的子菜单层级menuVO.setChildren(buildChildMenu(menuEntity.getMenuId(),AllMenuEntity));TopMenu.add(menuVO);}}result.put("data", TopMenu);return result;
}// 递归构建子菜单树
private List<ChildMenuVO> buildChildMenu(Integer parentId, List<MenuEntity> allMenuEntity) {List<ChildMenuVO> childMenuList = new ArrayList<>();// 查找当前父菜单ID对应的所有子菜单for (MenuEntity menuEntity : allMenuEntity) {if(menuEntity.getParentId().equals(parentId)){ChildMenuVO childMenuVO = new ChildMenuVO();BeanUtils.copyProperties(menuEntity,childMenuVO);childMenuVO.setId(menuEntity.getMenuId());// 递归获取子菜单的子菜单(多级菜单)List<ChildMenuVO> grandChildren = buildChildMenu(menuEntity.getMenuId(), allMenuEntity);childMenuVO.setChildren(grandChildren);childMenuList.add(childMenuVO);}}return childMenuList;
}
特点分析:
- 支持无限层级的菜单结构
- 代码逻辑清晰,易于维护
- 时间复杂度较高,每次递归都需要遍历整个菜单列表
- 适合需要多级嵌套的复杂菜单场景
方式三:HashMap 映射构建菜单树
利用 HashMap 的 O (1) 查找特性,先构建映射关系再组装菜单树,提高效率。
@Override
public List<MenuRouterVO> getMenuRoleByUser(Integer userId) {List<Menu> menuList = menuMapper.getMenuRouterByUserId(userId);// 定义所需对象MenuRouterVO menuRouterVO;ChildrenMenuRouterVO childrenMenuRouterVO;MetaVO metaVO;// 用Map存储菜单ID与菜单对象的映射关系Map<Integer, MenuRouterVO> menuMap = new HashMap<>();for (Menu menu : menuList) {// 处理父级菜单if(menu.getParentId()==0){menuRouterVO = new MenuRouterVO();menuRouterVO.setName(menu.getName());menuRouterVO.setPath(menu.getPath());menuRouterVO.setHidden(menu.getHidden());menuRouterVO.setRedirect("noRedirect");menuRouterVO.setComponent(menu.getComponent());menuRouterVO.setAlwaysShow("true");metaVO = new MetaVO();metaVO.setIcon(menu.getIcon());metaVO.setTitle(menu.getName());menuRouterVO.setMeta(metaVO);menuRouterVO.setChildren(new ArrayList<ChildrenMenuRouterVO>());menuMap.put(menu.getMenuId(), menuRouterVO);}// 处理子菜单else{childrenMenuRouterVO = new ChildrenMenuRouterVO();childrenMenuRouterVO.setName(menu.getName());childrenMenuRouterVO.setPath(menu.getPath());childrenMenuRouterVO.setHidden(menu.getHidden());childrenMenuRouterVO.setComponent(menu.getComponent());metaVO = new MetaVO();metaVO.setIcon(menu.getIcon());metaVO.setTitle(menu.getName());childrenMenuRouterVO.setMeta(metaVO);// 通过父ID直接从Map中获取父菜单并添加子菜单menuMap.get(menu.getParentId()).getChildren().add(childrenMenuRouterVO);}}return new ArrayList<>(menuMap.values());
}
特点分析:
- 时间复杂度为 O (n),效率最高
- 利用 HashMap 的快速查找特性,减少遍历次数
- 代码简洁,逻辑清晰
- 支持多级菜单,但需要确保菜单数据的完整性
- 适合数据量大、对性能要求高的场景
三种方式对比与选择建议
方式 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
双重循环 | 实现简单,易于理解 | 仅支持两级菜单,效率低 | 简单的两级菜单,数据量小 |
递归构建 | 支持无限层级,逻辑清晰 | 时间复杂度高,数据量大时性能差 | 多级菜单,数据量较小 |
HashMap 映射 | 效率高,支持多级菜单 | 需要额外的 Map 存储,依赖数据完整性 | 数据量大,多级菜单,对性能要求高 |
在实际开发中,应根据项目的菜单层级需求、数据量大小和性能要求选择合适的实现方式。
对于大多数后台管理系统,HashMap 映射方式是一个兼顾性能和灵活性的不错选择。