权限组前端页面制作
权限组管理角色和菜单之间关系,操作员管理着用户和角色之间的关系。
英文的输入框要有个前缀,SpringSecurity里角色英文名需要加一个ROLE_的前缀
上代码
<div><div class="permissManaTool"><el-input placeholder="请输入角色英文名" v-model="role.name"><template slot="prepend">ROLE_</template></el-input><el-input placeholder="请输入角色中文名" v-model="role.nameZh"></el-input></div></div>
data(){return{role:{name:"",nameZh:"",}}}
添加按钮
<el-button type="primary" size="small" icon="el-icon-plus">添加角色</el-button>
添加输入框样式
.permissManaTool{display: flex;justify-content: flex-start;}.permissManaTool .el-input{width: 300px;margin-right: 8px;}
添加一个折叠面板
可以看出展开了第 2 个
留一个就够了
从数据库中获取所有的角色展示到页面,注意后端不仅要返回所有角色还要返回角色操作的菜单,角色能操作哪些资源也要返回
权限用户角色前后端对接
我们先来把所有角色查询出来,在前端展示出来
PermissController
@RestController
@RequestMapping("/system/basic/permiss")
public class PermissController {@AutowiredRoleService roleService;@GetMapping("/")public List<Role> getAllRoles(){return roleService.getAllRoles();}
}
RoleService
@Service
public class RoleService {@AutowiredRoleMapper roleMapper;public List<Role> getAllRoles(){return roleMapper.getAllRoles();}
}
RoleMapper
List<Role> getAllRoles();
RoleMapper.xml
<select id="getAllRoles" resultMap="BaseResultMap">select *from role;</select>
对接前端
<div style="margin-top: 15px;width: 720px"><el-collapse accordion><el-collapse-item :title="item.namezh" :name="index" v-for="(item,index) in roles" :key="index"><div>与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念;</div><div>在界面中一致:所有的元素和结构需保持一致,比如:设计样式、图标和文本、元素的位置等。</div></el-collapse-item></el-collapse></div>
展示效果
里面展示的内容应该是卡片
组件
<div><el-card class="box-card"><div slot="header" class="clearfix"><span>卡片名称</span><el-button style="float: right; padding: 3px 0" type="text">操作按钮</el-button></div><div v-for="o in 4" :key="o" class="text item">{{'列表内容 ' + o }}</div></el-card></div>
按钮样式改垃圾桶图标
<el-button style="float: right; padding: 3px 0;color: #ff2a0c" type="text" icon="el-icon-delete"></el-button>
权限组菜单树展示
查询所有菜单展示树形结构,需要在服务端做处理返回
查询所有的父子类菜单,自己关联自己三次形成一张表,
select m1.id as id1,m1.name as name1,m2.id as id2,m2.name as name2,m3.id as id3,m3.name as name3 from menu m1,menu m2,menu m3
where m1.id = m2.parentId and m2.id =m3.parentId and m3.enabled = true
ORDER BY m1.id,m2.id,m3.id```### PermissController
![在这里插入图片描述](https://img-blog.csdnimg.cn/8bf2e5f06fc647038f6066e6603dfa49.png)```java
@RestController
@RequestMapping("/system/basic/permiss")
public class PermissController {@AutowiredRoleService roleService;@AutowiredMenuService menuService;@GetMapping("/")public List<Role> getAllRoles(){return roleService.getAllRoles();}@PostMapping("/menus")public List<Menu> getAllMenus(){return menuService.getAllMenus();}
}
MenuService
@Service
public class MenuService {@AutowiredMenuMapper menuMapper;public RespBean getMenusByHrId() {return RespBean.ok("操作成功!",menuMapper.getMenusByHrId( ((Hr) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getId()));//Id从哪里来呢,前端传过来的信息是不可信,我们登录的用户信息保存在security,可以从Security里获取登录用户信息}/*** 获取所有的菜单角色 一对多 一个菜单项有多个角色* @return*/
// @Cacheablepublic List<Menu> getAllMenusWithRole(){return menuMapper.getAllMenusWithRole();}public List<Menu> getAllMenus() {return menuMapper.getAllMenus();}
}
MenuMapper
List<Menu> getAllMenus();
MenuMapper.xml
一个父菜单有多个子菜单,子菜单中还有菜单,三级菜单,直接查询
如果不确认多少级菜单可以用递归
<resultMap id="MenuWithChildren" type="com.xyg.pojo.Menu" extends="BaseResultMap"><id column="id1" property="id"></id><result column="name1" property="name"></result><collection property="children" ofType="com.xyg.pojo.Menu"><id column="id2" property="id"></id><result column="name2" property="name"></result><collection property="children" ofType="com.xyg.pojo.Menu"><id column="id3" property="id"></id><result column="name3" property="name"></result></collection></collection></resultMap><select id="getAllMenus" resultMap="MenuWithChildren">select m1.id as id1,m1.name as name1,m2.id as id2,m2.name as name2,m3.id as id3,m3.name as name3from menu m1,menu m2,menu m3where m1.id = m2.parentId and m2.id =m3.parentId and m3.enabled = trueORDER BY m1.id,m2.id,m3.id </select>
测试
前端
拷贝过来
定义对应的变量
添加一个折叠面板的点击事件
进行请求后端加载数据
change(name){if (name){this.getAllMenus();//点击有id就执行}},getAllMenus(){this.postRequest("/system/basic/permiss/menus").then(resp=>{if(resp){console.log(resp)this.allmenus=resp}})},
添加多选框
展示效果
菜单角色关系修改
角色全部展示出来了,还差个预选中的问题,就是选中角色可以操作哪写菜单
看数据库有个menu_role 菜单角色关联表 ,根据角色id查询可以操作哪写菜单,把角色可以操作菜单的id查询出来。
使用组件
写死数据看一默认选择效果
展示效果
把写死的数据服务端返回的数据动态的修改,可以根据角色rid查询菜单mid就行了
PermissController
@GetMapping("/mids/{rid}")public List<Integer> getMidsByTid(@PathVariable Integer rid){return menuService.getMidsByTid(rid);}
menuMapper
public List<Integer> getMidsByTid(Integer rid) {return menuMapper.getMidsByTid(rid);}
MenuMapper
List<Integer> getMidsByTid(Integer rid);
MenuMapper.xml
<select id="getMidsByTid" resultType="integer">select mid from menu_role where rid=#{rid}</select>
对接前端
需要name参数绑定角色id
分别通过default-expanded-keys和default-checked-keys设置默认展开和默认选中的节点。需要注意的是,此时必须设置node-key,其值为节点数据中的一个字段名,该字段在整棵树中是唯一的。
对接后端
点击事件chance,传参角色id,调用getSelectedMenus把角色id传过去,查询菜单的id赋值selectedMenus数组,tree进行默认预选中多选框
change(rid){if (rid){this.getAllMenus();//点击有id就执行this.getSelectedMenus(rid)}},getSelectedMenus(rid){this.getRequest("/system/basic/permiss/mids/"+rid).then(resp=>{if (resp){this.selectedMenus=resp}})},
菜单角色关系修改
可以引用通过ref=“tree” 获取该组件元素
getCheckedKeys 方法 若节点可被选择(即 show-checkbox 为 true),则返回目前被选中的节点的 key 所组成的数组,(leafOnly) 接收一个 boolean 类型的参数,若为 true 则仅返回被选中的叶子节点的 keys,默认值为 false
打印出来看一下
methods:{doUpdate(rid,index){console.log(rid)let tree = this.$refs.tree[index];//返回当前选中的元素let selectedKeys = tree.getCheckedKeys(true)//getCheckedKeys方法获取选中菜单节点的key值就是菜单id,若为true就返回叶子节点也就是子节点console.log(selectedKeys)},
编写修改操作后端接口
这里的更新操作有点麻烦,比如用户## 权限组前端页面制作
权限组管理角色和菜单之间关系,操作员管理着用户和角色之间的关系。英文的输入框要有个前缀,SpringSecurity里角色英文名需要加一个ROLE_的前缀上代码bash <div> <div class="permissManaTool"> <el-input placeholder="请输入角色英文名" v-model="role.name"> <template slot="prepend">ROLE_</template> </el-input> <el-input placeholder="请输入角色中文名" v-model="role.nameZh"></el-input> </div> </div>``````bash data(){ return{ role:{ name:"", nameZh:"", } } }
添加按钮bash <el-button type="primary" size="small" icon="el-icon-plus">添加角色</el-button>
添加输入框样式bash .permissManaTool{ display: flex; justify-content: flex-start; } .permissManaTool .el-input{ width: 300px; margin-right: 8px; }
添加一个折叠面板可以看出展开了第 2 个 留一个就够了从数据库中获取所有的角色展示到页面,注意后端不仅要返回所有角色还要返回角色操作的菜单,角色能操作哪些资源也要返回## 权限用户角色前后端对接我们先来把所有角色查询出来,在前端展示出来### PermissController java@RestController@RequestMapping("/system/basic/permiss")public class PermissController { @Autowired RoleService roleService; @GetMapping("/") public List<Role> getAllRoles(){ return roleService.getAllRoles(); }}
### RoleService java@Servicepublic class RoleService { @Autowired RoleMapper roleMapper; public List<Role> getAllRoles(){ return roleMapper.getAllRoles(); }}
### RoleMapperjava List<Role> getAllRoles();
### RoleMapper.xmlxml <select id="getAllRoles" resultMap="BaseResultMap"> select * from role; </select>
### 对接前端bash <div style="margin-top: 15px;width: 720px"> <el-collapse accordion> <el-collapse-item :title="item.namezh" :name="index" v-for="(item,index) in roles" :key="index"> <div>与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念;</div> <div>在界面中一致:所有的元素和结构需保持一致,比如:设计样式、图标和文本、元素的位置等。</div> </el-collapse-item> </el-collapse> </div>
展示效果里面展示的内容应该是卡片组件bash <div> <el-card class="box-card"> <div slot="header" class="clearfix"> <span>卡片名称</span> <el-button style="float: right; padding: 3px 0" type="text">操作按钮</el-button> </div> <div v-for="o in 4" :key="o" class="text item"> {{'列表内容 ' + o }} </div> </el-card> </div>
按钮样式改垃圾桶图标bash <el-button style="float: right; padding: 3px 0;color: #ff2a0c" type="text" icon="el-icon-delete"></el-button>
## 权限组菜单树展示查询所有菜单展示树形结构,需要在服务端做处理返回查询所有的父子类菜单,自己关联自己三次形成一张表,sqlselect m1.id as id1,m1.name as name1,m2.id as id2,m2.name as name2,m3.id as id3,m3.name as name3 from menu m1,menu m2,menu m3 where m1.id = m2.parentId and m2.id =m3.parentId and m3.enabled = true ORDER BY m1.id,m2.id,m3.id
### PermissControllerjava@RestController@RequestMapping("/system/basic/permiss")public class PermissController { @Autowired RoleService roleService; @Autowired MenuService menuService; @GetMapping("/") public List<Role> getAllRoles(){ return roleService.getAllRoles(); } @PostMapping("/menus") public List<Menu> getAllMenus(){ return menuService.getAllMenus(); }}
### MenuServicejava@Servicepublic class MenuService { @Autowired MenuMapper menuMapper; public RespBean getMenusByHrId() { return RespBean.ok("操作成功!",menuMapper.getMenusByHrId( ((Hr) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getId()));//Id从哪里来呢,前端传过来的信息是不可信,我们登录的用户信息保存在security,可以从Security里获取登录用户信息 } /** * 获取所有的菜单角色 一对多 一个菜单项有多个角色 * @return */// @Cacheable public List<Menu> getAllMenusWithRole(){ return menuMapper.getAllMenusWithRole(); } public List<Menu> getAllMenus() { return menuMapper.getAllMenus(); }}
### MenuMapperjava List<Menu> getAllMenus();
### MenuMapper.xml一个父菜单有多个子菜单,子菜单中还有菜单,三级菜单,直接查询如果不确认多少级菜单可以用递归xml <resultMap id="MenuWithChildren" type="com.xyg.pojo.Menu" extends="BaseResultMap"> <id column="id1" property="id"></id> <result column="name1" property="name"></result> <collection property="children" ofType="com.xyg.pojo.Menu"> <id column="id2" property="id"></id> <result column="name2" property="name"></result> <collection property="children" ofType="com.xyg.pojo.Menu"> <id column="id3" property="id"></id> <result column="name3" property="name"></result> </collection> </collection> </resultMap> <select id="getAllMenus" resultMap="MenuWithChildren"> select m1.id as id1,m1.name as name1,m2.id as id2,m2.name as name2,m3.id as id3,m3.name as name3 from menu m1,menu m2,menu m3 where m1.id = m2.parentId and m2.id =m3.parentId and m3.enabled = true ORDER BY m1.id,m2.id,m3.id </select>
测试## 前端拷贝过来定义对应的变量添加一个折叠面板的点击事件进行请求后端加载数据java change(name){ if (name){ this.getAllMenus();//点击有id就执行 } }, getAllMenus(){ this.postRequest("/system/basic/permiss/menus").then(resp=>{ if(resp){ console.log(resp) this.allmenus=resp } }) },
添加多选框展示效果## 菜单角色关系修改角色全部展示出来了,还差个预选中的问题,就是选中角色可以操作哪写菜单看数据库有个menu_role 菜单角色关联表 ,根据角色id查询可以操作哪写菜单,把角色可以操作菜单的id查询出来。使用组件写死数据看一默认选择效果展示效果把写死的数据服务端返回的数据动态的修改,可以根据角色rid查询菜单mid就行了### PermissControllerjava @GetMapping("/mids/{rid}") public List<Integer> getMidsByTid(@PathVariable Integer rid){ return menuService.getMidsByTid(rid); }
### menuMapperjava public List<Integer> getMidsByTid(Integer rid) { return menuMapper.getMidsByTid(rid); }
### MenuMapperjavaList<Integer> getMidsByTid(Integer rid);
MenuMapper.xmlxml <select id="getMidsByTid" resultType="integer"> select mid from menu_role where rid=#{rid} </select>
### 对接前端需要name参数绑定角色id分别通过default-expanded-keys和default-checked-keys设置默认展开和默认选中的节点。需要注意的是,此时必须设置node-key,其值为节点数据中的一个字段名,该字段在整棵树中是唯一的。对接后端点击事件chance,传参角色id,调用getSelectedMenus把角色id传过去,查询菜单的id赋值selectedMenus数组,tree进行默认预选中多选框java change(rid){ if (rid){ this.getAllMenus();//点击有id就执行 this.getSelectedMenus(rid) } }, getSelectedMenus(rid){ this.getRequest("/system/basic/permiss/mids/"+rid).then(resp=>{ if (resp){ this.selectedMenus=resp } }) },
### 菜单角色关系修改 可以引用通过ref=“tree” 获取该组件元素getCheckedKeys 方法 若节点可被选择(即 show-checkbox 为 true),则返回目前被选中的节点的 key 所组成的数组,(leafOnly) 接收一个 boolean 类型的参数,若为 true 则仅返回被选中的叶子节点的 keys,默认值为 false打印出来看一下java methods:{ doUpdate(rid,index){ console.log(rid) let tree = this.$refs.tree[index];//返回当前选中的元素 let selectedKeys = tree.getCheckedKeys(true)//getCheckedKeys方法获取选中菜单节点的key值就是菜单id,若为true就返回叶子节点也就是子节点 console.log(selectedKeys) },
### 编写修改操作后端接口这里的更新操作有点麻烦,比如用户勾选了几个,有取消了几个,有点麻烦后台要一个一个判断,这里就直接删除原有的,直接更新操作
PermissController
@PutMapping("/")public RespBean updateMenuRole(Integer rid,Integer[] mids){if(menuService.updateMenuRole(rid,mids)){return RespBean.ok("更新成功");}return RespBean.err("更新失败");}
MenuService
@Transactionalpublic boolean updateMenuRole(Integer rid, Integer[] mids) {menuRoleMapper.deleteById(rid);Integer result=menuRoleMapper.insertRecord(rid,mids);return result==mids.length;}
MenuRoleMapper
void deleteById(Integer rid);Integer insertRecord(@Param("rid") Integer rid,@Param("mids") Integer[] mids);
MenuRoleMapper.xml
<delete id="deleteById">delete from menu_role where rid=#{rid}</delete><insert id="insertRecord">insert into menu_role (mid,rid) values<foreach collection="mids" separator="," item="mid">(#{mid},#{rid})</foreach></insert>
对接前端
doUpdate(rid,index){let tree = this.$refs.tree[index];//返回当前选中的元素let selectedKeys = tree.getCheckedKeys(true)//getCheckedKeys方法获取选中菜单节点的key值就是菜单id,为true就获取子节点let url='/system/basic/permiss/?rid='+ridselectedKeys.forEach(key=>{url +='&mids='+key;console.log(url)})this.putRequest(url).then(resp=>{if(resp){this.getRolesAll()}})},
控制面板绑定一个属性
赋值-1,就是谁都不展示
activeName他的值是等于如图里name值,就会展示,等于-1就没有对应的值就不展示
doUpdate(rid,index){let tree = this.$refs.tree[index];//返回当前选中的元素let selectedKeys = tree.getCheckedKeys(true)//getCheckedKeys方法获取选中菜单节点的key值就是菜单id,为true就获取子节点let url='/system/basic/permiss/?rid='+ridselectedKeys.forEach(key=>{url +='&mids='+key;console.log(url)})this.putRequest(url).then(resp=>{if(resp){this.getRolesAll()this.activeName=-1}})},
取消修改一样就不展示
cancelUpdate(){this.activeName=-1},
权限组角色添加
PermissController
@PostMapping("/role")public RespBean addRole(@RequestBody Role role){if(roleService.addRole(role)==1){return RespBean.ok("添加成功");}return RespBean.err("添加失败");}
RoleService
因为SpringSecurity的角色需要以ROLE开头数据
public Integer addRole(Role role) {if(!role.getName().startsWith("ROLE_")){role.setName("ROLE"+role.getName());}return roleMapper.insert(role);}
使用逆向工程工具生成的mapper
添加角色接口对接前端
判断输入框数据是否为空,不为空就执行后端接口
权限组角色删除
PermissController
@DeleteMapping("/")public RespBean deletePositionByIds(Integer[] ids){if(positionsService.deletePositionsByIds(ids)==ids.length){return RespBean.ok("删除成功");}return RespBean.err("删除失败");}
PositionsService
public int deletePositionsByIds(Integer[] ids) {return positionMapper.deletePositionsByIds(ids);}
RoleMapper
删除对接前端