在上一篇中,我们已经完成了用户的增删改查操作,同时也创建了角色和权限相关的数据库表,而且也创建好了相关实体类。这次我们来完成角色和权限以及资源的相关操作。
1、角色管理
角色管理的操作和用户管理差不多,所以我们首先要完成后端的CRUD操作。
1.1 后端代码
1.1.1 持久化dao
在模块ihrm_system中的dao包下,创建RoleDao接口:
package com.zdw.ihrm.system.dao;
import com.zdw.ihrm.domain.system.Role;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface RoleDao extends JpaRepository<Role,String>, JpaSpecificationExecutor<Role> {
}
1.1.2 业务逻辑层service
在模块ihrm_system中的service包下,创建RoleService类:
package com.zdw.ihrm.system.service;
import com.ihrm.common.service.BaseService;
import com.ihrm.common.utils.IdWorker;
import com.zdw.ihrm.domain.system.Role;
import com.zdw.ihrm.system.dao.RoleDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class RoleService extends BaseService {
@Autowired
private RoleDao roleDao;
@Autowired
private IdWorker idWorker;
//保存角色
public void save(Role role){
role.setId(idWorker.nextId()+"");//设置id
roleDao.save(role);
}
//修改角色
public void update(Role role){
Role target = roleDao.getOne(role.getId());//根据角色id查询角色信息
target.setDescription(role.getDescription());
target.setName(role.getName());
roleDao.save(target);
}
//根据id查询角色
public Role findById(String id){
return roleDao.findById(id).get();
}
//查询所有角色列表
public List<Role> findAll(String companyId){
return roleDao.findAll(getSpec(companyId));//调用父类的方法构造根据企业id查询的条件,然后查询角色信息
}
//根据id删除角色
public void deleteById(String id){
roleDao.deleteById(id);
}
//查询角色列表(根据条件分页查询)
public Page<Role> findByPage(String companyId, int page, int size) {
return roleDao.findAll(getSpec(companyId), PageRequest.of(page-1, size));
}
}
1.1.3 业务逻辑层controller
在模块ihrm_system中的controller包下,创建RoleController类:
package com.zdw.ihrm.system.controller;
import com.ihrm.common.controller.BaseController;
import com.ihrm.common.entity.PageResult;
import com.ihrm.common.entity.Result;
import com.ihrm.common.entity.ResultCode;
import com.zdw.ihrm.domain.system.Role;
import com.zdw.ihrm.domain.system.response.RoleResult;
import com.zdw.ihrm.system.service.RoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@CrossOrigin//解决跨域问题
@RestController
@RequestMapping("sys")
public class RoleController extends BaseController {
@Autowired
private RoleService roleService;
//保存角色
@RequestMapping(value = "/role",method = RequestMethod.POST)
public Result save(@RequestBody Role role){
role.setCompanyId(parseCompanyId());//设置角色的公司id
roleService.save(role);
return new Result(ResultCode.SUCCESS);
}
//修改角色
@RequestMapping(value = "/role/{id}", method = RequestMethod.PUT)
public Result update(@PathVariable("id") String id,@RequestBody Role role){
roleService.update(role);
return Result.SUCCESS();
}
//根据id查询角色
@RequestMapping(value = "/role/{id}", method = RequestMethod.GET)
public Result findById(@PathVariable("id") String id){
Role role = roleService.findById(id);
RoleResult roleResult = new RoleResult(role);
return new Result(ResultCode.SUCCESS,role);
}
//查询所有角色
@RequestMapping(value="/role/list" ,method=RequestMethod.GET)
public Result findAll(){
List<Role> roleList = roleService.findAll(parseCompanyId());//根据公司id查询所有角色
return new Result(ResultCode.SUCCESS,roleList);
}
//根据id删除角色
@RequestMapping(value = "/role/{id}", method = RequestMethod.DELETE)
public Result deleteById(@PathVariable("id") String id){
roleService.deleteById(id);
return Result.SUCCESS();
}
//分页查询角色列表
@RequestMapping(value = "/role", method = RequestMethod.GET)
public Result findByPage(int page,int pagesize,Role role){
Page<Role> searchPage = roleService.findByPage(parseCompanyId(), page, pagesize);//根据公司id分页查询
PageResult<Role> pr = new PageResult(searchPage.getTotalElements(),searchPage.getContent());//构造分页结果对象
return new Result(ResultCode.SUCCESS,pr);
}
}
1.2 前端代码
1.2.1 创建用户管理模块
在前端工程的src目录下创建模块:module-settings ,并创建相关目录和文件
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnL5cjN0EDNxITM3ITMxkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
1.2.2 注册模块
在前端工程的main.js中,将刚才新建的模块注册:
import settings from '@/module-settings/' // 把角色管理模块注册到项目中
Vue.use(settings, store) // 把角色管理模块注册到项目中
1.2.3 API方法
在src/base下面创建role.js文件,里面编写相关API,请求后台方法:
import {createAPI} from '@/utils/request'
import { get } from 'https';
export const list = data => createAPI('/sys/role', 'get', data)
export const simple = data => createAPI('/sys/role/simple', 'get', data)
export const add = data => createAPI('/sys/role', 'post', data)
export const update = data => createAPI(`/sys/role/${data.id}`, 'put', data)
export const remove = data => createAPI(`/sys/role/${data.id}`, 'delete', data)
export const detail = data => createAPI(`/sys/role/${data.id}`, 'get', data)
export const assignPrem = data => createAPI(`/sys/role/assignPrem`, 'put', data)
export const findAll = data => createAPI(`/sys/role/list`,'get',data)
1.2.4 配置路由
module-setttings模块的router/index.js文件中,配置路由:
import Layout from '@/module-dashboard/pages/layout'
const _import = require('@/router/import_' + process.env.NODE_ENV)
export default [
{
root: true,
path: '/settings',
component: Layout,
redirect: 'noredirect',
name: 'settings',
meta: {
title: '公司设置管理',
icon: 'set'
},
children: [
{
path: 'index',
component: _import('settings/pages/index'),
name: 'settings-index',
meta: {title: '公司设置', icon: 'set', noCache: true}
}
]
}
]
1.2.5 注册路由
在module-settings模块根目录的index.js下面,注册路由:
// vue-router
import {asyncRouterMap} from '@/router'
import routerMaps from './router'
// vuex
import app from './store/app'
export default {
install(module, store) {
// 注册路由
asyncRouterMap.push(routerMaps[0])
// 注册状态管理
if (store !== undefined) {
// store.registerModule('app', app)
}
}
}
1.2.6 index.vue视图
pages下面的index.vue,是整个角色相关的列表:
<template>
<div class="settingBox">
<div class="settingTop">
<div class="setTop">
<el-tabs v-model="activeName" class="topLab">
<el-tab-pane name="role" class="rInfo">
<span slot="label">角色管理</span>
<component v-bind:is="roleList"></component>
</el-tab-pane>
<el-tab-pane name="companyInfo" class="rInfo">
<span slot="label">公司信息</span>
<component v-bind:is="roleList"></component>
</el-tab-pane>
</el-tabs>
</div>
</div>
</div>
</template>
<script>
import roleList from './../components/role-list'
export default {
name: 'settings-table-index',
components: { roleList },
data() {
return {
roleList: 'roleList',
activeName: 'role'
}
},
methods: {
}
}
</script>
<style>
.disabled .el-upload--picture-card {
display: none !important;
}
</style>
<style rel="stylesheet/scss" scoped>
@import './../../styles/variables.scss';
.settingBox {
padding: 20px;
background: #fff;
border-radius: 3px;
margin: 15px;
border: 1px solid #ebeef5;
.setTop {
color: #666;
//border-bottom: solid 1px #ccc;
line-height: 40px;
span {
display: inline-block;
padding: 0 25px;
font-size: 18px;
cursor: pointer;
}
.act {
color: $green;
border-bottom: solid 2px $green;
}
}
.settingCont {
background: #fff;
.tips {
background: #f4f4f4;
color: #666;
margin: 10px 0;
padding: 0 10px;
line-height: 30px;
i {
margin-right: 5px;
position: relative;
top: 1px;
color: $orange;
}
}
.formList {
}
.jurisdictionSet {
position: relative;
.addAdmin {
text-align: right;
line-height: 40px;
position: relative;
top: -5px;
i {
border: solid 1px #666;
color: #666;
display: inline-block;
margin-right: 5px;
border-radius: 3px;
padding: 0 3px 2px 3px;
line-height: 12px;
}
}
.jurTabLab {
line-height: 40px;
span {
display: inline-block;
margin-right: 20px;
cursor: pointer;
}
.act {
color: $green;
}
}
.jurContent {
.name-wrapper {
span {
display: inline-block;
border: solid 1px #ccc;
margin-right: 10px;
padding: 0 10px;
border-radius: 3px;
background: #f4f4f4;
}
}
}
}
}
.inputWt {
width: 400px;
}
}
</style>
1.2.7 角色列表组件
在index.vue中,用到了组件:
<span slot="label">角色管理</span>
<component v-bind:is="roleList"></component>
import roleList from './../components/role-list'
该组件位于components目录下的role-list.vue,具体如下:
<template>
<div class="boxInfo">
<!-- 表单内容 -->
<div class="formInfo">
<div>
<!-- 头部信息 -->
<div class="userInfo">
<el-button type="primary" size="mini" icon="el-icon-plus" @click="handlerAdd">新增角色</el-button>
<el-table :data="dataList" border fit highlight-current-row style="width:100%; margin-top:10px;">
<el-table-column type="index" :index="1" label="序号" width="150"> </el-table-column>
<el-table-column sortable prop="name" label="角色名" width="150"></el-table-column>
<el-table-column sortable prop="description" label="描述"></el-table-column>
<el-table-column fixed="right" label="操作" align="center" width="250">
<template slot-scope="scope">
<el-button @click="handlerPerm(scope.row)" type="text" size="small">分配权限</el-button>
<el-button @click="handleUpdate(scope.row)" type="text" size="small">修改</el-button>
<el-button @click="handleDelete(scope.row)" type="text" size="small">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<PageTool :paginationPage="requestParameters.page" :paginationPagesize="requestParameters.pagesize" :total="counts" @pageChange="handleCurrentChange" @pageSizeChange="handleSizeChange">
</PageTool>
</div>
</div>
</div>
</div>
<el-dialog title="编辑角色" :visible.sync="dialogFormVisible" style="hight:100px;line-height:1px">
<el-form :model="formData" label-width="90px" style="margin-top:20px">
<el-form-item label="角色名称">
<el-input v-model="formData.name" autocomplete="off" style="width:90%"></el-input>
</el-form-item>
<el-form-item label="角色描述">
<el-input v-model="formData.description" autocomplete="off" style="width:90%"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="saveOrUpdate">确 定</el-button>
</div>
</el-dialog>
<el-dialog :title="'为【'+formData.name+'】分配权限'" :visible.sync="permFormVisible" style="hight:100px;line-height:1px">
<el-tree
:data="treeData"
default-expand-all
show-checkbox
node-key="id"
ref="tree"
:check-strictly="true"
:default-checked-keys="checkNodes"
:props="{label:'name'}">
</el-tree>
<div slot="footer" class="dialog-footer">
<el-button @click="permFormVisible = false">取 消</el-button>
<el-button type="primary" @click="assignPrem">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {list,add,update,remove,detail,assignPrem} from "@/api/base/role"
import * as permApi from "@/api/base/permissions"
import commonApi from "@/utils/common"
import PageTool from './../../components/page/page-tool'
var _this = null
export default {
name: 'roleList',
components: {PageTool},
props: ['objId'],
data() {
return {
formData:{},
treeData:[],
checkNodes:[],
dialogFormVisible: false,
permFormVisible:false,
dataList:[],
counts:0,
requestParameters:{
page: 1,
pagesize: 10
}
}
},
methods: {
assignPrem() {
assignPrem({id:this.formData.id,permIds:this.$refs.tree.getCheckedKeys()}).then(res => {
this.$message({message:res.data.message,type:res.data.success?"success":"error"});
this.permFormVisible=false
})
},
handlerPerm(obj) {
detail({id:obj.id}).then(res=>{
this.formData = res.data.data
this.checkNodes = res.data.data.permIds
permApi.list({type:0,pid:null,enVisible:1}).then(res => {
this.treeData = commonApi.transformTozTreeFormat(res.data.data)
this.permFormVisible=true
})
})
},
handlerAdd() {
this.formData={}
this.dialogFormVisible = true
},
handleDelete(obj) {
this.$confirm(
`本次操作将删除${obj.name},删除后角色将不可恢复,您确认删除吗?`
).then(() => {
remove({id: obj.id}).then(res => {
this.$message({message:res.data.message,type:res.data.success?"success":"error"});
this.doQuery()
})
})
},
handleUpdate(obj) {
detail({id:obj.id}).then(res=>{
this.formData = res.data.data;
this.formData.id = obj.id;
this.dialogFormVisible = true
})
},
saveOrUpdate() {
if(this.formData.id == null || this.formData.id == undefined) {
this.save()
}else{
this.update();
}
},
update(){
update(this.formData).then(res=>{
this.$message({message:res.data.message,type:res.data.success?"success":"error"});
if(res.data.success){
this.formData={};
this.dialogFormVisible=false;
this.doQuery();
}
})
},
save() {
add(this.formData).then(res=>{
this.$message({message:res.data.message,type:res.data.success?"success":"error"});
if(res.data.success){
this.formData={};
this.dialogFormVisible=false;
this.doQuery();
}
})
},
// 获取详情
doQuery() {
list(this.requestParameters).then(res => {
this.dataList = res.data.data.rows
this.counts = res.data.data.total
})
},
// 每页显示信息条数
handleSizeChange(pageSize) {
this.requestParameters.pagesize = pageSize
if (this.requestParameters.page === 1) {
_this.doQuery(this.requestParameters)
}
},
// 进入某一页
handleCurrentChange(val) {
this.requestParameters.page = val
_this.doQuery()
},
},
// 挂载结束
mounted: function() {},
// 创建完毕状态
created: function() {
_this = this
this.doQuery()
},
// 组件更新
updated: function() {}
}
</script>
<style rel="stylesheet/scss" >
.el-collapse-item__arrow {
float: left;
}
.el-collapse-item {
position: relative;
// width: 80%;
// .el-collapse-item__header{width: 80%;}
.infoR {
position: absolute;
background: #fff;
display: inline-block;
width: 100px;
height: 35px;
line-height: 35px;
text-align: right;
right: -100px;
top: 0px;
}
}
// .el-input--medium {
// width: 80%;
// }
.linkage {
display: inline-block;
}
.textBotm {
vertical-align: text-bottom;
}
.navInfo {
height: auto;
font-size: 30px;
color: #333;
background-color: #e4e4e4;
text-align: center;
border-bottom: 1px solid #333;
}
.step {
position: fixed;
left: 220px;
top: 50%;
margin-top: -150px;
background: #fff;
z-index: 9;
}
</style>
<style rel="stylesheet/scss" scoped>
</style>
注意://import * as permApi from "@/api/base/permissions" 这一行注释掉,因为这里要用到权限管理模块,而我们还没创建该模块,如果不注释这行会报错。等完善了权限管理之后再放开。
1.3 前后端联合测试
上面都完成之后,我们可以启动后端的企业和权限微服务,启动前端项目,然后访问,看是否都正常,然后可以进行角色的增上改查操作了。
2、权限和资源管理
2.1 需求分析
完成权限(菜单,按钮(权限点),API接口)的基本操作
权限与菜单,菜单与按钮,菜单与API接口都是一对一关系。为了方便操作,在SAAS-HRM系统的表设计中,采用基于共享主键的形式实现一对一关系维护,并且数据库约束,一切的关系维护需要程序员在代码中实现。
2.2 后端实现
相关的实体类,我们在之前就已经实现啦,数据库表的创建也已经实现。
2.2.1 持久层Dao
这里需要在ihrm_system模块的dao包下,创建权限和资源相关的四个dao,分别如下:
package com.zdw.ihrm.system.dao;
import com.zdw.ihrm.domain.system.Permission;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface PermissionDao extends JpaRepository<Permission,String>, JpaSpecificationExecutor<Permission> {
}
package com.zdw.ihrm.system.dao;
import com.zdw.ihrm.domain.system.PermissionMenu;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface PermissionMenuDao extends JpaRepository<PermissionMenu,String>, JpaSpecificationExecutor<PermissionMenu> {
}
package com.zdw.ihrm.system.dao;
import com.zdw.ihrm.domain.system.PermissionPoint;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface PermissionPointDao extends JpaRepository<PermissionPoint,String>, JpaSpecificationExecutor<PermissionPoint> {
}
package com.zdw.ihrm.system.dao;
import com.zdw.ihrm.domain.system.PermissionApi;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface PermissionApiDao extends JpaRepository<PermissionApi,String>, JpaSpecificationExecutor<PermissionApi> {
}
2.2.2 业务逻辑service
在ihrm_system模块的service包下,创建权限和资源相关的PermissionService:
首先在模块ihrm_common中的util包下,添加两个工具类,用来把map转成bean,把bean转成map:
package com.ihrm.common.utils;
import org.springframework.cglib.beans.BeanMap;
import java.util.HashMap;
import java.util.Map;
public class BeanMapUtils {
/**
* 将对象属性转化为map结合
*/
public static <T> Map<String, Object> beanToMap(T bean) {
Map<String, Object> map = new HashMap<>();
if (bean != null) {
BeanMap beanMap = BeanMap.create(bean);
for (Object key : beanMap.keySet()) {
map.put(key+"", beanMap.get(key));
}
}
return map;
}
/**
* 将map集合中的数据转化为指定对象的同名属性中
*/
public static <T> T mapToBean(Map<String, Object> map,Class<T> clazz) throws Exception {
T bean = clazz.newInstance();
BeanMap beanMap = BeanMap.create(bean);
beanMap.putAll(map);
return bean;
}
}
package com.ihrm.common.utils;
public class PermissionConstants {
/**
* 权限类型 1为菜单 2为功能 3为API
*/
public static final int PY_MENU = 1;
public static final int PY_POINT = 2;
public static final int PY_API = 3;
}
PermissionService内容如下:
package com.zdw.ihrm.system.service;
import com.ihrm.common.entity.ResultCode;
import com.ihrm.common.exception.CommonException;
import com.ihrm.common.utils.BeanMapUtils;
import com.ihrm.common.utils.IdWorker;
import com.ihrm.common.utils.PermissionConstants;
import com.zdw.ihrm.domain.system.Permission;
import com.zdw.ihrm.domain.system.PermissionApi;
import com.zdw.ihrm.domain.system.PermissionMenu;
import com.zdw.ihrm.domain.system.PermissionPoint;
import com.zdw.ihrm.system.dao.PermissionApiDao;
import com.zdw.ihrm.system.dao.PermissionDao;
import com.zdw.ihrm.system.dao.PermissionMenuDao;
import com.zdw.ihrm.system.dao.PermissionPointDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@Service
@Transactional //涉及到多表操作,添加事务注解
public class PermissionService {
@Autowired
private PermissionDao permissionDao;
@Autowired
private PermissionMenuDao permissionMenuDao;
@Autowired
private PermissionPointDao permissionPointDao;
@Autowired
private PermissionApiDao permissionApiDao;
@Autowired
private IdWorker idWorker;
/**
* 保存权限及其资源
* @param map map里面有权限及其对应的资源信息
*/
public void save(Map<String,Object> map) throws Exception {
//设置主键的值
String id = idWorker.nextId()+"";
//调用工具类代码,把map中的值封装到Permission对象中
Permission permission = BeanMapUtils.mapToBean(map, Permission.class);
permission.setId(id);
Integer type = permission.getType();
//根据权限类型判断,把map封装到对应的资源对象中,并保存
switch (type){
case PermissionConstants.PY_MENU :
PermissionMenu menu = BeanMapUtils.mapToBean(map, PermissionMenu.class);
menu.setId(id);
permissionMenuDao.save(menu);
break ;
case PermissionConstants.PY_POINT :
PermissionPoint point = BeanMapUtils.mapToBean(map, PermissionPoint.class);
point.setId(id);
permissionPointDao.save(point);
break ;
case PermissionConstants.PY_API :
PermissionApi api = BeanMapUtils.mapToBean(map, PermissionApi.class);
api.setId(id);
permissionApiDao.save(api);
break ;
default:
throw new CommonException(ResultCode.FAIL);
}
//保存权限信息
permissionDao.save(permission);
}
//修改权限
public void update(Map<String,Object> map) throws Exception {
//调用工具类代码,把map中的值封装到Permission对象中
Permission perm = BeanMapUtils.mapToBean(map, Permission.class);
//根据id查询权限信息
Optional<Permission> optional = permissionDao.findById(perm.getId());
if(optional.isPresent()){
Permission permission = optional.get();
permission.setName(perm.getName());
permission.setCode(perm.getCode());
permission.setDescription(perm.getDescription());
permission.setEnVisible(perm.getEnVisible());
Integer type = permission.getType();
//根据权限类型判断,把map封装到对应的资源对象中,并保存
switch (type){
case PermissionConstants.PY_MENU :
PermissionMenu menu = BeanMapUtils.mapToBean(map, PermissionMenu.class);
menu.setId(permission.getId());
permissionMenuDao.save(menu);
break ;
case PermissionConstants.PY_POINT :
PermissionPoint point = BeanMapUtils.mapToBean(map, PermissionPoint.class);
point.setId(permission.getId());
permissionPointDao.save(point);
break ;
case PermissionConstants.PY_API :
PermissionApi api = BeanMapUtils.mapToBean(map, PermissionApi.class);
api.setId(permission.getId());
permissionApiDao.save(api);
break ;
default:
throw new CommonException(ResultCode.FAIL);
}
//保存权限信息
permissionDao.save(permission);
}else{
throw new CommonException((ResultCode.FAIL));
}
}
//根据id查询
public Map<String, Object> findById(String id) throws Exception {
Optional<Permission> optional = permissionDao.findById(id);
if(optional.isPresent()){
Permission permission = optional.get();
Integer type = permission.getType();
Object object = null;
if(type==PermissionConstants.PY_MENU){
object = permissionMenuDao.findById(id).get();
}else if(type==PermissionConstants.PY_POINT){
object = permissionPointDao.findById(id).get();
}else if(type==PermissionConstants.PY_API){
object = permissionApiDao.findById(id).get();
}else {
throw new CommonException(ResultCode.FAIL);
}
Map<String, Object> map = BeanMapUtils.beanToMap(object);//把资源对象转成map
//把权限相关的属性也放到map中
map.put("name",permission.getName());
map.put("type",permission.getType());
map.put("code",permission.getCode());
map.put("description",permission.getDescription());
map.put("pid",permission.getPid());
map.put("enVisible",permission.getEnVisible());
return map;
}else{
throw new CommonException(ResultCode.FAIL);
}
}
//根据id删除
public void deleteById(String id) throws CommonException {
//1.通过传递的权限id查询权限
Optional<Permission> optional = permissionDao.findById(id);
if(optional.isPresent()){
Permission permission = optional.get();
//删除权限信息
permissionDao.delete(permission);
//根据权限类型,查询对应的权限资源信息
Integer type = permission.getType();
if(type==PermissionConstants.PY_MENU){
permissionMenuDao.deleteById(id);
}else if(type==PermissionConstants.PY_POINT){
permissionPointDao.deleteById(id);
}else if(type==PermissionConstants.PY_API){
permissionApiDao.deleteById(id);
}else {
throw new CommonException(ResultCode.FAIL);
}
}else{
throw new CommonException(ResultCode.FAIL);
}
}
/**
* 4.根据条件查询全部,这些条件都封装到了参数map中
* type : 查询全部权限列表type:0:菜单 + 按钮(权限点) 1:菜单2:按钮(权限点)3:API接口
* enVisible : 0:查询所有saas平台的最高权限,1:查询企业的权限
* pid :父id
*/
public List<Permission> findAll(Map<String,Object> map){
//创建条件查询对象
Specification<Permission> specification = new Specification<Permission>() {
//动态拼装查询条件
@Override
public Predicate toPredicate(Root<Permission> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
List<Predicate> list = new ArrayList<>();
//根据父id查询
String pid = (String)map.get("pid");
if(!StringUtils.isEmpty(pid)){
list.add(criteriaBuilder.equal(root.get("pid").as(String.class),pid));
}
//根据enVisible查询
String enVisible = (String)map.get("enVisible");
if(!StringUtils.isEmpty(enVisible)){
list.add(criteriaBuilder.equal(root.get("enVisible").as(String.class),enVisible));
}
//根据type查询
String type = (String)map.get("type");
if(!StringUtils.isEmpty(type)){
CriteriaBuilder.In<Object> in = criteriaBuilder.in(root.get("type"));//创建根据type的in对象
if("0".equals(type)){//type=0,查询0:菜单 + 按钮(权限点),菜单是1,按钮是2
in.value(1).value(2);
}else{
in.value(Integer.valueOf(type));
}
}
return criteriaBuilder.and(list.toArray(new Predicate[list.size()]));
}
};
return permissionDao.findAll(specification);
}
}
2.2.3 控制器controller
在ihrm_system的controller包下,创建PermissionController:
package com.zdw.ihrm.system.controller;
import com.ihrm.common.entity.Result;
import com.ihrm.common.entity.ResultCode;
import com.ihrm.common.exception.CommonException;
import com.zdw.ihrm.domain.system.Permission;
import com.zdw.ihrm.system.service.PermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@CrossOrigin
@RestController
@RequestMapping("sys")
public class PermissionController {
@Autowired
private PermissionService permissionService;
//保存
@RequestMapping(value = "/permission", method = RequestMethod.POST)
public Result save(@RequestBody Map<String,Object> map) throws Exception {
permissionService.save(map);
return Result.SUCCESS();
}
//修改
@RequestMapping(value = "/permission/{id}", method = RequestMethod.PUT)
public Result update(@PathVariable("id") String id,@RequestBody Map<String,Object> map) throws Exception {
map.put("id",id);
permissionService.update(map);
return Result.SUCCESS();
}
//根据id查询
@RequestMapping(value = "/permission/{id}", method = RequestMethod.GET)
public Result findById(@PathVariable("id") String id) throws Exception {
Map<String, Object> map = permissionService.findById(id);
return new Result(ResultCode.SUCCESS,map);
}
//根据id删除
@RequestMapping(value = "/permission/{id}", method = RequestMethod.DELETE)
public Result deleteById(@PathVariable("id") String id) throws CommonException {
permissionService.deleteById(id);
return Result.SUCCESS();
}
//根据条件查询所有
@RequestMapping(value = "/permission", method = RequestMethod.GET)
public Result findAll(@RequestParam Map<String,Object> map){
List<Permission> list = permissionService.findAll(map);
return new Result(ResultCode.SUCCESS,list);
}
}
2.3 前端实现
2.3.1 创建权限相关模块
在前端代码的src下面创建模块:module-permissions
2.3.2 注册模块
在前端工程的main.js里面注册模块:
import permissions from '@/module-permissions/' // 把权限管理模块注册到项目中
Vue.use(permissions, store) // 把权限管理模块注册到项目中
注意:把module-settings模块的 role-list.vue中的注释掉的这行代码放开:
//import * as permApi from "@/api/base/permissions"
2.3.3 API方法
在src/base目录下新建permissions.js,里面封装请求后台的方法:
import {createAPI} from '@/utils/request'
const api = "/sys/permission"
export const list = data => createAPI(`${api}`, 'get', data)
export const add = data => createAPI(`${api}`, 'post', data)
export const update = data => createAPI(`${api}/${data.id}`, 'put', data)
export const remove = data => createAPI(`${api}/${data.id}`, 'delete', data)
export const detail = data => createAPI(`${api}/${data.id}`, 'get', data)
export const saveOrUpdate = data => {return data.id?update(data):add(data)}
2.3.4 路由配置
在module-permissions模块的router的index.js中配置路由:
import Layout from '@/module-dashboard/pages/layout'
const _import = require('@/router/import_' + process.env.NODE_ENV)
export default [
{
root: true,
path: '/permissions',
component: Layout,
redirect: 'noredirect',
name: 'permissions',
meta: {
title: '权限设置',
icon: 'set'
},
children: [
{
path: 'index',
component: _import('permissions/pages/index'),
name: 'permissions-index',
meta: {title: '权限设置', icon: 'set', noCache: true}
}
]
}
]
2.3.5 注册路由
在module-permissions模块根目录的index.js中注册路由:
// vue-router
import {asyncRouterMap} from '@/router'
import routerMaps from './router'
// vuex
import app from './store/app'
export default {
install(module, store) {
// 注册路由
asyncRouterMap.push(routerMaps[0])
// 注册状态管理
if (store !== undefined) {
// store.registerModule('app', app)
}
}
}
2.3.6 index.vue
<template>
<div class="dashboard-container">
<div class="app-container">
<el-card shadow="never">
<el-button class="filter-item fr" size="small" style="margin-left: 10px;" @click="handleCreate(null,1);setPid(1,'0')" type="primary" icon="el-icon-edit">添加菜单</el-button>
<el-table :data="dataList" fit style="width: 100%;" highlight-current-row>
<el-table-column fixed prop="name" label="菜单名称" width="200px">
<template slot-scope="scope">
<i :class="scope.row.type==1?'ivu-icon fa fa-folder-open-o fa-fw':'ivu-icon el-icon-view'"
:style="scope.row.type==1?'margin-left: 0px':'margin-left: 20px'"></i>
<span @click="show(scope.$index,scope.row.id)">{{scope.row.name}}</span>
</template>
</el-table-column>
<el-table-column fixed prop="code" label="权限标识" width="200"></el-table-column>
<el-table-column fixed prop="description" label="描述" width="200"></el-table-column>
<el-table-column fixed="right" label="操作">
<template slot-scope="scope">
<el-button v-if="scope.row.type==1" @click="handleCreate(null,2);setPid(2,scope.row.id)" type="text" size="small">添加权限点</el-button>
<el-button @click="handlerApiList(scope.row.id)" type="text" size="small">查看api权限</el-button>
<el-button @click="handleCreate(scope.row.id,scope.row.type);setPid(scope.row.type,scope.row.pid)" type="text" size="small">查看</el-button>
<el-button @click="handleDelete(scope.row.id)" type="text" size="small">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
<el-dialog title="编辑权限" :visible.sync="dialogFormVisible" style="hight:100px;line-height:1px">
<el-form :model="formData" label-width="90px" style="margin-top:20px">
<el-form-item label="权限名称">
<el-input v-model="formData.name" autocomplete="off" style="width:90%"></el-input>
</el-form-item>
<el-form-item label="权限标识">
<el-input v-model="formData.code" autocomplete="off" style="width:90%"></el-input>
</el-form-item>
<el-form-item label="权限描述">
<el-input v-model="formData.description" autocomplete="off" style="width:90%"></el-input>
</el-form-item>
<el-form-item label="企业可见">
<el-switch
v-model="formData.enVisible"
active-value="1"
inactive-value="0"
active-text="可见"
inactive-text="不可见">
</el-switch>
</el-form-item>
<div v-if="type==1">
<el-form-item label="菜单顺序">
<el-input v-model="formData.menuOrder" autocomplete="off" style="width:90%"></el-input>
</el-form-item>
<el-form-item label="菜单icon">
<el-input v-model="formData.menuIcon" autocomplete="off" style="width:90%"></el-input>
</el-form-item>
</div>
<div v-else-if="type==2">
<el-form-item label="按钮样式">
<el-input v-model="formData.pointClass" autocomplete="off" style="width:90%"></el-input>
</el-form-item>
<el-form-item label="按钮icon">
<el-input v-model="formData.pointIcon" autocomplete="off" style="width:90%"></el-input>
</el-form-item>
<el-form-item label="按钮状态">
<el-input v-model="formData.pointStatus" autocomplete="off" style="width:90%"></el-input>
</el-form-item>
</div>
<div v-else-if="type==3">
<el-form-item label="api请求地址">
<el-input v-model="formData.apiUrl" autocomplete="off" style="width:90%"></el-input>
</el-form-item>
<el-form-item label="api请求方式">
<el-input v-model="formData.apiMethod" autocomplete="off" style="width:90%"></el-input>
</el-form-item>
<el-form-item label="api类型">
<el-input v-model="formData.apiLevel" autocomplete="off" style="width:90%"></el-input>
</el-form-item>
</div>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="saveOrUpdate">确 定</el-button>
</div>
</el-dialog>
<el-dialog title="API权限列表" :visible.sync="apiDialogVisible" style="hight:400px;line-height:1px">
<el-button class="filter-item fr" size="small" style="margin-left: 10px;" @click="handleCreate(null,1);setPid(3,pid)" type="primary" icon="el-icon-edit">添加api权限</el-button>
<el-table :data="apiList" fit style="width: 100%;" max-height="250" >
<el-table-column fixed prop="name" label="菜单名称" width="120px"></el-table-column>
<el-table-column fixed prop="code" label="权限标识" width="200"></el-table-column>
<el-table-column fixed prop="description" label="描述" width="200"></el-table-column>
<el-table-column fixed="right" label="操作" width="200">
<template slot-scope="scope">
<el-button @click="handleCreate(scope.row.id,scope.row.type);setPid(scope.row.type,scope.row.pid)" type="text" size="small">查看</el-button>
<el-button @click="handleDelete(scope.row.id);handlerApiList(pid)" type="text" size="small">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-dialog>
</div>
</template>
<script>
import {saveOrUpdate,list,detail,remove} from "@/api/base/permissions"
export default {
name: 'permissions-table-index',
data() {
return {
MenuList: 'menuList',
type:0,
pid:"",
dialogFormVisible:false,
apiDialogVisible:false,
formData:{},
dataList:[],
apiList:[],
pointEnable:{}
}
},
methods: {
setPid(type,pid){
this.pid = pid;
this.type = type
},
handleCreate(id) {
if(id && id !=undefined) {
detail({id}).then(res => {
this.formData = res.data.data
this.dialogFormVisible=true
})
}else{
this.formData = {}
this.dialogFormVisible=true
}
},
saveOrUpdate() {
this.formData.type = this.type
this.formData.pid = this.pid
saveOrUpdate(this.formData).then(res => {
this.$message({message:res.data.message,type:res.data.success?"success":"error"});
if(res.data.success){
this.formData={};
this.dialogFormVisible=false;
}
if(this.type ==3){
this.handlerApiList(this.pid);
}else{
this.getList();
this.pointEnable = {}
}
})
},
handleDelete(id) {
remove({id}).then(res=> {
this.$message({message:res.data.message,type:res.data.success?"success":"error"});
if(res.data.success){
this.getList();
}
})
},
getList() {
list({type:1,pid:0}).then(res=> {
this.dataList = res.data.data
})
},
show(index,id) {
if(!this.pointEnable[id] == null || this.pointEnable[id]==undefined){
list({type:2,pid:id}).then(res=> {
if(res.data.data.length <=0) {
this.$message.error("无子权限")
}else{
for(var i = 0 ; i <res.data.data.length;i++) {
this.dataList.splice(index+1,0,res.data.data[i]);
}
this.pointEnable[id] = res.data.data.length;
}
})
}else{
this.dataList.splice(index+1,this.pointEnable[id])
this.pointEnable[id] = null;
}
},
handlerApiList(id) {
this.pid = id;
list({type:3,pid:id}).then(res=> {
this.apiList = res.data.data
this.apiDialogVisible = true;
})
}
},
created () {
this.getList();
}
}
</script>
<style rel="stylesheet/scss" scoped>
.alert {
margin: 10px 0px;
}
.pagination {
margin-top: 10px;
// text-align: right;
}
</style>
<style>
.el-table th {
background-color: #fafafa;
}
.el-table th.is-leaf {
border-bottom: 2px solid #e8e8e8;
}
.el-table__row i{ font-style:normal}
</style>
2.3.7 组件menu-list.vue
<template>
<el-table :data="dataList" fit style="width: 100%;" highlight-current-row>
<el-table-column fixed prop="name" label="菜单名称" width="200px">
<template slot-scope="scope">
<i :class="scope.row.type==1?'ivu-icon fa fa-folder-open-o fa-fw':'ivu-icon el-icon-view'"
:style="scope.row.type==1?'margin-left: 0px':'margin-left: 20px'"></i>
<span @click="show(scope.$index,scope.row.id)">{{scope.row.name}}</span>
</template>
</el-table-column>
<el-table-column fixed prop="code" label="权限标识" width="200"></el-table-column>
<el-table-column fixed prop="description" label="描述" width="200"></el-table-column>
<el-table-column fixed="right" label="操作">
<template slot-scope="scope">
<el-button @click="handleClick(scope.row)" type="text" size="small">查看</el-button>
<el-button type="text" size="small">编辑</el-button>
</template>
</el-table-column>
</el-table>
</template>
<script>
import {list} from "@/api/base/permissions"
import commonApi from "@/utils/common"
export default {
data () {
return {
dataList:[],
pointEnable:{}
}
},
created () {
this.getList();
},
methods: {
getList() {
list({type:1,pid:0}).then(res=> {
this.dataList = res.data.data
})
},
show(index,id) {
if(!this.pointEnable[id] == null || this.pointEnable[id]==undefined){
list({type:2,pid:id}).then(res=> {
for(var i = 0 ; i <res.data.data.length;i++) {
this.dataList.splice(index+1,0,res.data.data[i]);
}
this.pointEnable[id] = res.data.data.length;
})
}else{
this.dataList.splice(index+1,this.pointEnable[id])
this.pointEnable[id] = null;
}
}
}
}
</script>
3、分配角色
在用户管理列表中,操作列有分配角色按钮,我们可以点击进行角色的分配,但是该功能还没有完善。
3.1 前端代码实现
3.1.1 添加分配角色组件
在components目录下新增addRole.vue组件:
<template>
<div class="add-form">
<el-dialog title="分配角色" :visible.sync="roleFormVisible" style="height:300px">
<el-form :model="formBase" label-position="left" label-width="120px" style='margin-left:120px; width:500px;'>
<el-checkbox-group
v-model="checkedRoles">
<el-checkbox v-for="(item,index) in roles" :label="item.id" :key="index">{{item.name}}</el-checkbox>
</el-checkbox-group>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="createData">提交</el-button>
<el-button @click="roleFormVisible=false">取消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {findAll} from "@/api/base/role"
import {assignRoles,detail} from "@/api/base/users"
export default {
data () {
return {
roleFormVisible:false,
formBase:{},
checkedRoles:[],
data:[],
roles:[],
id:null
}
},
methods: {
toAssignPrem(id) {
detail({id:id}).then(res1 => {
this.checkedRoles = res1.data.data.roleIds;
console.log(this.checkedRoles)
findAll().then(res => {
this.id = id;
this.roles = res.data.data
console.log(this.roles)
this.roleFormVisible=true
})
})
},
createData() {
assignRoles({id:this.id,roleIds:this.checkedRoles}).then(res => {
this.$message({message:res.data.message,type:res.data.success?"success":"error"});
this.roleFormVisible=false
})
}
}
}
</script>
在index.vue中要引用该组件:
上面两个图中,红框标记的都是新增的内容。
当我们再次点击分配角色时,打开浏览器的F12,发现如下:
究竟是怎么回事呢?仔细查看组件中的代码,发现:
这个checkedRoles表示的是我们选中的角色id,但是当我们查询用户相关信息的时候, 我们之前的后台并没有查询用户相关的角色,所以在下面这行代码中,导致了this.checkedRoles的值是undefined,从而报错:
解决上面的问题,就需要我们在查询用户信息的时候,就应该查询出该用户对应的角色id的集合,修改UserController的findById方法:
//根据id查询用户
@RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
public Result findById(@PathVariable("id") String id){
User user = userService.findtById(id);
// 添加 roleIds (用户已经具有的角色id数组)
UserResult userResult = new UserResult(user);
return new Result(ResultCode.SUCCESS,userResult);
}
UserResult实体类定义在ihrm_common_model的包system.response下面,里面通过User对象,封装了角色id的集合:
package com.zdw.ihrm.domain.system.response;
import com.zdw.ihrm.domain.system.Role;
import com.zdw.ihrm.domain.system.User;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.BeanUtils;
import javax.persistence.Id;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Getter
@Setter
public class UserResult implements Serializable {
private static final long serialVersionUID = -1578313786206948978L;
@Id
private String id;//ID
private String mobile;//手机号码
private String username;//用户名称
private String password;//密码
private Integer enableState;//启用状态 0为禁用 1为启用
private Date createTime;//创建时间
private String companyId;//企业id
private String companyName;//企业名称
private String departmentId;//部门id
private Date timeOfEntry;//入职时间
private Integer formOfEmployment;//聘用形式
private String workNumber;//工号
private String formOfManagement;//管理形式
private String workingCity;//工作城市
private Date correctionTime;//转正时间
private Integer inServiceStatus;//在职状态 1.在职 2.离职
private String departmentName;//部门名称
private List<String> roleIds = new ArrayList<>();//用户对应的角色ID的集合
public UserResult(User user) {//通过传入用户,得到返回对象UserResult,
BeanUtils.copyProperties(user,this);
for (Role role : user.getRoles()) {//循环用户角色信息,把用户的角色对应的id添加到集合roleIds中
this.roleIds.add(role.getId());
}
}
}
重启后台,我们访问页面,点击分配角色就可以看到如下:
3.2 分配角色服务端代码实现
在UserController中,添加分配角色的控制器方法实现:
//分配角色
@RequestMapping(value = "/user/assignRoles", method = RequestMethod.PUT)
public Result save(@RequestBody Map<String,Object> map) {
//1.获取被分配的用户id
String userId = (String) map.get("id");
//2.获取到角色的id列表
List<String> roleIds = (List<String>) map.get("roleIds");
//3.调用service完成角色分配
userService.assignRoles(userId,roleIds);
return new Result(ResultCode.SUCCESS);
}
在UserService中,添加分配角色assignRoles方法:
@Autowired
private RoleDao roleDao;
/**
* 分配角色
*/
public void assignRoles(String userId,List<String> roleIds) {
//1.根据id查询用户
User user = userDao.findById(userId).get();
//2.设置用户的角色集合
Set<Role> roles = new HashSet<>();
for (String roleId : roleIds) {
Role role = roleDao.findById(roleId).get();
roles.add(role);
}
//设置用户和角色集合的关系
user.setRoles(roles);
//3.更新用户
userDao.save(user);
}
4、分配权限
在公司设置菜单,我们可以看到列表的操作列中,有分配权限的按钮:
4.1 前端实现
前端代码还是在之前的role-list.vue中已经实现啦。
吸取刚才分配角色的教训,我们可以查看module-settings模块的components目录下的role-list.vue中,有这样的代码:
这里就是点击分配权限展开的树型权限对话框,二且在点击分配权限会触发的方法如下:
能看出来,this.checkNodes就是我们的角色所拥有的权限的id集合,所以当在后台查询角色信息的时候,我们也需要查询权限id的集合信息,所以修改后台RoleController的findById方法:
//根据id查询角色
@RequestMapping(value = "/role/{id}", method = RequestMethod.GET)
public Result findById(@PathVariable("id") String id){
Role role = roleService.findById(id);
RoleResult roleResult = new RoleResult(role);
return new Result(ResultCode.SUCCESS,roleResult);
}
RoleResult类如下:
package com.zdw.ihrm.domain.system.response;
import com.zdw.ihrm.domain.system.Permission;
import com.zdw.ihrm.domain.system.Role;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.BeanUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
public class RoleResult implements Serializable {
private static final long serialVersionUID = 152410808770300424L;
private String id;//ID
private String name;//角色名
private String description;//说明
private String companyId;//企业id
private List<String> permIds = new ArrayList<>();//权限的集合
public RoleResult(Role role) {//构造方法,传入角色对象,构造RoleResult对象,得到角色的权限,然后添加到权限集合permIds中
BeanUtils.copyProperties(role,this);
for (Permission perm : role.getPermissions()) {
this.permIds.add(perm.getId());
}
}
}
4.2 后台实现
在RoleController新增分配权限的方法:
/**
* 分配权限
*/
@RequestMapping(value = "/role/assignPrem", method = RequestMethod.PUT)
public Result assignPrem(@RequestBody Map<String,Object> map) {
//1.获取被分配的角色的id
String roleId = (String) map.get("id");
//2.获取到权限的id列表
List<String> permIds = (List<String>) map.get("permIds");
//3.调用service完成权限分配
roleService.assignPerms(roleId,permIds);
return new Result(ResultCode.SUCCESS);
}
在RoleService新增分配权限的方法:
@Autowired
private PermissionDao permissionDao;
public void assignPerms(String roleId,List<String> permIds) {
//1.获取分配的角色对象
Role role = roleDao.findById(roleId).get();
//2.构造角色的权限集合
Set<Permission> perms = new HashSet<>();
for (String permId : permIds) {
Permission permission = permissionDao.findById(permId).get();
//需要根据父id和类型查询API权限列表
List<Permission> apiList = permissionDao.findByTypeAndPid(PermissionConstants.PY_API, permission.getId());
perms.addAll(apiList);//自定赋予API权限
perms.add(permission);//当前菜单或按钮的权
System.out.println(perms.size());
}
//3.设置角色和权限的关系
role.setPermissions(perms);
//4.更新角色
roleDao.save(role);
}
因为上面:permissionDao.findByTypeAndPid,所以需要在PermissionDao中添加该方法:
public interface PermissionDao extends JpaRepository<Permission,String>, JpaSpecificationExecutor<Permission> {
List<Permission> findByTypeAndPid(Integer type,String pid);
}
接下来就可以启动前后台进行测试啦。