SpringSecurity+vue通用权限系统2
SpringSecurity+vue通用权限系统2
用户管理实现
用户管理-列表分页显示实现
分页实体PageBean:
package com.java.entity;/*** 分页Model类*/
public class PageBean {private int pageNum; // 第几页private int pageSize; // 每页记录数private int start; // 起始页private String query; // 查询参数public PageBean() {}public PageBean(int pageNum, int pageSize, String query) {this.pageNum = pageNum;this.pageSize = pageSize;this.query = query;}public PageBean(int pageNum, int pageSize) {super();this.pageNum = pageNum;this.pageSize = pageSize;}public int getPageNum() {return pageNum;}public void setPageNum(int pageNum) {this.pageNum = pageNum;}public int getPageSize() {return pageSize;}public void setPageSize(int pageSize) {this.pageSize = pageSize;}public int getStart() {return (pageNum-1)*pageSize;}public String getQuery() {return query;}public void setQuery(String query) {this.query = query;}
}
MybatisPlus开启分页功能:
package com.java.config;import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** MybatisPlus配置类*/
@Configuration
public class MybatisPlusConfig {@Beanpublic PaginationInterceptor paginationInterceptor(){return new PaginationInterceptor();}
}
SysUserController
/*** 根据条件分页查询用户信息* @param pageBean* @return*/@PostMapping("/list")@PreAuthorize("hasAuthority('system:user:query')")public R list(@RequestBody PageBean pageBean){String query=pageBean.getQuery().trim();Page<SysUser> pageResult = sysUserService.page(new Page<>(pageBean.getPageNum(), pageBean.getPageSize()) );List<SysUser> userList = pageResult.getRecords();Map<String,Object> resultMap=new HashMap<>();resultMap.put("userList",userList);resultMap.put("total",pageResult.getTotal());return R.ok(resultMap);}
前端user/index.vue
<template><div class="app-container"><el-table :data="tableData" stripe style="width: 100%"><el-table-column prop="username" label="用户名" width="180" /></el-table><el-paginationv-model:currentPage="queryForm.pageNum"v-model:page-size="queryForm.pageSize":page-sizes="[10, 20, 30, 40]"layout="total, sizes, prev, pager, next, jumper":total="total"@size-change="handleSizeChange"@current-change="handleCurrentChange"/></div>
</template>
<script setup>
import requestUtil,{getServerUrl} from "@/util/request";
import { ref } from 'vue'
const tableData=ref([]);
const total=ref(0)
const queryForm=ref({query:'',pageNum:1,pageSize:10
})
const initUserList=async()=>{const res=await requestUtil.post("sys/user/list",queryForm.value);tableData.value=res.data.userList;total.value=res.data.total;
}
initUserList();
const handleSizeChange=(pageSize)=>{queryForm.value.pageNum=1;queryForm.value.pageSize=pageSize;initUserList()
}
const handleCurrentChange=(pageNum)=>{queryForm.value.pageNum=pageNum;initUserList()
}
</script>
<style lang="scss" scoped>
.header{padding-bottom: 16px;box-sizing: border-box;
}
.el-pagination{float: right;padding: 20px;box-sizing: border-box;
}
::v-deep th.el-table__cell{word-break: break-word;background-color: #f8f8f9 !important;color: #515a6e;height: 40px;font-size: 13px;
}
.el-tag--small {margin-left: 5px;
}
</style>
elementplus国际化中文
// 国际化中文
import zhCn from ‘element-plus/es/locale/lang/zh-cn’
app.use(ElementPlus, {
locale: zhCn,
})
用户管理-搜索功能实现
前端需要显示角色信息
SysUser实体加字段
/**
* 所有角色集合
*/
@TableField(exist = false)
private List<SysRole> sysRoleList;
/*** 根据条件分页查询用户信息* @param pageBean* @return*/@PostMapping("/list")@PreAuthorize("hasAuthority('system:user:query')")public R list(@RequestBody PageBean pageBean){String query=pageBean.getQuery().trim();Page<SysUser> pageResult = sysUserService.page(new Page<>(pageBean.getPageNum(), pageBean.getPageSize()),new QueryWrapper<SysUser>().like(StringUtil.isNotEmpty(query),"username",query));List<SysUser> userList = pageResult.getRecords();for(SysUser user:userList){List<SysRole> roleList = sysRoleService.list(new QueryWrapper<SysRole>().inSql("id","select role_id from sys_user_role where user_id=" + user.getId()));user.setSysRoleList(roleList);}Map<String,Object> resultMap=new HashMap<>();resultMap.put("userList",userList);resultMap.put("total",pageResult.getTotal());return R.ok(resultMap);}
搜索框
<el-row :gutter="20" class="header"><el-col :span="7"><el-input placeholder="请输入用户名..." v-model="queryForm.query" clearable></el-input></el-col><el-button type="primary" :icon="Search" @click="initUserList">搜索</el-button></el-row>import { Search ,Delete,DocumentAdd ,Edit, Tools, RefreshRight} from '@elementplus/icons-vue'
<template><div class="app-container"><el-row :gutter="20" class="header"><el-col :span="7"><el-input placeholder="请输入用户名..." v-model="queryForm.query" clearable></el-input></el-col><el-button type="primary" :icon="Search" @click="initUserList">搜索</el-button></el-row><el-table :data="tableData" stripe style="width: 100%"><el-table-column type="selection" width="55" /><el-table-column prop="avatar" label="头像" width="80" align="center"><template v-slot="scope"><img :src="getServerUrl()+'image/userAvatar/'+scope.row.avatar"width="50" height="50"/></template></el-table-column><el-table-column prop="username" label="用户名" width="100"align="center"/><el-table-column prop="roles" label="拥有角色" width="200" align="center"><template v-slot="scope"><el-tag size="small" type="warning" v-for="item in
scope.row.sysRoleList"> {{item.name}}</el-tag></template></el-table-column><el-table-column prop="email" label="邮箱" width="200" align="center"/><el-table-column prop="phonenumber" label="手机号" width="120"align="center"/><el-table-column prop="status" label="状态?" width="200" align="center"><template v-slot="{row}" ><el-switch v-model="row.status" @change="statusChangeHandle(row)"active-text="正常"inactive-text="禁用" active-value="0" inactive-value="1"></el-switch></template></el-table-column><el-table-column prop="createTime" label="创建时间" width="200"align="center"/><el-table-column prop="loginDate" label="最后登录时间" width="200"align="center"/><el-table-column prop="remark" label="备注" /><el-table-column prop="action" label="操作" width="400" fixed="right"align="center"><template v-slot="scope" ><el-button type="primary" :icon="Tools" >分配角色</el-button></template></el-table-column></el-table><el-paginationv-model:currentPage="queryForm.pageNum"v-model:page-size="queryForm.pageSize":page-sizes="[10, 20, 30, 40]"layout="total, sizes, prev, pager, next, jumper":total="total"@size-change="handleSizeChange"@current-change="handleCurrentChange"/></div>
</template>
用户管理-添加修改功能实现
后端提供一个API
添加或者修改:
/*** 添加或者修改* @param sysUser* @return*/@PostMapping("/save")@PreAuthorize("hasAuthority('system:user:add')"+"||"+"hasAuthority('system:user:edit')")public R save(@RequestBody SysUser sysUser){if(sysUser.getId()==null || sysUser.getId()==-1){sysUser.setCreateTime(new Date());sysUser.setPassword(bCryptPasswordEncoder.encode(sysUser.getPassword()));sysUserService.save(sysUser);}else{sysUser.setUpdateTime(new Date());sysUserService.updateById(sysUser);}return R.ok();}
修改功能,需要根据id查询数据
/*** 根据id查询* @param id* @return*/@GetMapping("/{id}")@PreAuthorize("hasAuthority('system:user:query')")public R findById(@PathVariable(value = "id")Integer id){SysUser sysUser = sysUserService.getById(id);Map<String,Object> map=new HashMap<>();map.put("sysUser",sysUser);return R.ok(map);}
添加用户,需要验证用户名是否重复
/*** 验证用户名* @param sysUser* @return*/@PostMapping("/checkUserName")@PreAuthorize("hasAuthority('system:user:query')")public R checkUserName(@RequestBody SysUser sysUser){if(sysUserService.getByUsername(sysUser.getUsername())==null){return R.ok();}else{return R.error();}}
前端,新建一个 dialog.vue 作为用户添加和修改页面组件
<template><el-dialog:visible="dialogVisible":title="dialogTitle"width="30%"@close="handleClose"><el-formref="formRef":model="form":rules="rules"label-width="100px"><el-form-item label="用户名" prop="username"><el-input v-model="form.username" :disabled="form.id==-1?false:'disabled'" /><el-alertv-if="form.id==-1"title="默认初始密码:123456":closable="false"style="line-height: 10px;"type="success" ></el-alert></el-form-item><el-form-item label="手机号" prop="phonenumber"><el-input v-model="form.phonenumber" /></el-form-item><el-form-item label="邮箱" prop="email"><el-input v-model="form.email" /></el-form-item><el-form-item label="状态" prop="status"><el-radio-group v-model="form.status"><el-radio :label="'0'">正常</el-radio><el-radio :label="'1'">禁用</el-radio></el-radio-group></el-form-item><el-form-item label="备注" prop="remark"><el-input v-model="form.remark" type="textarea" :rows="4"/></el-form-item></el-form><template #footer><span class="dialog-footer"><el-button type="primary" @click="handleConfirm">确认</el-button><el-button @click="handleClose">取消</el-button></span></template></el-dialog></template><script setup>
import {defineEmits, defineProps,ref,watch } from "vue"
import requestUtil,{getServerUrl} from "@/util/request";
import { ElMessage } from 'element-plus'const props=defineProps({id:{type:Number,default:-1,required:true},dialogTitle:{type:String,default:'',required:true},dialogVisible:{type:Boolean,default:false,required:true}}
)const form=ref({id:-1,username:"",password:"123456",status:"0",phonenumber:"",email:"",remark:""
})const checkUsername = async (rule, value, callback) => {if(form.value.id==-1){const res=await requestUtil.post("sys/user/checkUserName",{username:form.value.username});if (res.data.code==500) {callback(new Error("用户名已存在!"));} else {callback();}}else{callback();}}const rules=ref({username:[{ required: true, message: '请输入用户名'},{ required: true, validator: checkUsername, trigger: "blur" }],email: [{ required: true, message: "邮箱地址不能为空", trigger: "blur" }, { type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],phonenumber: [{ required: true, message: "手机号码不能为空", trigger: "blur" }, { pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }],
})const formRef=ref(null)const initFormData=async(id)=>{const res=await requestUtil.get("sys/user/"+id);form.value=res.data.sysUser;
}watch(()=>props.dialogVisible,()=>{let id=props.id;console.log("id="+id)if(id!=-1){initFormData(id);}else{form.value={id:-1,username:"",password:"123456",status:"0",phonenumber:"",email:"",remark:""}}}
)const emits=defineEmits(['update:modelValue','initUserList'])const handleClose=()=>{emits('update:modelValue',false)
}const handleConfirm=()=>{formRef.value.validate(async(valid)=>{if(valid){let result=await requestUtil.post("sys/user/save",form.value);let data=result.data;if(data.code==200){ElMessage.success("执行成功!")formRef.value.resetFields();emits("initUserList")handleClose();}else{ElMessage.error(data.msg);}}else{console.log("fail")}})
}</script><style lang="scss" scoped></style>
index.vue页面
<el-button type="success" :icon="DocumentAdd" @click="handleDialogValue()">新增
</el-button>
<el-button v-if="scope.row.username!='java1234'" type="primary" :icon="Edit"
@click="handleDialogValue(scope.row.id)" />
添加和修改按钮
import Dialog from './components/dialog'<Dialog v-model="dialogVisible" :dialogVisible="dialogVisible" :id="id"
:dialogTitle="dialogTitle" @initUserList="initUserList"/>
const dialogVisible=ref(false)
const dialogTitle=ref("")
const id=ref(-1)const handleDialogValue=(userId)=>{
if(userId){
id.value=userId;
dialogTitle.value="用户修改"
}else{
id.value=-1;
dialogTitle.value="用户添加"
}
dialogVisible.value=true
}
用户管理-删除和批量删除功能实现
后端:
/*** 删除* @param ids* @return*/@Transactional@PostMapping("/delete")@PreAuthorize("hasAuthority('system:user:delete')")public R delete(@RequestBody Long[] ids){sysUserService.removeByIds(Arrays.asList(ids));sysUserRoleService.remove(new QueryWrapper<SysUserRole>().in("user_id",ids));return R.ok();}
前端:
<el-popconfirm title="您确定批量删除这些记录吗?" @confirm="handleDelete(null)">
<template #reference>
<el-button type="danger" :disabled="delBtnStatus" :icon="Delete" >批量删除</elbutton>
</template>
</el-popconfirm>
const delBtnStatus=ref(true)
表格复选框选中事件:
@selection-change="handleSelectionChange"
定义 选中的行
const multipleSelection=ref([])const handleSelectionChange=(selection)=>{
console.log("勾选了")
console.log(selection)
multipleSelection.value=selection;
delBtnStatus.value=selection.length==0;
}
行上面的删除按钮
<el-popconfirm v-if="scope.row.username!='java1234'" title="您确定要删除这条记录
吗?" @confirm="handleDelete(scope.row.id)">
<template #reference>
<el-button type="danger" :icon="Delete" />
</template>
</el-popconfirm>
import { ElMessage, ElMessageBox } from 'element-plus'
const handleDelete=async (id)=>{var ids = []if(id){ids.push(id)}else{multipleSelection.value.forEach(row=>{ids.push(row.id)})}const res=await requestUtil.post("sys/user/delete",ids)if(res.data.code==200){ElMessage({type: 'success',message: '执行成功!'})initUserList();}else{ElMessage({type: 'error',message: res.data.msg,})}
}
用户管理-用户信息重置密码和状态更新功能实现
后端 重置密码:
/*** 重置密码* @param id* @return*/@GetMapping("/resetPassword/{id}")@PreAuthorize("hasAuthority('system:user:edit')")public R resetPassword(@PathVariable(value = "id")Integer id){SysUser sysUser = sysUserService.getById(id);sysUser.setPassword(bCryptPasswordEncoder.encode(Constant.DEFAULT_PASSWORD));sysUser.setUpdateTime(new Date());sysUserService.updateById(sysUser);return R.ok();}
package com.java.common.constant;/*** 通用常量信息*/
public class Constant {public final static String DEFAULT_PASSWORD="123456";
}
/*** 更新status状态* @param id* @param status* @return*/@GetMapping("/updateStatus/{id}/status/{status}")@PreAuthorize("hasAuthority('system:user:edit')")public R updateStatus(@PathVariable(value = "id")Integer id,@PathVariable(value= "status")String status){SysUser sysUser = sysUserService.getById(id);sysUser.setStatus(status);sysUserService.saveOrUpdate(sysUser);return R.ok();}
前端:
<el-popconfirm v-if="scope.row.username!='java1234'" title="您确定要对这个用户重置密
码吗?" @confirm="handleResetPassword(scope.row.id)"><template #reference><el-button type="warning" :icon="RefreshRight" >重置密码</el-button></template></el-popconfirm>
const handleResetPassword=async (id)=>{const res=await requestUtil.get("sys/user/resetPassword/"+id)if(res.data.code==200){ElMessage({type: 'success',message: '执行成功!'})initUserList();}else{ElMessage({type: 'error',message: res.data.msg,})}
}const statusChangeHandle=async (row)=>{let res=awaitrequestUtil.get("sys/user/updateStatus/"+row.id+"/status/"+row.status);if(res.data.code==200){ElMessage({type: 'success',message: '执行成功!'})}else{ElMessage({type: 'error',message: res.data.msg,})initUserList();}
}
重置密码和状态更新
用户管理-用户分配角色功能实现
新建 roleDialog.vue
<template><el-dialogmodel-value="roleDialogVisible"title="分配角色"width="30%"@close="handleClose"><el-formref="formRef":model="form"label-width="100px"><el-checkbox-group v-model="form.checkedRoles"><el-checkbox v-for="role in form.roleList" :id="role.id" :key="role.id" :label="role.id" name="checkedRoles" >{{role.name}}</el-checkbox></el-checkbox-group></el-form><template #footer><span class="dialog-footer"><el-button type="primary" @click="handleConfirm">确认</el-button><el-button @click="handleClose">取消</el-button></span></template></el-dialog>
</template><script setup>import {defineEmits, defineProps, ref, watch} from "vue";
import requestUtil,{getServerUrl} from "@/util/request";
import { ElMessage } from 'element-plus'const props=defineProps({id:{type:Number,default:-1,required:true},roleDialogVisible:{type:Boolean,default:false,required:true},sysRoleList:{type:Array,default:[],required:true}})const form=ref({id:-1,roleList:[],checkedRoles:[]
})const formRef=ref(null)const initFormData=async(id)=>{const res=await requestUtil.get("sys/role/listAll");form.value.roleList=res.data.roleList;form.value.id=id;
}watch(()=>props.roleDialogVisible,()=>{let id=props.id;console.log("id="+id)if(id!=-1){form.value.checkedRoles=[]props.sysRoleList.forEach(item=>{form.value.checkedRoles.push(item.id);})initFormData(id)}})const emits=defineEmits(['update:modelValue','initUserList'])const handleClose=()=>{emits('update:modelValue',false)}const handleConfirm=()=>{formRef.value.validate(async(valid)=>{if(valid){let result=await requestUtil.post("sys/user/grantRole/"+form.value.id,form.value.checkedRoles);let data=result.data;if(data.code==200){ElMessage.success("执行成功!")emits("initUserList")handleClose();}else{ElMessage.error(data.msg);}}else{console.log("fail")}})}</script><style scoped></style>
import RoleDialog from './components/roleDialog'const sysRoleList=ref([])
const roleDialogVisible=ref(false)
后端
/*** 用户角色授权* @param userId* @param roleIds* @return*/@Transactional@PostMapping("/grantRole/{userId}")@PreAuthorize("hasAuthority('system:user:role')")public R grantRole(@PathVariable("userId") Long userId,@RequestBody Long[] roleIds){List<SysUserRole> userRoleList=new ArrayList<>();Arrays.stream(roleIds).forEach(r -> {SysUserRole sysUserRole = new SysUserRole();sysUserRole.setRoleId(r);sysUserRole.setUserId(userId);userRoleList.add(sysUserRole);});sysUserRoleService.remove(new QueryWrapper<SysUserRole>().eq("user_id",userId));sysUserRoleService.saveBatch(userRoleList);return R.ok();}
新建控制SysRoleController 类
package com.java.controller;import com.java.entity.R;
import com.java.entity.SysRole;
import com.java.service.SysRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** 系统角色Controller控制器*/
@RestController
@RequestMapping("/sys/role")
public class SysRoleController {@Autowiredprivate SysRoleService sysRoleService;@GetMapping("/listAll")@PreAuthorize("hasAuthority('system:role:query')")public R listAll(){Map<String,Object> resultMap=new HashMap<>();List<SysRole> roleList = sysRoleService.list();resultMap.put("roleList",roleList);return R.ok(resultMap);}
}
可以添加,删除角色
角色管理实现
角色管理-根据条件列表分页显示实现
后端
/*** 根据条件分页查询角色信息* @param pageBean* @return*/@PostMapping("/list")@PreAuthorize("hasAuthority('system:role:query')")public R list(@RequestBody PageBean pageBean){String query=pageBean.getQuery().trim();Page<SysRole> pageResult = sysRoleService.page(new Page<>(pageBean.getPageNum(), pageBean.getPageSize()),new QueryWrapper<SysRole>().like(StringUtil.isNotEmpty(query),"name",query));List<SysRole> roleList = pageResult.getRecords();Map<String,Object> resultMap=new HashMap<>();resultMap.put("roleList",roleList);resultMap.put("total",pageResult.getTotal());return R.ok(resultMap);}
前端 从user index.vue复制一份改改 user改成role User改成Role
<template><div class="app-container"><el-row :gutter="20" class="header"><el-col :span="7"><el-input placeholder="请输入角色名..." v-model="queryForm.query" clearable></el-input></el-col><el-button type="primary" :icon="Search" @click="initRoleList">搜索</el-button><el-button type="success" :icon="DocumentAdd" @click="handleDialogValue()">新增</el-button><el-popconfirm title="您确定批量删除这些记录吗?" @confirm="handleDelete(null)"><template #reference><el-button type="danger" :disabled="delBtnStatus" :icon="Delete" >批量删除</el-button></template></el-popconfirm></el-row><el-table :data="tableData" stripe style="width: 100%" @selection-change="handleSelectionChange"><el-table-column type="selection" width="55" /><el-table-column prop="name" label="角色名" width="100" align="center"/><el-table-column prop="code" label="权限字符" width="200" align="center"/><el-table-column prop="createTime" label="创建时间" width="200" align="center"/><el-table-column prop="remark" label="备注" /><el-table-column prop="action" label="操作" width="400" fixed="right" align="center"><template v-slot="scope" ><el-button type="primary" :icon="Tools" @click="handleRoleDialogValue(scope.row.id,scope.row.sysRoleList)">分配权限</el-button><el-button v-if="scope.row.code!='admin'" type="primary" :icon="Edit"@click="handleDialogValue(scope.row.id)" /><el-popconfirm v-if="scope.row.code!='admin'" title="您确定要删除这条记录
吗?" @confirm="handleDelete(scope.row.id)"><template #reference><el-button type="danger" :icon="Delete" /></template></el-popconfirm></template></el-table-column></el-table><el-paginationv-model:currentPage="queryForm.pageNum"v-model:page-size="queryForm.pageSize":page-sizes="[10, 20, 30, 40]"layout="total, sizes, prev, pager, next, jumper":total="total"@size-change="handleSizeChange"@current-change="handleCurrentChange"v/></div><Dialog v-model="dialogVisible" :dialogVisible="dialogVisible" :id="id" :dialogTitle="dialogTitle" @initRoleList="initRoleList"/><RoleDialog v-model="roleDialogVisible" :sysRoleList="sysRoleList":roleDialogVisible="roleDialogVisible" :id="id" @initRoleList="initRoleList"></RoleDialog>
</template>
可正常搜索,显示
角色管理-添加修改功能实现
后端:
/*** 添加或者修改* @param sysRole* @return*/@PostMapping("/save")@PreAuthorize("hasAuthority('system:role:add')"+"||"+"hasAuthority('system:role:edit')")public R save(@RequestBody SysRole sysRole){if(sysRole.getId()==null || sysRole.getId()==-1){sysRole.setCreateTime(new Date());sysRoleService.save(sysRole);}else{sysRole.setUpdateTime(new Date());sysRoleService.updateById(sysRole);}return R.ok();}/*** 根据id查询* @param id* @return*/@GetMapping("/{id}")@PreAuthorize("hasAuthority('system:role:query')")public R findById(@PathVariable(value = "id")Integer id){SysRole sysRole = sysRoleService.getById(id);Map<String,Object> map=new HashMap<>();map.put("sysRole",sysRole);return R.ok(map);}
前端:
dialog.vue
<template><el-dialog:visible="dialogVisible":title="dialogTitle"width="30%"@close="handleClose"><el-formref="formRef":model="form":rules="rules"label-width="100px"><el-form-item label="角色名称" prop="name"><el-input v-model="form.name" /></el-form-item><el-form-item label="权限字符" prop="code"><el-input v-model="form.code" /></el-form-item><el-form-item label="备注" prop="remark"><el-input v-model="form.remark" type="textarea" :rows="4"/></el-form-item></el-form><template #footer><span class="dialog-footer"><el-button type="primary" @click="handleConfirm">确认</el-button><el-button @click="handleClose">取消</el-button></span></template></el-dialog></template><script setup>
import {defineEmits, defineProps,ref,watch } from "vue"
import requestUtil,{getServerUrl} from "@/util/request";
import { ElMessage } from 'element-plus'const props=defineProps({id:{type:Number,default:-1,required:true},dialogTitle:{type:String,default:'',required:true},dialogVisible:{type:Boolean,default:false,required:true}}
)const form=ref({id:-1,name:"",code:"",remark:""
})const rules=ref({name:[{ required: true, message: '请输入角色名称'}],code:[{ required: true, message: '请输入权限字符'}],
})const formRef=ref(null)const initFormData=async(id)=>{const res=await requestUtil.get("sys/role/"+id);form.value=res.data.sysRole;
}watch(()=>props.dialogVisible,()=>{let id=props.id;console.log("id="+id)if(id!=-1){initFormData(id);}else{form.value={id:-1,name:"",code:"",remark:""}}}
)const emits=defineEmits(['update:modelValue','initRoleList'])const handleClose=()=>{emits('update:modelValue',false)
}const handleConfirm=()=>{formRef.value.validate(async(valid)=>{if(valid){let result=await requestUtil.post("sys/role/save",form.value);let data=result.data;if(data.code==200){ElMessage.success("执行成功!")formRef.value.resetFields();emits("initRoleList")handleClose();}else{ElMessage.error(data.msg);}}else{console.log("fail")}})
}</script><style lang="scss" scoped></style>
角色管理-删除和批量删除功能实现
/*** 删除* @param ids* @return*/@Transactional@PostMapping("/delete")@PreAuthorize("hasAuthority('system:role:delete')")public R delete(@RequestBody Long[] ids){sysRoleService.removeByIds(Arrays.asList(ids));sysUserRoleService.remove(new QueryWrapper<SysUserRole>().in("role_id",ids));return R.ok();}
角色管理-显示权限菜单树
后端:
package com.java.controller;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import com.java.entity.R;
import com.java.entity.SysMenu;
import com.java.service.SysMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;import java.util.*;/*** 系统菜单Controller控制器*/
@RestController
@RequestMapping("/sys/menu")
public class SysMenuController {@Autowiredprivate SysMenuService sysMenuService;/*** 查询所有菜单树信息* @return*/@RequestMapping("/treeList")@PreAuthorize("hasAuthority('system:menu:query')")public R treeList(){List<SysMenu> menuList = sysMenuService.list(new QueryWrapper<SysMenu>().orderByAsc("order_num"));return R.ok().put("treeMenu",sysMenuService.buildTreeMenu(menuList));}/*** 添加或者修改* @param sysMenu* @return*/@PostMapping("/save")@PreAuthorize("hasAuthority('system:menu:add')"+"||"+"hasAuthority('system:menu:edit')")public R save(@RequestBody SysMenu sysMenu){if(sysMenu.getId()==null || sysMenu.getId()==-1){sysMenu.setCreateTime(new Date());sysMenuService.save(sysMenu);}else{sysMenu.setUpdateTime(new Date());sysMenuService.updateById(sysMenu);}return R.ok();}/*** 根据id查询* @param id* @return*/@GetMapping("/{id}")@PreAuthorize("hasAuthority('system:menu:query')")public R findById(@PathVariable(value = "id")Long id){SysMenu sysMenu = sysMenuService.getById(id);Map<String,Object> map=new HashMap<>();map.put("sysMenu",sysMenu);return R.ok(map);}/*** 删除* @param id* @return*/@GetMapping("/delete/{id}")@PreAuthorize("hasAuthority('system:menu:delete')")public R delete(@PathVariable(value = "id")Long id){int count = sysMenuService.count(new QueryWrapper<SysMenu>().eq("parent_id", id));if(count>0){return R.error("请先删除子菜单!");}sysMenuService.removeById(id);return R.ok();}}
前端
<template><el-dialogmodel-value="menuDialogVisible"title="分配权限"width="30%"@close="handleClose"><el-formref="formRef":model="form"label-width="100px"><el-treeref="treeRef":data="treeData":props="defaultProps"show-checkbox:default-expand-all=truenode-key="id":check-strictly=true/></el-form><template #footer><span class="dialog-footer"><el-button type="primary" @click="handleConfirm">确认</el-button><el-button @click="handleClose">取消</el-button></span></template></el-dialog>
</template><script setup>import {defineEmits, defineProps, ref, watch} from "vue";
import requestUtil,{getServerUrl} from "@/util/request";
import { ElMessage } from 'element-plus'const props=defineProps({id:{type:Number,default:-1,required:true},menuDialogVisible:{type:Boolean,default:false,required:true}})const form=ref({id:-1,})const treeRef=ref(null)const treeData=ref([])const defaultProps = {children: 'children',label: 'name'
}const formRef=ref(null)const initFormData=async(id)=>{const res=await requestUtil.get("sys/menu/treeList");console.log("res.data.treeMenu="+res.data.treeMenu)treeData.value=res.data.treeMenu;form.value.id=id;
}watch(()=>props.menuDialogVisible,()=>{let id=props.id;console.log("id="+id)if(id!=-1){initFormData(id)}})const emits=defineEmits(['update:modelValue','initRoleList'])const handleClose=()=>{emits('update:modelValue',false)}const handleConfirm=()=>{formRef.value.validate(async(valid)=>{if(valid){let result=await requestUtil.post("sys/user/grantRole/"+form.value.id,form.value.checkedRoles);let data=result.data;if(data.code==200){ElMessage.success("执行成功!")emits("initUserList")handleClose();}else{ElMessage.error(data.msg);}}else{console.log("fail")}})}</script><style scoped></style>
index.vue
<MenuDialog v-model="menuDialogVisible" :menuDialogVisible="menuDialogVisible"
:id="id" @initRoleList="initRoleList"></MenuDialog>
import MenuDialog from './components/menuDialog'
const menuDialogVisible=ref(false);
const handleMenuDialogValue=(roleId)=>{
if(roleId){
id.value=roleId;
}
menuDialogVisible.value=true
}
角色管理-分配功能实现
后端:
/*** 获取当前角色的权限菜单ID集合* @param id* @return*/@GetMapping("/menus/{id}")@PreAuthorize("hasAuthority('system:role:menu')")public R menus(@PathVariable(value = "id")Integer id){List<SysRoleMenu> roleMenuList = sysRoleMenuService.list(new QueryWrapper<SysRoleMenu>().eq("role_id", id));List<Long> menuIdList = roleMenuList.stream().map(p -> p.getMenuId()).collect(Collectors.toList());return R.ok().put("menuIdList",menuIdList);}/*** 更新角色权限信息* @param id* @param menuIds* @return*/@Transactional@PostMapping("/updateMenus/{id}")@PreAuthorize("hasAuthority('system:role:menu')")public R updateMenus(@PathVariable(value = "id")Long id, @RequestBody Long[] menuIds){sysRoleMenuService.remove(new QueryWrapper<SysRoleMenu>().eq("role_id",id));List<SysRoleMenu> sysRoleMenuList=new ArrayList<>();Arrays.stream(menuIds).forEach(menuId->{SysRoleMenu roleMenu=new SysRoleMenu();roleMenu.setRoleId(id);roleMenu.setMenuId(menuId);sysRoleMenuList.add(roleMenu);});sysRoleMenuService.saveBatch(sysRoleMenuList);return R.ok();}
前端:
<template><el-dialogmodel-value="menuDialogVisible"title="分配权限"width="30%"@close="handleClose"><el-formref="formRef":model="form"label-width="100px"><el-treeref="treeRef":data="treeData":props="defaultProps"show-checkbox:default-expand-all=truenode-key="id":check-strictly=true/></el-form><template #footer><span class="dialog-footer"><el-button type="primary" @click="handleConfirm">确认</el-button><el-button @click="handleClose">取消</el-button></span></template></el-dialog>
</template><script setup>import {defineEmits, defineProps, ref, watch} from "vue";
import requestUtil,{getServerUrl} from "@/util/request";
import { ElMessage } from 'element-plus'const props=defineProps({id:{type:Number,default:-1,required:true},menuDialogVisible:{type:Boolean,default:false,required:true}})const form=ref({id:-1,})const treeRef=ref(null)const treeData=ref([])const defaultProps = {children: 'children',label: 'name'
}const formRef=ref(null)const initFormData=async(id)=>{const res=await requestUtil.get("sys/menu/treeList");treeData.value=res.data.treeMenu;form.value.id=id;const res2=await requestUtil.get("sys/role/menus/"+id);treeRef.value.setCheckedKeys(res2.data.menuIdList);}watch(()=>props.menuDialogVisible,()=>{let id=props.id;console.log("id="+id)if(id!=-1){initFormData(id)}})const emits=defineEmits(['update:modelValue','initRoleList'])const handleClose=()=>{emits('update:modelValue',false)}const handleConfirm=()=>{formRef.value.validate(async(valid)=>{if(valid){var menuIds=treeRef.value.getCheckedKeys();let result=await requestUtil.post("sys/role/updateMenus/"+form.value.id,menuIds);let data=result.data;if(data.code==200){ElMessage.success("执行成功!")emits("initRoleList")handleClose();}else{ElMessage.error(data.msg);}}else{console.log("fail")}})
}</script><style scoped></style>
菜单管理实现
菜单管理-树形表格菜单信息显示
index.vue
<template><div class="app-container"><el-row class="header"><el-button type="success" :icon="DocumentAdd" @click="handleDialogValue()">新增</el-button></el-row><el-table:data="tableData"row-key="id"stripestyle="width: 100%; margin-bottom: 20px"borderdefault-expand-all:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"><el-table-column prop="name" label="菜单名称" width="200"/><el-table-column prop="icon" label="图标" width="70" align="center"><template v-slot="scope"><el-icon><svg-icon :icon="scope.row.icon" /></el-icon></template></el-table-column><el-table-column prop="orderNum" label="排序" width="70" align="center"/><el-table-column prop="perms" label="权限标识" width="200" /><el-table-column prop="path" label="组件路径" width="180" /><el-table-column prop="menuType" label="菜单类型" width="120" align="center"><template v-slot="scope"><el-tag size="small" v-if="scope.row.menuType === 'M'" type="danger" effect="dark">目录</el-tag><el-tag size="small" v-else-if="scope.row.menuType === 'C'" type="success" effect="dark">菜单</el-tag><el-tag size="small" v-else-if="scope.row.menuType === 'F'" type="warning" effect="dark">按钮</el-tag></template></el-table-column><el-table-column prop="createTime" label="创建时间" align="center"/><el-table-column prop="action" label="操作" width="400" fixed="right" align="center"><template v-slot="scope" ><el-button type="primary" :icon="Edit" @click="handleDialogValue(scope.row.id)" /><el-popconfirm title="您确定要删除这条记录吗?" @confirm="handleDelete(scope.row.id)"><template #reference><el-button type="danger" :icon="Delete" /></template></el-popconfirm></template></el-table-column></el-table></div><Dialog v-model="dialogVisible" :tableData="tableData" :dialogVisible="dialogVisible" :id="id" :dialogTitle="dialogTitle" @initMenuList="initMenuList"/></template><script setup>
import {ref} from 'vue';
import requestUtil,{getServerUrl} from "@/util/request";
import { Search ,Delete,DocumentAdd ,Edit, Tools, RefreshRight} from '@element-plus/icons-vue'
import Dialog from './components/dialog'
import { ElMessage, ElMessageBox } from 'element-plus'const tableData=ref([])const dialogVisible=ref(false)const dialogTitle=ref("")const id=ref(-1)const initMenuList=async()=>{const res=await requestUtil.get("sys/menu/treeList");tableData.value=res.data.treeMenu;}initMenuList();const handleDialogValue=(menuId)=>{if(menuId){id.value=menuId;dialogTitle.value="菜单修改"}else{id.value=-1;dialogTitle.value="菜单添加"}dialogVisible.value=true
}const handleDelete=async (id)=>{const res=await requestUtil.get("sys/menu/delete/"+id)if(res.data.code==200){ElMessage({type: 'success',message: '执行成功!'})initMenuList();}else{ElMessage({type: 'error',message: res.data.msg,})}
}</script><style lang="scss" scoped>.header{padding-bottom: 16px;box-sizing: border-box;
}.el-pagination{float: right;padding: 20px;box-sizing: border-box;
}::v-deep th.el-table__cell{word-break: break-word;background-color: #f8f8f9 !important;color: #515a6e;height: 40px;font-size: 13px;}.el-tag--small {margin-left: 5px;
}
</style>
菜单管理-添加修改功能实现
后端:
/*** 添加或者修改* @param sysMenu* @return*/@PostMapping("/save")@PreAuthorize("hasAuthority('system:menu:add')"+"||"+"hasAuthority('system:menu:edit')")public R save(@RequestBody SysMenu sysMenu){if(sysMenu.getId()==null || sysMenu.getId()==-1){sysMenu.setCreateTime(new Date());sysMenuService.save(sysMenu);}else{sysMenu.setUpdateTime(new Date());sysMenuService.updateById(sysMenu);}return R.ok();}/*** 根据id查询* @param id* @return*/@GetMapping("/{id}")@PreAuthorize("hasAuthority('system:menu:query')")public R findById(@PathVariable(value = "id")Long id){SysMenu sysMenu = sysMenuService.getById(id);Map<String,Object> map=new HashMap<>();map.put("sysMenu",sysMenu);return R.ok(map);}
前端:
<template><el-dialogmodel-value="dialogVisible":title="dialogTitle"width="30%"@close="handleClose"><el-formref="formRef":model="form":rules="rules"label-width="100px"><el-form-item label="上级菜单" prop="parentId"><el-select v-model="form.parentId" placeholder="请选择上级菜单" @change="$forceUpdate()"><template v-for="item in tableData"><el-option :label="item.name" :value="item.id"></el-option><template v-for="child in item.children"><el-option :label="child.name" :value="child.id"><span>{{ " -- " + child.name }}</span></el-option></template></template></el-select></el-form-item><el-form-item label="菜单类型" prop="menuType" label-width="100px"><el-radio-group v-model="form.menuType"><el-radio :label="'M'">目录</el-radio><el-radio :label="'C'">菜单</el-radio><el-radio :label="'F'">按钮</el-radio></el-radio-group></el-form-item><el-form-item label="菜单图标" prop="icon"><el-input v-model="form.icon" /></el-form-item><el-form-item label="菜单名称" prop="name"><el-input v-model="form.name" /></el-form-item><el-form-item label="权限标识" prop="perms"><el-input v-model="form.perms" /></el-form-item><el-form-item label="组件路径" prop="component"><el-input v-model="form.component" /></el-form-item><el-form-item label="显示顺序" prop="orderNum" ><el-input-number v-model="form.orderNum" :min="1" label="显示顺序"></el-input-number></el-form-item></el-form><template #footer><span class="dialog-footer"><el-button type="primary" @click="handleConfirm">确认</el-button><el-button @click="handleClose">取消</el-button></span></template></el-dialog>
</template><script setup>import {defineEmits, defineProps, ref, watch} from "vue";
import requestUtil,{getServerUrl} from "@/util/request";
import { ElMessage } from 'element-plus'const tableData=ref([])const props=defineProps({id:{type:Number,default:-1,required:true},dialogTitle:{type:String,default:'',required:true},dialogVisible:{type:Boolean,default:false,required:true},tableData:{type:Array,default:[],required:true}})const form=ref({id:-1,parentId:'',menuType:"M",icon:'',name:'',perms:'',component:'',orderNum:1
})const rules=ref({parentId:[{ required: true, message: '请选择上级菜单'}],name: [{ required: true, message: "菜单名称不能为空", trigger: "blur" }]
})const formRef=ref(null)const initFormData=async(id)=>{const res=await requestUtil.get("sys/menu/"+id);form.value=res.data.sysMenu;
}watch(()=>props.dialogVisible,()=>{let id=props.id;tableData.value=props.tableData;if(id!=-1){initFormData(id)}else{form.value={id:-1,parentId:'',menuType:"M",icon:'',name:'',perms:'',component:'',orderNum:1}}})const emits=defineEmits(['update:modelValue','initMenuList'])const handleClose=()=>{emits('update:modelValue',false)}const handleConfirm=()=>{formRef.value.validate(async(valid)=>{if(valid){let result=await requestUtil.post("sys/menu/save",form.value);let data=result.data;if(data.code==200){ElMessage.success("执行成功!")formRef.value.resetFields();emits("initMenuList")handleClose();}else{ElMessage.error(data.msg);}}else{console.log("fail")}})}</script><style scoped></style>
菜单管理-删除功能实现
后端:
/*** 删除* @param id* @return*/@GetMapping("/delete/{id}")@PreAuthorize("hasAuthority('system:menu:delete')")public R delete(@PathVariable(value = "id")Long id){int count = sysMenuService.count(new QueryWrapper<SysMenu>().eq("parent_id", id));if(count>0){return R.error("请先删除子菜单!");}sysMenuService.removeById(id);return R.ok();}
前端:index.vue
const handleDelete=async (id)=>{const res=await requestUtil.get("sys/menu/delete/"+id)if(res.data.code==200){ElMessage({type: 'success',message: '执行成功!'})initMenuList();}else{ElMessage({type: 'error',message: res.data.msg,})}
}