php成品网站下载,公司的seo是什么意思,网页类界面图片,可以做婚礼视频的网站个人博客#xff1a;无奈何杨#xff08;wnhyang#xff09;
个人语雀#xff1a;wnhyang
共享语雀#xff1a;在线知识共享
Github#xff1a;wnhyang - Overview 背景
之前一直讲过自己独立在做一个中后台管理系统#xff0c;当然这个只是开始#xff0c;未来会基…个人博客无奈何杨wnhyang
个人语雀wnhyang
共享语雀在线知识共享
Githubwnhyang - Overview 背景
之前一直讲过自己独立在做一个中后台管理系统当然这个只是开始未来会基于此开发其他项目因为时间的原因这项目算是搁置了一段时间最近又重新拾取来完善。
项目链接如下
GitHub - wnhyang/okay-boot
GitHub - wnhyang/okay-vben-admin
其前端采用vben中后台开发框架后端就是常用的Spirng Boot那一套用户角色菜单设计也是最常用RABC的方案。
问题
如下是菜单管理查询到的菜单列表展示为树形结构。 在给角色分配菜单权限时使用的是一个TreeSelect的组件该组件提供了可多选的树形结构菜单当然这个组件本身就有很多配置项可以自定义很多内容。 选中如上菜单时收集的数据是如上“用户更新”、“角色新增”、“角色更新”、“角色删除”、“角色查询”这些菜单对应的id。然后通过类似于下面的方法新增或修改角色。
Transactional(rollbackFor Exception.class)
public Long createRole(RoleCreateVO reqVO) {validateRoleForCreateOrUpdate(null, reqVO.getName(), reqVO.getValue());RolePO role RoleConvert.INSTANCE.convert(reqVO);roleMapper.insert(role);if (CollectionUtil.isNotEmpty(reqVO.getMenuIds())) {roleMenuMapper.insertBatch(CollectionUtils.convertList(reqVO.getMenuIds(),menuId - new RoleMenuPO().setRoleId(role.getId()).setMenuId(menuId)));}return role.getId();
}Transactional(rollbackFor Exception.class)
public void updateRole(RoleUpdateVO reqVO) {// 校验是否可以更新validateRoleForUpdate(reqVO.getId());// 校验角色的唯一字段是否重复validateRoleForCreateOrUpdate(reqVO.getId(), reqVO.getName(), reqVO.getValue());// 更新到数据库RolePO role RoleConvert.INSTANCE.convert(reqVO);roleMenuMapper.deleteByRoleId(role.getId());if (CollectionUtil.isNotEmpty(reqVO.getMenuIds())) {roleMenuMapper.insertBatch(CollectionUtils.convertList(reqVO.getMenuIds(),menuId - new RoleMenuPO().setRoleId(role.getId()).setMenuId(menuId)));}roleMapper.updateById(role);
}这样本身是没有问题数据的修改和回显都是可以的。
问题是用户关联角色角色关联菜单如果角色关联的菜单不是顶级菜单前端动态渲染菜单时就会有问题。如用户A有“用户查询”权限应该能正确显示系统管理/用户管理页面只是只有查询权限但是如果按上面的树形菜单收集数据并通过新增和修改角色的关联菜单后角色关联表里只有选中的角色id和菜单id的数据没有指定菜单父菜单的关联关系所以这里要处理一下不然会有问题。
方案
1、利用前端Tree组件相关方法选中子节点时带上其父节点这个角色就能关联上虽有需要的菜单节点了。唯一要注意的是数据回显因为Tree组件通常是粘性的选中父节点的同时会选中其所有子节点所以回显时要注意些要么数据查回时去除一些父节点再渲染要么利用组件的其他方法。
2、前面所有方案不变数据存储还是只是选中菜单节点和角色的关联只是在用户第一次登录需要根据权限渲染菜单时把菜单节点处理一下也就是把所有菜单查到根结点后返回。
查菜单时带上父菜单直到根结点
以下仅供参考
public ListUserInfoVO.MenuVO getLoginUserMenuTreeList(boolean removeButton) {Login loginUser LoginUtil.getLoginUser();if (loginUser null) {throw exception(UNAUTHORIZED);}Long id loginUser.getId();ListMenuPO all menuMapper.selectList();if (LoginUtil.isAdministrator(id)) {return buildUserMenuTree(all, removeButton);}SetLong menuIds convertSet(roleMenuMapper.selectListByRoleId(loginUser.getRoleIds()), RoleMenuPO::getMenuId);SetMenuPO menuSet findMenusWithParentsOrChildrenByIds(all, menuIds, true, false);return buildUserMenuTree(new ArrayList(menuSet), removeButton);
}查询菜单的父/子菜单
/*** 查找菜单的父/子菜单集合** param all 所有菜单* param menuIds 需要的菜单集合* param withParent 是否包含父菜单* param withChildren 是否包含子菜单* return 结果*/
private SetMenuPO findMenusWithParentsOrChildrenByIds(ListMenuPO all, SetLong menuIds, boolean withParent, boolean withChildren) {MapLong, MenuPO menuMap new HashMap();for (MenuPO menu : all) {menuMap.put(menu.getId(), menu);}// 使用LinkedHashSet保持插入顺序SetMenuPO result new LinkedHashSet();// 存储已处理过的菜单IDSetLong 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(SetMenuPO resultSet, MapLong, MenuPO menuMap, Long menuId, SetLong 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(SetMenuPO resultSet, MapLong, 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 ListMenuTreeRespVO buildMenuTree(ListMenuPO menuList, boolean removeButton) {if (removeButton) {// 移除按钮menuList.removeIf(menu - menu.getType().equals(MenuType.BUTTON.getType()));}ListMenuTreeRespVO convert MenuConvert.INSTANCE.convert2TreeRespList(menuList);MapLong, 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
共享语雀在线知识共享
Githubwnhyang - Overview