前言
首先这不是一个常规的单单生成菜单权限树,网上找遍了,也没有我这种需求。大多数都是在构建一颗权限树,按照id进行分级。然而,这次的需求,不是需要id树这么简单。
需求问题
本次需求是,构建权限菜单的完整路径,并非id组成,而是名称组成。
大概需要得到的效果如下:
说明:
- sys_permission 是一张菜单权限表,其他字段可以不管,有如图3个字段即可。
- permission_id 是某个菜单的主键id。
- parent_Id 是该菜单对应的上级权限id,即父级菜单的id。
- 上下级菜单,通过parent_Id 进行关联。
- 默认顶级权限是parent_Id = -1 。
我们需要,构建的是 各个父级路径+ 本级路径。如icon选择中所示。
由于,存储的时候,各级菜单都仅仅是按照一个parent_Id 进行上下级关联,因此,要构建上下级完整路径,就比较麻烦了。
实现方案
实现原理,采用java的递归算法思想。
//全局Map存放最终结果,也可以考虑redis替代
private Map<Long, String> permissionsPathMap= new HashMap<Long, String>();
/**
* 递归算法构建菜单权限完整路径
* 已验证,同一租户下,不会出现两个相同名称的顶级权限菜单。
* 这样之后key-value都是唯一的了
*
* @author zoutao
* @version v1.0
* @date 2021/11/25
* @param parentId 父级id
*/
private Map<Long, String> queryChildPermissionsPath(Long parentId){
LambdaQueryWrapper<SysPermission> wrapper = new LambdaQueryWrapper<SysPermission>()
.select(SysPermission::getPermissionId, SysPermission::getPermissionName,SysPermission::getParentId)
.eq(SysPermission::getParentId,parentId)
.orderByAsc(SysPermission::getParentId);
List<SysPermission> treeList = sysPermissionMapper.selectList(wrapper);
//如果没有查询到数据,证明是最后一级菜单,有数据则表示拥有子节点
if (CollectionUtils.isNotEmpty(treeList)) {
for (SysPermission entity : treeList) {
// 放入顶级菜单
if (ROOT_ID == entity.getParentId()){
permissionsPathMap.put(entity.getPermissionId(),entity.getPermissionName());
}
}
System.out.println("顶级菜单:"+permissionsPathMap);
for (SysPermission entity : treeList) {
String parentName = permissionsPathMap.get(entity.getParentId());
String fullpath = "";
if (StringUtils.isBlank(parentName)) {
fullpath = entity.getPermissionName();
}else {
fullpath = parentName+"/"+entity.getPermissionName();
}
// 26-用户中心/部门管理
permissionsPathMap.put(entity.getPermissionId(),fullpath);
queryChildPermissionsPath(entity.getPermissionId());
}
}
System.out.println("递归后的map"+permissionsPathMap);
return permissionsPathMap;
}
在Impl或者其他地方,发起调用,先构建顶级 ROOT_ID = -1 :
Map<Long, String> permissionsPathMap = queryChildPermissionsPath(ROOT_ID);
当你的全局Map没有人用了,系统才会回收,假如map还有人用,里面的对象如果不清除,都会被map持有,永远得不到回收,所以在map中数据不需要时,记得及时clear。
if (MapUtils.isNotEmpty(permissionsPathMap)) {
permissionsPathMap.clear();
}
放在合适的地方即可。
控制台输出:
递归后的map{