关键词:
文章目录
谷粒学院项目权限管理模块
1.数据库表
这里系统权限控制采用的访问控制模型是 RBAC 模型
RBAC模型:
RBAC 即基于角色的权限访问控制(Role-Based Access Control)。这是一种通过角色关联权限,角色同时又关联用户的授权的方式。
简单地说:一个用户可以拥有若干角色,每一个角色又可以被分配若干权限,这样就构造成“用户-角色-权限” 的授权模型。在这种模型中,用户与角色、角色与权限之间构成了多对多的关系,如下图:
在 RBAC 中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。
-
菜单表
acl_permission
-
角色表
acl_role
-
用户表
acl_user
-
角色—菜单表
acl_role_permission
-
用户—角色表
acl_user_role
几个表之间的关系:
2.菜单相关操作
2.1 递归查询全部菜单
controller
:
/**
* 递归获取全部菜单 √
* @return R
*/
@GetMapping
public R indexAllPermission()
List<Permission> list = permissionService.queryAllMenuGuli();
return R.ok().data("children",list);
service
:
/**
* 递归查询所有菜单
*
* @return
*/
@Override
public List<Permission> queryAllMenuGuli()
//1.查询菜单表所有数据
LambdaQueryWrapper<Permission> queryWrapper = new LambdaQueryWrapper<>();
//按id从大到小排序
queryWrapper.orderByDesc(Permission::getId);
List<Permission> permissionList = baseMapper.selectList(queryWrapper);
//2.把查询所有的菜单按照要求封装
List<Permission> resultList = bulidPermission(permissionList);
return resultList;
把返回所有菜单list集合进行封装,具体分为这几步:
- 创建list集合,用于数据最终封装
- 把所有菜单list集合遍历,得到顶层菜单
pid=0
菜单,设置level=1
- 根据顶层菜单,向里面进行查询子菜单,封装到最终返回结果
finalNode
里面
/**
* 把返回所有菜单list集合进行封装的方法
*
* @param permissionList
* @return
*/
public static List<Permission> bulidPermission(List<Permission> permissionList)
//1.创建list集合,用于数据最终封装
List<Permission> finalNode = new ArrayList<>();
//2.把所有菜单list集合遍历,得到顶层菜单 pid=0菜单,设置level是1
for (Permission permission : permissionList)
//得到顶层菜单 pid=0菜单
if ("0".equals(permission.getPid()))
//设置顶层菜单的level是1
permission.setLevel(1);
//3.根据顶层菜单,向里面进行查询子菜单,封装到finalNode里面
finalNode.add(selectChildren(permission, permissionList));
return finalNode;
递归查找当前菜单的所有子菜单,具体分这几步:
- 因为向一层菜单里面放二层菜单,二层里面还要放三层,所以先把把子菜单集合初始化
- 遍历所有菜单list集合,进行判断比较,比较当前菜单pid和传过来的父菜单id值是否相同,相同就是该父菜单的子菜单
- 设置当前菜单level为父菜单level+1
- 设置子菜单,子菜单依然需要递归查询子菜单是否也有子菜单
/**
* 递归查找当前菜单的所有子菜单
*
* @param permissionNode 需要查找子菜单的当前菜单
* @param permissionList 所有菜单的集合
* @return
*/
private static Permission selectChildren(Permission permissionNode, List<Permission> permissionList)
//因为向一层菜单里面放二层菜单,二层里面还要放三层,把对象初始化
permissionNode.setChildren(new ArrayList<Permission>());
//遍历所有菜单list集合,进行判断比较,比较id和pid值是否相同,是不是当前菜单的子菜单
for (Permission permission : permissionList)
//当前菜单的pid=上级菜单id
if (permission.getPid().equals(permissionNode.getId()))
int level = permissionNode.getLevel() + 1;
//设置当前菜单level为父菜单level+1
permission.setLevel(level);
//设置子菜单,子菜单依然需要递归查询子菜单是否也有子菜单
permissionNode.getChildren().add(selectChildren(permission, permissionList));
return permissionNode;
2.2 递归删除菜单
controller
:
/**
* 递归删除菜单 √
* @param id
* @return
*/
@DeleteMapping("remove/id")
public R remove(@PathVariable String id)
permissionService.removeChildByIdGuli(id);
return R.ok();
service
:
/**
* 递归删除菜单
*
* @param id 菜单id
*/
@Override
public void removeChildByIdGuli(String id)
//1.创建list集合,用于封装所有删除菜单id值
List<String> idList = new ArrayList<>();
//2.加入所有子菜单的id
this.selectPermissionChildById(id, idList);
//3.加入自己的id
idList.add(id);
//4.批量根据id删除菜单
baseMapper.deleteBatchIds(idList);
根据当前菜单id,查询其所有的子菜单的id并放入idList,分为这几步:
- 根据id查询下一层子菜单
- 循环变量子菜单list,将id放入idList
- 递归求子id的子id,也放入idList,以此类推
/**
* 根据当前菜单id,查询菜单里面子菜单id,封装到list集合
*
* @param id 当前菜单id
* @param idList 最终封装要删除的id集合
*/
private void selectPermissionChildById(String id, List<String> idList)
LambdaQueryWrapper<Permission> queryWrapper = new LambdaQueryWrapper<>();
//1.查询菜单里面子菜单id
queryWrapper.eq(Permission::getPid, id);
//2.只需要id
queryWrapper.select(Permission::getId);
List<Permission> childIdList = baseMapper.selectList(queryWrapper);
//3.遍历子id集合,加入idList,然后递归遍历子菜单的子菜单
childIdList.stream().forEach(item ->
idList.add(item.getId());
selectPermissionChildById(item.getId(), idList);
);
2.3 给角色分配权限
controller
:
根据角色id和菜单id集合,一个角色分配多个菜单(权限):
/**
* 给角色分配权限 √
* @param roleId 角色id
* @param permissionId 分配的菜单id集合
* @return
*/
@PostMapping("/doAssign")
public R doAssign(String roleId,String[] permissionId)
permissionService.saveRolePermissionRealtionShipGuli(roleId,permissionId);
return R.ok();
service
:
/**
* 角色分配菜单
*
* @param roleId 角色id
* @param permissionIds 菜单id集合
*/
@Override
public void saveRolePermissionRealtionShipGuli(String roleId, String[] permissionIds)
//1.创建list集合,用于封装添加数据
List<RolePermission> permissionList = new ArrayList<>();
for (String permissionId : permissionIds)
if (StringUtils.isEmpty(permissionId)) continue;
RolePermission rolePermission = new RolePermission();
rolePermission.setPermissionId(permissionId);
rolePermission.setRoleId(roleId);
permissionList.add(rolePermission);
//2.批量保存到acl_role_permission表
rolePermissionService.saveBatch(permissionList);
2.4 根据角色获取菜单
controller
:
根据角色id获取对应的拥有的菜单集合:
/**
* 根据角色获取菜单
* @param roleId
* @return
*/
@GetMapping("toAssign/roleId")
public R toAssign(@PathVariable String roleId)
List<Permission> list = permissionService.selectAllMenu(roleId);
return R.ok().data("children", list);
service
:
根据角色id获取菜单集合,具体分为这几步:
- 查询所有Perssion,并按id排序得到permissionList
- 根据roleId查询在acl_role_permission表里查询所有RolePerssion得到rolePermissionList
- 用stream将rolePermissionList所有对应的permissionId提取出来得到permissionIdList
- 遍历permissionList,如果对象的id是目标集合permissionIdList里的id,则设置select为true
- 把所有的菜单list集合permissionList进行树状封装,递归封装,最终返回
/**
* 根据角色获取菜单
*
* @param roleId 角色id
* @return
*/
@Override
public List<Permission> selectAllMenu(String roleId)
//1.查询所有Perssion,并按id排序
List<Permission> permissionList = baseMapper.selectList(new LambdaQueryWrapper<Permission>().orderByDesc(Permission::getId));
//2.根据roleId查询在acl_role_permission表里查询所有RolePerssion
List<RolePermission> rolePermissionList = rolePermissionService.list(new LambdaQueryWrapper<RolePermission>().eq(RolePermission::getRoleId, roleId));
//3.用stream将rolePermissionList所有对应的permissionId提取出来
List<String> permissionIdList = rolePermissionList.stream().map(e -> e.getPermissionId()).collect(Collectors.toList());
//4.遍历permissionList,如果对象的id是目标集合permissionIdList里的id,则设置select为true
permissionList.forEach(permission->
if(permissionIdList.contains(permission.getId()))
permission.setSelect(true);
else
permission.setSelect(false);
);
//5.把所有的菜单list集合进行树状封装,递归封装
List<Permission> resPermission = bulidPermission(permissionList);
return resPermission;
2.5 添加菜单
controller
:
直接调用mybatis-plus提供的方法:
/**
* 新增菜单 √
* @param permission
* @return
*/
@PostMapping("save")
public R save(@RequestBody Permission permission)
permissionService.save(permission);
return R.ok();
2.6 修改菜单
controller
:
根据菜单id修改菜单,直接调用mybatis-plus提供的方法:
/**
* 修改菜单 √
* @param permission
* @return
*/
@PutMapping("update")
public R updateById(@RequestBody Permission permission)
//直接根据id修改
permissionService.updateById(permission);
return R.ok();
3.角色相关操作
3.1 获取角色分页列表
/**
* 获取角色分页列表
* @param page 当前页
* @param limit 每页数量
* @param role 查询的角色,根据名字模糊查询
* @return
*/
@GetMapping("page/limit")
public R index(@PathVariable Long page, @PathVariable Long limit, Role role)
//构造page对象
Page<Role> pageParam=new Page<>(page,limit);
//构造查询,如果有名字查询则进行like模糊查询
LambdaQueryWrapper<Role> queryWrapper=new LambdaQueryWrapper<>();
if(StringUtils.isNotBlank(role.getRoleName()))
queryWrapper.like(Role::getRoleName,role.getRoleName());
//进行带条件的分页查询
roleService.page(pageParam,queryWrapper);
//返回最终的数据集合和总条数
return R.ok().data("items",pageParam.getRecords()).data("total",pageParam.getTotal());
3.2 其他操作
根据id获取角色:
/**
* 根据id获取角色
*
* @param id 角色id
* @return
*/
@GetMapping("get/id")
public R get(@PathVariable String id)
Role role = roleService.getById(id);
return R.ok().data("item", role);
新增角色:
/**
* 保存角色
*
* @param role 角色对象
* @return
*/
@PostMapping("save")
public R save(@RequestBody Role role)
roleService.save(role);
return R.ok();
根据id修改角色:
/**
* 根据id修改角色
*
* @param role
* @return
*/
@PutMapping("update")
public R updateById(@RequestBody Role role)
roleService.updateById(role);
return R.ok();
根据id删除角色:
/**
* 根据id删除角色
*
* @param id
* @return
*/
@DeleteMapping("remove/id")
public R remove(@PathVariable String id)
roleService.removeById(id);
return R.ok();
批量删除角色:
/**
* 批量删除角色
*
* @param idList 要删除角色的id集合
* @return
*/
@DeleteMapping("batchRemove")
public R batchRemove(@RequestBody List<String> idList)
roleService.removeByIds(idList);
return R.ok();
4.用户相关操作
4.1 获取管理用户分页列表
/**
* 获取管理用户分页列表
*
* @param page 当前页
* @param limit 每页数量
* @param userQueryVo 查询条件,根据用户名字模糊查询
* @return
*/
@GetMapping("page/limit")
public R index(@PathVariable Long page, @PathVariable Long limit, User userQueryVo)
//构造page对象
Page<User> pageParam = new Page<>(page, limit);
构造查询,如果有名字查询则进行like模糊查询
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
if (StringUtils.isNotBlank(userQueryVo.getUsername()))
queryWrapper.like(User::getUsername, userQueryVo.getUsername());
//进行带条件的分页查询
userService.page(pageParam, queryWrapper);
//返回最终的数据集合和总条数
return R.ok().data("items", pageParam.getRecords()).data("total", pageParam.getTotal());
4.2 根据用户获取角色数据
controller
:
/**
* 根据用户获取角色数据
* @param userId 用户id
* @return
*/
@GetMapping("/toAssign/userId")
public R toAssign(@PathVariable String userId)
Map<String, Object> roleMap = roleService.findRoleByUserId(userId);
return R.ok().data(roleMap);
service
:
/**
* 根据用户获取角色数据
*
* @param userId
* @return
*/
@Override
public Map<String, Object> findRoleByUserId(String userId)
//1.查询所有的角色
List<Role> roleList = baseMapper.selectList(null);
//2.根据用户id查询对应UserRole对象
List<UserRole> userRoleList = userRoleService.list(new LambdaQueryWrapper<查看详情
谷粒学院项目总结(代码片段)
文章目录谷粒学院项目总结1.项目介绍1.1采用的商业模式1.2功能模块1.3采用技术2.Mybatis-Plus相关配置2.1配置分页插件2.2自动填充2.3代码生成器3.Swagger配置4.统一返回数据格式4.1统一结果返回类4.2统一定义返回码5.统一异常处理5.1创... 查看详情
谷粒学院第四天(代码片段)
一、axios1、介绍2、使用<!DOCTYPEhtml><htmllang="en"><head><title>axios使用</title><scriptsrc="vue.min.js"></script><scriptsrc="axios. 查看详情
谷粒商城--品牌管理详情(代码片段)
目录1.简单上传测试2.AliyunSpringBootOSS3.模块mall-third-service 4.前端5.数据校验6.JSR303数据校验7.分组校验功能8.自定义校验功能9.完善代码1.简单上传测试OSS是对象存储服务,有什么用呢?把图片存储到云服务器上能让所有人都... 查看详情
day201.项目起步mybatisplus谷粒学院(代码片段)
谷粒学院一、起步0、前置知识1、项目背景在线教育顾名思义,是以网络为介质的教学方式,通过网络,学员与教师即使相隔万里也可以开展教学活动;此外,借助网络课件,学员还可以随时随地进行学习&... 查看详情
谷粒学院——day09整合阿里云视频点播(代码片段)
❤作者主页:Java技术一点通的博客❀个人介绍:大家好,我是Java技术一点通!( ̄▽ ̄)~*🍊记得关注、点赞、收藏、评论⭐️⭐️⭐️📣认真学习,共同进步!!!🎉🎉视... 查看详情
计算机毕业设计springboot+vue+elementui独立学院资产管理系统(代码片段)
项目介绍独立学院资产管理系统主要设计的用户范围是:注册用户、管理员。每一个角色在系统中即可看作是不同的子系统,其所拥有的功能权限是不一致的。系统架构包括后台数据库的建立和维护以及应用程序。系统... 查看详情
nuxtcannotresolve“swiper/dist/css/swiper.css“(写谷粒学院碰到)(代码片段)
报错内容这个错就是没找到这个文件,原因如下官方说6.x版本里是没有dist这个文件夹的,所以引入要用swiper/swiper-bundle.css(后面会说在哪里引入),你可以自己找下自己用npminstall命令在node_modules文件夹里下载... 查看详情
谷粒商城简介(代码片段)
...现,采用前后端分离继续编写。项目介绍gulimall(谷粒商城)项目是一套电商项目,包括前台商城系统以及后台管理系统,基于SpringCloud+SpringCloudAlibaba+MyBatis-Plus实现,采用Docker容器化部署。前台商城... 查看详情
6.添加权限管理模块(代码片段)
本文主要是以权限管理模块为例来介绍使用springboot+mybatis完成增删改查的功能。1.添加Permission实体类1packagecom.lvniao.blog.model;23importjava.util.ArrayList;4importjava.util.List;56publicclassPermission78privateLongid;910privateString 查看详情
nacos源码之auth(权限)模块-2(权限管理与权限配置)(代码片段)
上一篇:《nacos源码之Auth(权限)模块-1(授权过滤器与控制器缓存)》Nacos权限模块2Nacos权限模块权限管理权限管理的实现数据库操作的实现分布式数据处理的一致性算法JRaft分布式数据处理的读写锁权限配置Nacos源码读后感... 查看详情
第184天学习打卡(项目谷粒商城26统一异常管理jsr303分组校验)(代码片段)
API品牌管理-统一异常管理gulimall-productcontrollerBrandController.javapackagecom.doudou.gulimall.product.controller;importjava.util.Arrays;importjava.util.HashMap;importjava.util.Map;//importorg.apache.shiro.au 查看详情
django权限系统auth模块详解(代码片段)
auth模块是Django提供的标准权限管理系统,可以提供用户身份认证,用户组和权限管理。auth可以和admin模块配合使用,快速建立网站的管理系统。在INSTALLED_APPS中添加‘django.contrib.auth‘使用该APP,auth模块默认启用。UserUser是auth模块中... 查看详情
bootdo后台管理系统(代码片段)
...一个Java基础开发平台,MyBatis为数据访问层,ApacheShiro为权限授权层,Ehcahe对常用数据进行缓存。BootDo目前包括以下四大模块,系统管理(SYS)模块、内容管理(CMS)模块、在线办公(OA)模块、代码生成(GEN)模块。系统管理模... 查看详情
谷粒商城-前端开发基础知识(代码片段)
目录1.ES61.1.简介1.2.let声明变量 1.4.解构表达式1.5.字符串扩展1.6.函数优化1.7.对象优化1.8.map和reduce1.9.Promise1.9.模块化 2.Vue2.1.MVVM思想2.2.Vue简介2.3.入门案例 2..4.概念2.5.指令2.6.计算属性和侦听器2.7.组件化2.8.声明周期和钩子函数2.9... 查看详情
谷粒商城-前端开发基础知识(代码片段)
目录1.ES61.1.简介1.2.let声明变量 1.4.解构表达式1.5.字符串扩展1.6.函数优化1.7.对象优化1.8.map和reduce1.9.Promise1.9.模块化 2.Vue2.1.MVVM思想2.2.Vue简介2.3.入门案例 2..4.概念2.5.指令2.6.计算属性和侦听器2.7.组件化2.8.声明周期和钩子函数2.9... 查看详情
学生管理系统-明日学院的(代码片段)
importre#导入正则表达式模块importos#导入操作系统模块filename="students.txt"#定义保存学生信息的文件名defmenu():#输出菜单print(‘‘‘╔———————学生信息管理系统————————... 查看详情
谷粒商城简介(代码片段)
...现,采用前后端分离继续编写。项目介绍gulimall(谷粒商城)项目是一套电商项目,包括前台商城系统以及后台管理系统,基于SpringCloud+SpringCloudAlibaba+MyBatis-Plus实现& 查看详情