# AuthorityManagement **Repository Path**: sunchang0101/AuthorityManagement ## Basic Information - **Project Name**: AuthorityManagement - **Description**: SpringBoot + Vue2 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-08-02 - **Last Updated**: 2024-03-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: SpringBoot, vue2, mybatis-plus ## README # 0.博客 [CSDN](https://blog.csdn.net/qq_43336396/article/details/132133822?spm=1001.2014.3001.5502) # 1.文件(夹)说明 前后端分离 # 2.参考 [视频](https://www.bilibili.com/video/BV1ad4y1y7LU/?spm_id_from=333.999.0.0) [资源](https://pan.baidu.com/s/1faiMIENEgBDPTM661BUXLQ?pwd=yyds) # 3.技术栈 |技术|功能| |--|--| |SSM|Java EE框架| |Spring Boot|Java EE框架| |MyBatis-Plus|ORM框架| |MySQL|数据库| |Redis|数据缓存| |Swagger|RESTful风格的API工具| |Vue2|JS框架| |HTML|页面| |Element-UI|样式| |Axios|网络异步| |vue-element-admin|Vue框架| # 4.项目简介 |/|0/1 | |--|--| |前后端分离|1| |模块化开发|0| |技术侧重|全栈| ||| # 5.业务实现 ### 1)角色管理:CUDR ### 2)用户管理:CUDR ### 3)菜单管理:CUDR ### 4)权限管理 (1)用户是否被禁用 (2)用户分配角色 (3)角色分配权限 # 6.业务分析 ## 6.0 跨域 ### 1)什么是跨域:前端后端项目访问接口地址不一致 ### 2)如何解决跨域: 前端:代理服务器 后端:CORS、JSONP ### 3)跨域被解决的示例 ![输入图片说明](imgs/%E5%9B%BE%E7%89%87.png) ## 6.1 登陆 ### 6.1.1 效验 #### 前端: 1)事件绑定:login/index.vue ![输入图片说明](imgs/%E5%9B%BE%E7%89%872.png) 2)vuex判断:store/modules/user.js ![输入图片说明](imgs/%E5%9B%BE%E7%89%873.png) 3)接口请求:api/user.js ![输入图片说明](imgs/%E5%9B%BE%E7%89%875.png) 4)Axios二次封装:util/request.js _ 总:vuex取(缓存)信息(token)判断,再用Axios向后端发送请求_ #### 后端: ##### 1)Controller: 0)地址映射 ![输入图片说明](imgs/%E5%9B%BE%E7%89%876.png) _【注】 请求方法与请求路径相对应; 前端:传参并(修改)呈现 后端:接收参数并返回_ 1)效验
2)状态判断
3)生成并存储token
```java @PostMapping("login") public Result login(@RequestBody LoginVo loginVo) { // 1.判断用户是否存在 SysUser sysUser = sysUserService.getUserInfoByUserName(loginVo.getUsername()); if(sysUser == null) { throw new GuiguException(20001,"用户名错误"); } // 2.判断密码是否正确 String password = loginVo.getPassword(); // 加密 String md5Password = MD5.encrypt(password); if(!sysUser.getPassword().equals(md5Password)) { throw new GuiguException(20001,"密码不正确"); } // 3.判断用户是否被禁用 if(sysUser.getStatus().intValue()==0) { throw new GuiguException(20001,"用户已经被禁用"); } // 4.生成token 根据userid和username生成token字符串,通过map返回 String token = JwtHelper.createToken(sysUser.getId(), sysUser.getUsername()); Map map = new HashMap<>(); map.put("token",token); return Result.ok(map); } ``` ##### 2)Impl: ```java // 更改用户状态 @Override public void updateStatus(String id, Integer status) { // 根据用户id查询 SysUser sysUser = baseMapper.selectById(id); // 更新用户状态 sysUser.setStatus(status); // 调用方法修改 baseMapper.updateById(sysUser); } // username查询 @Override public SysUser getUserInfoByUserName(String username) { // SELECT * FROM sys_user WHERE username = 'username'; QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("username",username); return baseMapper.selectOne(wrapper); } ``` _**【注】如下功能点不再考虑地址映射并弱化前端描述**_ ## 6.2 登陆后页面呈现 ** 【思路】 0)前端请求传值
1)获取token
2)根据token获取身份
3)根据身份获取权限
4)构建树形结构
** ### 6.2.1 Controller ```java @GetMapping("info") public Result info(HttpServletRequest request) { // 1.获取请求头token字符串 String token = request.getHeader("token"); // 2.从token字符串获取用户名称(id) String username = JwtHelper.getUsername(token); // 3.根据用户名称获取用户信息(基本信息 和 菜单权限 和 按钮权限数据) Map map = sysUserService.getUserInfo(username); return Result.ok(map); } ``` ### 6.2.2 Impl **_User:_** ```java // 根据用户名称获取用户信息(基本信息 和 菜单权限 和 按钮权限数据) @Override public Map getUserInfo(String username) { // 根据username查询用户基本信息 SysUser sysUser = this.getUserInfoByUserName(username); // 根据userid查询菜单权限值 List routerVolist = sysMenuService.getUserMenuList(sysUser.getId()); // 根据userid查询按钮权限值 List permsList = sysMenuService.getUserButtonList(sysUser.getId()); Map result = new HashMap<>(); result.put("name",username); result.put("avatar","https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif"); result.put("roles","[\"admin\"]"); // 菜单权限数据 result.put("routers",routerVolist); // 按钮权限数据 result.put("buttons",permsList); return result; } ``` **_Menu:_** ```java // 根据userid查询菜单权限值 @Override public List getUserMenuList(String userId) { // admin 1 超级管理员 查询所有权限数据 // !admin !1 !超级管理员 查询相关用户权限 List sysMenuList = null; // 1.判断用户身份 if("1".equals(userId)) { QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("status",1); wrapper.orderByAsc("sort_value"); sysMenuList = baseMapper.selectList(wrapper); } else { // 如果userid不是1,其他类型用户,查询这个用户权限 sysMenuList = baseMapper.findMenuListUserId(userId); } // 2.构建树形结构 List sysMenuTreeList = MenuHelper.bulidTree(sysMenuList); // 3.构建路由结构 List routerVoList = RouterHelper.buildRouters(sysMenuTreeList); return routerVoList; } //根据userid查询按钮权限值 @Override public List getUserButtonList(String userId) { List sysMenuList = null; //判断是否管理员 if("1".equals(userId)) { sysMenuList = baseMapper.selectList(new QueryWrapper().eq("status",1)); } else { sysMenuList = baseMapper.findMenuListUserId(userId); } //sysMenuList遍历 List permissionList = new ArrayList<>(); for (SysMenu sysMenu:sysMenuList) { // type=2 if(sysMenu.getType()==2) { String perms = sysMenu.getPerms(); permissionList.add(perms); } } return permissionList; } ``` ## 6.3 分页 ### 6.3.1 思路 ![输入图片说明](%E5%9B%BE%E7%89%877.png) ### 6.3.2 前端 ```vue 搜索 重置 // 分页 // 控制:每页展示数据 handleSizeChange(limit) { // 每页大小变化的逻辑 this.page = 1; // 重置页码为1 this.limit = limit; this.fetchData(this.page); // 根据新的每页大小重新获取数据 }, // 控制:跳转页 handlePageChange(page) { // 页码变化的逻辑 this.page = page; this.fetchData(this.page); // 获取指定页码的数据 }, // 分页查询 fetchData(page = 1) { this.page = page; // 日期筛选 if (this.createTimes && this.createTimes.length == 2) { this.searchObj.createTimeBegin = this.createTimes[0]; this.searchObj.createTimeEnd = this.createTimes[1]; } api.getPageList(this.page, this.limit, this.searchObj) .then((response) => { this.list = response.data.records; this.total = response.data.total; // this.list.forEach((item) => { // item.updateTime = this.searchObj.updateTime; // }); }); // console.log(this.searchObj); // console.log(this.searchObj.updateTime); // this.searchObj.updateTime = new Date().toLocaleString(); }, ``` ### 6.3.3 后端 **_Controller:_** ```java // page: 当前页码 // limit: 每页记录数 @ApiOperation("用户列表") @GetMapping("/{page}/{limit}") public Result list(@PathVariable Long page, @PathVariable Long limit, SysUserQueryVo sysUserQueryVo) { // 创建page对象 Page pageParam = new Page<>(page,limit); // 调用service方法 IPage pageModel = sysUserService.selectPage(pageParam,sysUserQueryVo); return Result.ok(pageModel); } ``` **_Impl:_** ```java @Override public IPage selectPage(Page pageParam, SysUserQueryVo sysUserQueryVo) { return baseMapper.selectPage(pageParam,sysUserQueryVo); } ``` **_【注】使用MP的Page和Ipage对象接收并处理分页_** ## 6.4 批量删除 ### 6.4.1 思路 ![输入图片说明](imgs/%E5%9B%BE%E7%89%878.png) ### 6.4.2 前端 ```vue
添 加 批量删除
// 事件 batchRemove() { // 批量删除 // 1.判断:选框是否选中数据 if(this.selectValue.length==0) { this.$message.warning('请选择要删除的记录!') return } // 2.提示 this.$confirm('此操作将永久删除该角色, 是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { // 3.取值:获取(handleSelectionChange)复选框变化的值 // 定义数组 // 获取多个复选框对应id,封装到数组里面:[1,2,3] var idList = [] for(var i=0;i { // 5.提示 this.$message({ type: 'success', message: '删除成功!' }); // 6.刷新 this.fetchData() }) }) }, ``` ### 6.4.3 后端 ```java // 多个id值 [1,2,3] // json数组格式 --- java的list集合 @PreAuthorize("hasAuthority('bnt.sysRole.remove')") @ApiOperation("批量删除") @DeleteMapping("batchRemove") public Result batchRemove(@RequestBody List ids) { sysRoleService.removeByIds(ids); return Result.ok(); } ``` **_【注】逻辑删除的实现:_** ![输入图片说明](%E5%9B%BE%E7%89%8710.png) ## 6.5 状态更改 ### 6.5.1 思路 ![输入图片说明](%E5%9B%BE%E7%89%878.png) ### 6.5.2 前端 ```vue // 事件 // 【更改用户状态】 switchStatus(row) { // 判断,如果当前用户可用,修改禁用 row.status = row.status === 1 ? 0 : 1; api.updateStatus(row.id, row.status).then((response) => { this.$message.success(response.message || "操作成功"); this.fetchData(); }); }, ``` **_【注】前端CUD操作后均需要进行再次(分页)查询_** ### 6.5.3 后端 **_Controller:_** ```java @ApiOperation("更改用户状态") @GetMapping("updateStatus/{id}/{status}") public Result updateStatus(@PathVariable String id, @PathVariable Integer status) { sysUserService.updateStatus(id,status); return Result.ok(); } ``` **_Impl:_** ```java // 更改用户状态 @Override public void updateStatus(String id, Integer status) { // 根据用户id查询 SysUser sysUser = baseMapper.selectById(id); // 更新用户状态 sysUser.setStatus(status); // 调用方法修改 baseMapper.updateById(sysUser); } ``` ## 6.6 用户分配角色 ### 6.6.1 思路 ![输入图片说明](imgs/%E5%9B%BE%E7%89%8711.png) ### 6.6.2 前端 ```vue ``` ### 6.6.3 后端 **_Controller:_** ```java @ApiOperation("用户分配角色") @PostMapping("doAssign") public Result doAssign(@RequestBody AssginRoleVo assginRoleVo) { sysRoleService.doAssign(assginRoleVo); return Result.ok(); } ``` **_Impl:_** ```java // 用户分配角色 @Override public void doAssign(AssginRoleVo assginRoleVo) { // 1.-:根据用户id删除之前分配的角色 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("user_id",assginRoleVo.getUserId()); sysUserRoleMapper.delete(wrapper); // 2.+:获取所有的角色id,添加到角色用户关系表中表 //角色id列表 List roleIdList = assginRoleVo.getRoleIdList(); for (String roleId:roleIdList) { SysUserRole userRole = new SysUserRole(); userRole.setUserId(assginRoleVo.getUserId()); userRole.setRoleId(roleId); sysUserRoleMapper.insert(userRole); } } ```