目录
1、角色后端接口
2、角色列表查询
2.1 效果图
2.2页面原型代码
2.3 角色api代码 role.js
2.4 查询角色列表代码
4、 新增和编辑角色
5、删除角色
6、分配权限
6.1 分配权限思路
6.2 分配权限回显接口
6.3 分配权限回显前端实现
6.4分配权限后端接口
6.4.1 RolePermissionDTO
6.4.2 RoleMapper
6.4.3 RoleMapper.xml
6.4.4 RoleService
6.4.5 RoleServiceImp
6.4.6 RoleController
6.5分配权限回显前端实现
1、角色后端接口
package com.cizhu.vo.query;import com.cizhu.entity.Permission;
import lombok.Data;@Data
public class RoleQueryVo extends Permission {private Long pageNo = 1L;//当前页码private Long pageSize = 10L;//每页显示数量private Long userId;//用户ID
}
package com.cizhu.mapper;import com.cizhu.entity.Role;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Select;import java.util.List;/*** <p>* Mapper 接口* </p>** @author cizhu* @since 2023-12-14*/
public interface RoleMapper extends BaseMapper<Role> {@Select("select count(1) from sys_user_role where role_id = #{roleId}")int getRoleCountByRoleId(Long roleId);@Delete("delete from sys_role_permission where role_id = #{roleId}")void deleteRolePermissionByRoleId(Long roleId);/*** 保存角色权限关系* @param roleId* @param permissionIds* @return*/int saveRolePermission(Long roleId, List<Long> permissionIds);/*** 根据用户ID查询该用户拥有的角色ID* @param userId* @return*/@Select("select role_id from `sys_user_role` where user_id = #{userId}")List<Long> findRoleIdByUserId(Long userId);}
package com.cizhu.service;import com.baomidou.mybatisplus.core.metadata.IPage;
import com.cizhu.entity.Role;
import com.baomidou.mybatisplus.extension.service.IService;
import com.cizhu.vo.query.RoleQueryVo;import java.util.List;/*** <p>* 服务类* </p>** @author cizhu* @since 2023-12-14*/
public interface IRoleService extends IService<Role> {/*** 根据用户查询角色列表* @param page* @param roleQueryVo* @return*/IPage<Role> findRoleListByUserId(IPage<Role> page, RoleQueryVo roleQueryVo);/**** 检查该角色是否已被使用* @param id:* @return boolean*/boolean hasRoleCount(Long id);/**** 删除角色* @param id:* @return boolean*/boolean deleteRoleById(Long id);/*** 保存角色权限关系* @param roleId* @param permissionIds* @return*/boolean saveRolePermission(Long roleId, List<Long> permissionIds);/*** 根据用户ID查询该用户拥有的角色ID* @param userId* @return*/List<Long> findRoleIdByUserId(Long userId);
}
package com.cizhu.service.impl;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cizhu.entity.Role;
import com.cizhu.entity.User;
import com.cizhu.mapper.RoleMapper;
import com.cizhu.mapper.UserMapper;
import com.cizhu.service.IPermissionService;
import com.cizhu.service.IRoleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cizhu.utils.Result;
import com.cizhu.vo.query.RoleQueryVo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;
import java.util.List;/*** <p>* 服务实现类* </p>** @author cizhu* @since 2023-12-14*/
@Service
@Transactional
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements IRoleService {@Resourceprivate UserMapper userMapper;/*** 根据用户查询角色列表** @param page* @param roleQueryVo* @return*/@Overridepublic IPage<Role> findRoleListByUserId(IPage<Role> page, RoleQueryVo roleQueryVo) {//创建条件构造器QueryWrapper<Role> queryWrapper = new QueryWrapper<Role>();//角色名称queryWrapper.like(!ObjectUtils.isEmpty(roleQueryVo.getRoleName()),"role_name",roleQueryVo.getRoleName());//排序queryWrapper.orderByAsc("id");//根据用户ID查询用户信息User user = userMapper.selectById(roleQueryVo.getUserId());//如果用户不为空、且不是管理员,则只能查询自己创建的角色if(user!=null && !ObjectUtils.isEmpty(user.getIsAdmin()) && user.getIsAdmin() !=1){queryWrapper.eq("create_user",roleQueryVo.getUserId());}return baseMapper.selectPage(page,queryWrapper);}/**** 检查该角色是否已被使用* @param id :* @return boolean*/@Overridepublic boolean hasRoleCount(Long id) {return baseMapper.getRoleCountByRoleId(id) > 0 ;}/**** 删除角色* @param id :* @return boolean*/@Overridepublic boolean deleteRoleById(Long id) {// 删除角色权限关系baseMapper.deleteRolePermissionByRoleId(id);// 删除角色return baseMapper.deleteById(id) > 0 ;}/*** 保存角色权限关系** @param roleId* @param permissionIds* @return*/@Overridepublic boolean saveRolePermission(Long roleId, List<Long> permissionIds) {//删除该角色对应的权限信息baseMapper.deleteRolePermissionByRoleId(roleId);//保存角色权限return baseMapper.saveRolePermission(roleId,permissionIds)>0;}/*** 根据用户ID查询该用户拥有的角色ID** @param userId* @return*/@Overridepublic List<Long> findRoleIdByUserId(Long userId) {return baseMapper.findRoleIdByUserId(userId);}
}
package com.cizhu.controller;import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cizhu.dto.RolePermissionDTO;
import com.cizhu.entity.Role;
import com.cizhu.service.IPermissionService;
import com.cizhu.service.IRoleService;
import com.cizhu.utils.Result;
import com.cizhu.vo.query.RolePermissionVo;
import com.cizhu.vo.query.RoleQueryVo;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;/*** <p>* 前端控制器* </p>** @author cizhu* @since 2023-12-14*/
@RestController
@RequestMapping("/api/role")
public class RoleController {@Resourceprivate IRoleService roleService;@Resourceprivate IPermissionService permissionService;/*** 分页查询角色列表* @param roleQueryVo* @return*/@GetMapping("/list")public Result list(RoleQueryVo roleQueryVo){//创建分页对象IPage<Role> page = new Page<Role>(roleQueryVo.getPageNo(),roleQueryVo.getPageSize());//调用分页查询方法roleService.findRoleListByUserId(page,roleQueryVo);//返回数据return Result.ok(page);}/*** 添加角色* @param role* @return*/@PostMapping("/add")public Result add(@RequestBody Role role){if(roleService.save(role)){return Result.ok().message("角色添加成功");}return Result.error().message("角色添加失败");}/*** 修改角色* @param role* @return*/@PutMapping("/update")public Result update(@RequestBody Role role){if(roleService.updateById(role)){return Result.ok().message("角色修改成功");}return Result.error().message("角色修改失败");}/*** 删除角色* @param id* @return*/@DeleteMapping("/delete/{id}")public Result delete(@PathVariable Long id){if(roleService.deleteRoleById(id)){return Result.ok().message("角色删除成功");}return Result.error().message("角色删除失败");}/*** 检查该角色是否已被使用* @param id* @return*/@GetMapping("/check/{id}")public Result check(@PathVariable Long id){//检查该角色是否已被使用if(roleService.hasRoleCount(id)){return Result.exist().message("该角色已分配给其他用户使用,无法删除");}return Result.ok();}/*** 分配权限-查询权限树数据* @param userId* @param roleId* @return*/@GetMapping("/getAssignPermissionTree")public Result getAssignPermissionTree(Long userId, Long roleId) {//调用查询权限树数据的方法RolePermissionVo permissionTree = permissionService.findPermissionTree(userId, roleId);//返回数据return Result.ok(permissionTree);}/*** 分配权限-保存权限数据** @param rolePermissionDTO* @return*/@PostMapping("/saveRoleAssign")public Result saveRoleAssign(@RequestBody RolePermissionDTO rolePermissionDTO) {if (roleService.saveRolePermission(rolePermissionDTO.getRoleId(),rolePermissionDTO.getList())) {return Result.ok().message("权限分配成功");} else {return Result.error().message("权限分配失败");}}}
2、角色列表查询
2.1 效果图
2.2页面原型代码
<template><el-main><!-- 查询条件 --><el-form :model="searchModel" ref="searchForm" label-width="80px" :inline="true" size="small"><el-form-item><el-input v-model="searchModel.roleName" placeholder="请输入角色名称"/></el-form-item><el-form-item><el-button type="primary" icon="el-icon-search" @click="search(pageNo,pageSize)">查询</el-button><el-button icon="el-icon-refresh-right" @click="resetValue()">重置</el-button><el-button type="success" icon="el-icon-plus" @click="openAddWindow()">新增</el-button></el-form-item></el-form><!-- 数据表格 --><el-table :data="roleList" :height="tableHeight" border stripe style="width: 100%; margin-bottom: 10px"><el-table-column prop="roleCode" label="角色编码" width="160" align="center"></el-table-column><el-table-column prop="roleName" label="角色名称"></el-table-column><el-table-column prop="remark" label="角色备注"></el-table-column><el-table-column label="操作" align="center" width="290"><template slot-scope="scope"><el-button icon="el-icon-edit" type="primary" size="small" @click="handleEdit(scope.row)">编辑</el-button><el-button icon="el-icon-delete" type="danger" size="small" @click="handleDelete(scope.row)">删除</el-button><el-button icon="el-icon-setting" type="primary" size="small" @click="assignRole(scope.row)">分配权限</el-button></template></el-table-column></el-table><!-- 分页工具栏 --><el-paginationbackground@size-change="handleSizeChange"@current-change="handleCurrentChange":current-page="pageNo":page-sizes="[10, 20, 30, 40, 50]":page-size="10"layout="total, sizes, prev, pager, next, jumper":total="total"></el-pagination><!-- 添加和修改角色窗口 --><system-dialog:title="roleDialog.title":visible="roleDialog.visible":width="roleDialog.width":height="roleDialog.height"@onClose="onClose"@onConfirm="onConfirm"><div slot="content"><el-form :model="role" ref="roleForm" :rules="rules" label-width="80px" :inline="false" size="small"><el-form-item label="角色编码" prop="roleCode"><el-input v-model="role.roleCode"></el-input></el-form-item><el-form-item label="角色名称" prop="roleName"><el-input v-model="role.roleName"></el-input></el-form-item><el-form-item label="角色描述"><el-input type="textarea" v-model="role.remark" :rows="5"></el-input></el-form-item></el-form></div></system-dialog><!-- 分配权限树窗口 --><system-dialog:title="assignDialog.title":visible="assignDialog.visible":width="assignDialog.width":height="assignDialog.height"@onClose="onAssignClose"@onConfirm="onAssignConfirm"><div slot="content"><el-tree ref="assignTree" :data="assignTreeData" node-key="id":props="defaultProps" empty-text="暂无数据" :show-checkbox="true":highlight-current="true" default-expand-all></el-tree></div></system-dialog></el-main>
</template>
2.3 角色api代码 role.js
import http from '@/utils/request'export function getRoutes() {// return request({// url: '/vue-element-admin/routes',// method: 'get'// })
}/**
* 查询角色列表
* @returns
*/
export async function getRoles(params) {return await http.get("/api/role/list", params)
}/*** 新增角色* @param {*} data * @returns */
export async function addRole(data) {return await http.post("/api/role/add", data)
}/*** 修改角色* @param {*} data * @returns */
export async function updateRole(data) {return await http.put("/api/role/update", data)
}/**
* 查询角色是否已被使用
* @returns
*/
export async function checkRole(params) {return await http.getRestApi("/api/role/check", params)
}/*** 删除角色* @param {*} id */
export async function deleteRole(params) {return await http.delete("/api/role/delete", params)
}/*** 查询分配权限树列表
* @returns*/
export async function getAssignTree(params) {return await http.get("/api/role/getAssignPermissionTree", params)
}/**
* 分配权限
* @returns
*/
export async function assignSave(params) {return await http.post("/api/role/saveRoleAssign", params)
}
2.4 查询角色列表代码
<script>
//导入role.js脚本
import {getRoles, addRole, updateRole, deleteRole, checkRole, getAssignTree, assignSave} from '@/api/role';
// 导入对话框组件
import SystemDialog from '@/components/system/SystemDialog.vue'
//导入末级节点脚本
import leafUtils from '@/utils/leaf'export default {name: 'roleList',//注册组件components:{ SystemDialog },data() {return {//查询条件searchModel: {roleName: '',pageNo:1,pageSize:10,userId:this.$store.getters.userId //用户ID},roleList: [], //数据列表tableHeight: 0, //表格高度pageNo: 1, //当前页码pageSize: 10, //每页显示数量total: 0, //总数量rules: {roleCode: [{ required: true, trigger: 'blur', message: '请输入角色编码' }],roleName: [{ required: true, trigger: 'blur', message: '请输入角色名称' }]},//添加和修改角色窗口属性roleDialog: {title: '',visible: false,height: 230,width: 500},//角色对象role: {id:"",roleCode:"",roleName:"",remark:"",createUser:this.$store.getters.userId},//分配权限窗口属性assignDialog: {title: '',visible: false,height: 450,width: 300},roleId: '', //角色IDassignTreeData: [], //树节点数据//树节点属性defaultProps: {children: 'children',label: 'label'}}},created() {//调用查询角色列表的方法this.search();},mounted() {this.$nextTick(() => {this.tableHeight = window.innerHeight - 220})},methods: {/*** 查询*/async search(pageNo=1,pageSize=10) {this.searchModel.pageNo = pageNothis.searchModel.pageSize = pageSizelet res = await getRoles(this.searchModel)if (res.success){//console.log(res)this.roleList = res.data.recordsthis.total = res.data.total}},/*** 每页显示数量发生变化*/handleSizeChange(size){this.pageSize = size// 查询数据this.search(this.pageNo, size)},/*** 显示第几页*/handleCurrentChange(page){this.pageNo = page// 查询数据this.search(page, this.pageSize)},/*** 重置查询条件*/resetValue(){//重置查询条件this.searchModel.roleName = ""this.search()},
获取当前用户ID store/user.js
import { login, logout, getInfo } from '@/api/user'
import { getToken, setToken, removeToken, setTokenTime } from '@/utils/auth'
import router, { resetRouter } from '@/router'const state = {token: getToken(), // 获取token信息name: '',avatar: '',introduction: '',roles: []
}const mutations = {SET_TOKEN: (state, token) => {state.token = token},SET_INTRODUCTION: (state, introduction) => {state.introduction = introduction},SET_NAME: (state, name) => {state.name = name},SET_AVATAR: (state, avatar) => {state.avatar = avatar},SET_ROLES: (state, roles) => {state.roles = roles},SET_USERUID: (state, userId) => {state.userId = userId},
}const actions = {// user loginlogin({ commit }, userInfo) {const { username, password } = userInforeturn new Promise((resolve, reject) => {login({ username: username.trim(), password: password }).then(response => {const { token, expireTime } = responsecommit('SET_TOKEN', token)setToken(token)// 设置token过期时间setTokenTime(expireTime)resolve()}).catch(error => {reject(error)})})},// get user infogetInfo({ commit, state }) {return new Promise((resolve, reject) => {getInfo(state.token).then(response => {const { data } = responseif (!data) {reject('Verification failed, please Login again.')}// 从后端反馈的data数据中解构出用户相关信息const { roles, name, avatar, introduction, id } = data// roles must be a non-empty arrayif (!roles || roles.length <= 0) {reject('getInfo: roles must be a non-null array!')}commit('SET_ROLES', roles)commit('SET_NAME', name)commit('SET_AVATAR', avatar)commit('SET_INTRODUCTION', introduction)commit('SET_USERUID', id)//将权限字段保存到sessionStorage中sessionStorage.setItem("codeList",JSON.stringify(roles));resolve(data)}).catch(error => {reject(error)})})},// user logoutlogout({ commit, state, dispatch }) {return new Promise((resolve, reject) => {logout(state.token).then(() => {commit('SET_TOKEN', '')commit('SET_ROLES', [])removeToken()resetRouter()// reset visited views and cached views// to fixed https://github.com/PanJiaChen/vue-element-admin/issues/2485dispatch('tagsView/delAllViews', null, { root: true })resolve()}).catch(error => {reject(error)})})},// remove tokenresetToken({ commit }) {return new Promise(resolve => {commit('SET_TOKEN', '')commit('SET_ROLES', [])removeToken()resolve()})},// dynamically modify permissionsasync changeRoles({ commit, dispatch }, role) {const token = role + '-token'commit('SET_TOKEN', token)setToken(token)const { roles } = await dispatch('getInfo')resetRouter()// generate accessible routes map based on rolesconst accessRoutes = await dispatch('permission/generateRoutes', roles, { root: true })// dynamically add accessible routesrouter.addRoutes(accessRoutes)// reset visited views and cached viewsdispatch('tagsView/delAllViews', null, { root: true })}
}export default {namespaced: true,state,mutations,actions
}
4、 新增和编辑角色
/*** 打开添加窗口*/openAddWindow() {//清空表单数据this.$resetForm("roleForm",this.role);this.roleDialog.title = '新增角色'//设置窗口标题this.roleDialog.visible = true//显示窗口},/*** 窗口取消事件*/onClose() {this.roleDialog.visible = false},/*** 窗口确认事件*/onConfirm() {//表单验证this.$refs.roleForm.validate(async (valid)=>{// 验证通过if (valid) {let res = null// 判断是新增还是修改操作(role.id是否为空)if (this.role.id === ""){// 发送新增角色请求res = await addRole(this.role)}else{// 发送修改角色请求res = await updateRole(this.role)}if (res.success){// 提示成功this.$message.success(res.message)// 刷新数据//this.search(this.pageNo, this.pageSize)window.location.reload();//关闭窗口this.roleDialog.visible = false;}else{this.$message.error(res.message)}}});},/*** 编辑角色*/handleEdit(row){//数据回显this.$objCopy(row, this.role); //将当前编辑的数据复制到role对象中//设置窗口标题this.roleDialog.title = "编辑角色";//显示编辑角色窗口this.roleDialog.visible = true;}
5、删除角色
/*** 删除角色*/async handleDelete(row){//查询角色是否已被使用let result = await checkRole({ id: row.id })//判断是否可以删除if (!result.success) {//提示不能删除this.$message.warning(result.message);} else {//确认是否删除let confirm = await this.$myconfirm("确定要删除该数据吗?")if (confirm) {//发送删除请求let res = await deleteRole({ id: row.id })//判断是否成功if (res.success) {//成功提示this.$message.success(res.message)//刷新this.search(this.pageNo, this.pageSize)} else {//失败提示this.$message.error(res.message)}}}},
6、分配权限
6.1 分配权限思路
6.2 分配权限回显接口
PermissionService
/*** 查询分配权限树列表* @param userId* @param roleId* @return*/RolePermissionVo findPermissionTree(Long userId, Long roleId);
PermissionServiceImp
/*** 查询分配权限树列表** @param userId* @param roleId* @return*/@Overridepublic RolePermissionVo findPermissionTree(Long userId, Long roleId) {// 1.查询当前用户信息User user = userService.getById(userId);List<Permission> list = null;//2.判断当前用户角色,如果是管理员,则查询所有权限;如果不是管理员,则只查询自己所拥有的的权限if (!ObjectUtils.isEmpty(user) && user.getIsAdmin() == 1){//查询所有权限list = baseMapper.selectList(null);}else{//根据用户ID查询list = baseMapper.findPermissionListByUserId(userId);}//3.组装成树数据List<Permission> permissionList = MenuTree.makeMenuTree(list, 0L);//4.查询要分配角色的原有权限List<Permission> rolePermissions = baseMapper.findPermissionListByRoleId(roleId);//5.找出该角色存在的数据List<Long> listIds = new ArrayList<Long>();Optional.ofNullable(list).orElse(new ArrayList<>()).stream().filter(item -> item != null).forEach(item -> {Optional.ofNullable(rolePermissions).orElse(new ArrayList<>()).stream().filter(Objects::nonNull).forEach(obj -> {// 判断两者的权限id是否一致if(item.getId().equals(obj.getId())){listIds.add(obj.getId());return;}});});//创建RolePermissionVo vo = new RolePermissionVo();vo.setPermissionList(permissionList);vo.setCheckList(listIds.toArray());return vo;}
RoleController
6.3 分配权限回显前端实现
/*** 分配权限*/async assignRole(row){this.roleId = row.id// 构建查询参数let params = {roleId: row.id, // 角色iduserId: this.$store.getters.userId // 用户id}// 发送查询分配权限菜单请求let res = await getAssignTree(params)if (res.success){//获取当前登录用户所拥有的所有菜单权限let {permissionList} = res.data//获取当前被分配角色的已经拥有的菜单权限let { checkList } = res.data//判断当前菜单是否是最后一级let { setLeaf } = leafUtils()//设置权限菜单列表let newPermissionList = setLeaf(permissionList)//设置树节点菜单数据this.assignTreeData = newPermissionList//将回调延迟到下次DOM更新循环之后执行,在修改数据之后立即使用它,然后等待DOM更新。this.$nextTick(() => {//获取树菜单的节点数据let nodes = this.$refs.assignTree.children//设置子节点this.setChild(nodes, checkList)})}//显示窗口this.assignDialog.visible = true//设置窗口标题this.assignDialog.title = `给【${row.roleName}】分配权限`},/*** 设置子节点*/setChild(childNodes, checkList) {//判断是否存在子节点if (childNodes && childNodes.length > 0){//循环所有权限for (let i=0; i< childNodes.length; i++) {//根据data或key获取树组件中的node节点let node = this.$refs.assignTree.getNode(childNodes[i])//判断使用已经拥有对应的角色权限数据if (checkList && checkList.length > 0) {//循环遍历已有的权限集合for (let j = 0; j < checkList.length; j++) {//找到已经存在的菜单权限节点if (checkList[j] == childNodes[i].id) {//如果节点是展开状态,则将树节点选中if (childNodes[i].open) {this.$refs.assignTree.setChecked(node, true)break}}}}//如果存在子节点,则递归选中if (childNodes[i].children) {this.setChild(childNodes[i].children, checkList)}}}},/*** 分配权限窗口取消事件*/onAssignClose() {this.assignDialog.visible = false},
6.4分配权限后端接口
6.4.1 RolePermissionDTO
6.4.2 RoleMapper
6.4.3 RoleMapper.xml
6.4.4 RoleService
/*** 保存角色权限关系* @param roleId* @param permissionIds* @return*/boolean saveRolePermission(Long roleId, List<Long> permissionIds);
6.4.5 RoleServiceImp
/*** 保存角色权限关系** @param roleId* @param permissionIds* @return*/@Overridepublic boolean saveRolePermission(Long roleId, List<Long> permissionIds) {//删除该角色对应的权限信息baseMapper.deleteRolePermissionByRoleId(roleId);//保存角色权限return baseMapper.saveRolePermission(roleId,permissionIds)>0;}
6.4.6 RoleController
/*** 分配权限-保存权限数据** @param rolePermissionDTO* @return*/@PostMapping("/saveRoleAssign")public Result saveRoleAssign(@RequestBody RolePermissionDTO rolePermissionDTO) {if (roleService.saveRolePermission(rolePermissionDTO.getRoleId(),rolePermissionDTO.getList())) {return Result.ok().message("权限分配成功");} else {return Result.error().message("权限分配失败");}}
6.5分配权限回显前端实现
/*** 分配权限窗口确认事件*/async onAssignConfirm() {//获取选中的节点keylet ids = this.$refs.assignTree.getCheckedKeys()//获取选中节点的父节点idlet pids = this.$refs.assignTree.getHalfCheckedKeys()//组装选中的节点ID数据let listId = ids.concat(pids)//组装参数let params = {roleId: this.roleId,list: listId}//发送请求let res = await assignSave(params)//判断是否成功if (res.success) {//关闭窗口this.assignDialog.visible = false//提示成功this.$message.success(res.message)} else {//提示失败this.$message.error(res.data)}}