后端
修改 UserController 添加对应的 CRUD 以及分批角色,删除用户要把对应的角色与用户的关系表数据也紧接着删除掉,代码如下
,如下编写的业务就是 RBAC 了,我就快速的贴代码了,重点是在后面的 Jwt + Security + OAuth2 的知识点
/**
* <p>
* 用户表 前端控制器
* </p>
*
* @author BNTang
* @since 2021-04-21
*/
("/service_auth/admin/user")
(tags = "用户组")
public class UserController {
private UserService userService;
private RoleService roleService;
/**
* <b>
* 获取管理用户,分页列表
* </b>
*/
(value = "获取管理用户,分页列表")
("/getUserList/{page}/{limit}")
public ResponseResult index( Long page, Long limit, User userQueryVo) {
IPage<User> pageParam = new Page<>(page, limit);
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
if (!StringUtils.isEmpty(userQueryVo.getOpenId())) {
queryWrapper.like("open_id", userQueryVo.getOpenId());
}
IPage<User> pageModel = userService.page(pageParam, queryWrapper);
return ResponseResult.ok()
.data("items", pageModel.getRecords())
.data("total", pageModel.getTotal());
}
/**
* <b>
* 新增管理用户
* </b>
*/
(value = "新增管理用户")
("/saveUser")
public ResponseResult save( User user) {
user.setPassword(Md5.encrypt(user.getPassword()));
userService.save(user);
return ResponseResult.ok();
}
/**
* <b>
* 修改管理用户
* </b>
*/
(value = "修改管理用户")
("/updateUser")
public ResponseResult updateById( User user) {
user.setPassword(Md5.encrypt(user.getPassword()));
userService.updateById(user);
return ResponseResult.ok();
}
/**
* <b>
* 删除管理用户
* </b>
*/
(value = "删除管理用户")
("/removeUser/{id}")
public ResponseResult remove( String id) {
userService.removeById(id);
return ResponseResult.ok();
}
/**
* <b>
* 批量删除用户
* </b>
*/
(value = "批量删除用户")
("/batchRemoveUser")
public ResponseResult batchRemove( List<String> idList) {
userService.removeByIds(idList);
return ResponseResult.ok();
}
/**
* <b>
* 根据用户id查询用户
* </b>
*/
(value = "根据用户id查询用户")
("/getUserById/{id}")
public ResponseResult getUser( String id) {
return ResponseResult.ok().data("user", userService.getById(id));
}
/**
* <b>
* 根据用户ID获取角色数据
* </b>
*/
(value = "根据用户ID获取角色数据")
("/getUserRoleData/{userId}")
public ResponseResult toAssign( String userId) {
return ResponseResult.ok().data(roleService.findRoleByUserId(userId));
}
/**
* <b>
* 根据用户ID分配用户角色
* </b>
*/
(value = "根据用户ID分配用户角色")
("/doAssignRole")
public ResponseResult doAssign( String userId, String[] roleId) {
roleService.saveUserRoleRelationShip(userId, roleId);
return ResponseResult.ok();
}
}
紧接着修改 RoleService
接口,添加如下方法
/**
* <p>
* 角色 服务类
* </p>
*
* @author BNTang
* @since 2021-04-21
*/
public interface RoleService extends IService<Role> {
/**
* <b>
* 根据用户ID获取角色数据
* </b>
*
* @param userId 用户ID
* @return 角色数据
*/
Map<String, Object> findRoleByUserId(String userId);
/**
* <b>
* 根据用户ID分配用户角色
* </b>
*
* @param userId 用户ID
* @param roleId 角色ID
*/
void saveUserRoleRelationShip(String userId, String[] roleId);
}
修改 RoleServiceImpl
/**
* <p>
* 角色 服务实现类
* </p>
*
* @author BNTang
* @since 2021-04-21
*/
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {
private UserRoleService userRoleService;
/**
* <b>
* 根据用户ID获取角色数据
* </b>
*/
public Map<String, Object> findRoleByUserId(String userId) {
// 1.查询出所有的角色
List<Role> allRoles = baseMapper.selectList(null);
// 2.当前用户选中的角色有哪些
QueryWrapper<UserRole> queryWrapper = new QueryWrapper<UserRole>()
.eq("user_id", userId)
.select("role_id");
// 获取到当前用户所在的角色关系
List<UserRole> userRoleList = userRoleService.list(queryWrapper);
// 取出所有的roleId 放到一个集合当中
List<String> roleIds = userRoleList.stream().map(UserRole::getRoleId).collect(Collectors.toList());
// 根据角色id,取出所有的角色对象
List<Role> userRoles = new ArrayList<>();
allRoles.forEach(role -> {
if (roleIds.contains(role.getId())) {
userRoles.add(role);
}
});
Map<String, Object> roleMap = new HashMap<>(2);
// 用户的角色
roleMap.put("assignRoles", userRoles);
// 所有的角色
roleMap.put("allRolesList", allRoles);
return roleMap;
}
/**
* <b>
* 根据用户ID分配用户角色
* </b>
*/
public void saveUserRoleRelationShip(String userId, String[] roleId) {
// 1.删除原来角色与用户之间的关系
userRoleService.remove(new QueryWrapper<UserRole>().eq("user_id", userId));
// 2.重新建立关系
List<UserRole> userRoleArrayList = Stream.of(roleId).map(role -> {
UserRole userRole = new UserRole();
userRole.setUserId(userId);
userRole.setRoleId(role);
return userRole;
}).collect(Collectors.toList());
// 3.批量保存关系
userRoleService.saveBatch(userRoleArrayList);
}
}
移动之前 server_video 微服务当中的 AppConfig,目的为了就是其它微服务如果也需要用到分页的配置和逻辑删除就不用再继续写冗余的配置文件内容了,我们的 server_auth 模块中有分页查询用户逻辑删除用户等等,但是 video 微服务当中也需要这样大家都是 server 的子服务就都会有对应的配置内容了
修改 gateway
配置 server_auth 的网关服务转发规则,修改 gateway 的 application.yml
id service-auth
uri lb //service-auth
predicates
Path=/service_auth/**
配置逻辑删除和属性的自动填充如下,每个实体类都自己加一下,不然你也可以按照报错自行排查问题
前端
修改路由文件 index.js 在路由当中添加路由
内容如下
{
path: '/auth',
component: Layout,
redirect: '/auth/user/list',
name: '权限管理',
meta: {title: '权限管理', icon: 'tree'},
children: [
{
path: 'user/list',
name: '用户管理',
component: () => import('@/views/video/auth/user/list'),
meta: {title: '用户管理'}
},
{
path: 'user/add',
name: '用户添加',
component: () => import('@/views/video/auth/user/form'),
meta: {title: '用户添加'},
hidden: true
},
{
path: 'user/update/:id',
name: '用户修改',
component: () => import('@/views/video/auth/user/form'),
meta: {title: '用户修改'},
hidden: true
},
{
path: 'user/role/:id',
name: '用户角色',
component: () => import('@/views/video/auth/user/roleForm'),
meta: {title: '用户角色'},
hidden: true
}
]
},
在 api 包中添加 user.js 编写请求方法内容如下
import request from '@/utils/request';
const api_name = '/service_auth/admin/user';
export default {
// 获取用户分页数据
getPageList(page, limit, searchObj) {
return request({
url: `${api_name}/getUserList/${page}/${limit}`,
method: 'get',
// url查询字符串或表单键值对
params: searchObj
});
},
// 根据用户id查询用户
getUserById(id) {
return request({
url: `${api_name}/getUserById/${id}`,
method: 'get'
});
},
// 保存用户
save(user) {
return request({
url: `${api_name}/saveUser`,
method: 'post',
data: user
});
},
// 更新用户
updateById(user) {
return request({
url: `${api_name}/updateUser`,
method: 'post',
data: user
});
},
// 根据用户id查询用户下角色信息
getAssign(userId) {
return request({
url: `${api_name}/getUserRoleData/${userId}`,
method: 'get'
});
},
// 保存用户角色信息
saveAssign(userId, roleId) {
return request({
url: `${api_name}/doAssignRole`,
method: 'post',
params: {userId, roleId}
});
},
// 删除用户
removeById(id) {
return request({
url: `${api_name}/removeUser/${id}`,
method: 'post'
});
},
// 批量删除用户
removeRows(idList) {
return request({
url: `${api_name}/batchRemoveUser`,
method: 'post',
data: idList
});
}
}
都是之前写过的,我直接贴代码如下,如下是 list.vue
的内容
<template>
<div class="app-container">
<!--查询表单-->
<el-form :inline="true" class="demo-form-inline">
<el-form-item>
<el-input v-model="searchObj.username" placeholder="用户名"/>
</el-form-item>
<el-button type="primary" icon="el-icon-search" @click="fetchData()">查询</el-button>
<el-button type="default" @click="resetData()">清空</el-button>
</el-form>
<!-- 工具条 -->
<div>
<el-button type="danger" size="mini" @click="addUser()">添加</el-button>
<el-button type="danger" size="mini" @click="removeRows()">批量删除</el-button>
</div>
<!--用户列表 -->
<el-table
v-loading="listLoading"
:data="list"
stripe
@selection-change="handleSelectionChange">
<el-table-column
type="selection"
width="55"/>
<el-table-column
label="序号"
width="70"
align="center">
<template slot-scope="scope">
{{ (page - 1) * limit + scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column prop="openId" label="用户名" align="center"/>
<el-table-column prop="nickName" label="用户昵称" align="center"/>
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<router-link :to="'/auth/user/role/'+scope.row.id">
<el-button type="success" size="mini">绑定角色</el-button>
</router-link>
<router-link :to="'/auth/user/update/'+scope.row.id">
<el-button type="primary" size="mini">修改</el-button>
</router-link>
<el-button type="danger" @click="removeDataById(scope.row.id)" size="mini">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<el-pagination
:current-page="page"
:total="total"
:page-size="limit"
:page-sizes="[5, 10, 20, 30, 40, 50, 100]"
layout="sizes, prev, pager, next, jumper, ->, total, slot"
@current-change="fetchData"
@size-change="changeSize"
/>
</div>
</template>
<script>
import user from '@/api/video/auth/user';
export default {
name: "list",
data() {
return {
// 数据是否正在加载
listLoading: true,
// 用户列表
list: null,
// 数据库中的总记录数
total: 0,
// 默认页码
page: 1,
// 每页记录数
limit: 10,
// 查询条件的表单对象
searchObj: {},
// 批量选择中选择的记录列表
multipleSelection: []
}
},
created() {
// 加载页面数据
this.fetchData();
},
methods: {
// 当页码发生改变的时候
changeSize(size) {
this.limit = size;
this.fetchData(1);
},
addUser() {
// 添加用户,跳转到添加路由
this.$router.push({path: '/auth/user/add'});
},
// 加载用户数据
fetchData(page = 1) {
this.page = page;
user.getPageList(this.page, this.limit, this.searchObj).then(
response => {
this.list = response.data.items;
this.total = response.data.total;
// 数据加载并绑定成功
this.listLoading = false;
}
);
},
// 重置查询表单
resetData() {
this.searchObj = {};
this.fetchData();
},
// 根据id删除数据
removeDataById(id) {
this.$confirm('此操作将永久删除该记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
// 点击确定,远程调用ajax
return user.removeById(id);
}).then((response) => {
// 重新加载列表
this.fetchData(this.page);
if (response.success) {
this.$message({
type: 'success',
message: response.message
})
}
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
})
},
// 当表格复选框选项发生变化的时候触发
handleSelectionChange(selection) {
this.multipleSelection = selection;
},
// 批量删除
removeRows() {
if (this.multipleSelection.length === 0) {
this.$message({
type: 'warning',
message: '请选择要删除的记录!'
})
return;
}
this.$confirm('此操作将永久删除该记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let idList = [];
this.multipleSelection.forEach(item => {
idList.push(item.id);
});
// 调用api
return user.removeRows(idList);
}).then((response) => {
this.fetchData(this.page)
if (response.success) {
this.$message({
type: 'success',
message: response.message
})
}
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
})
});
}
}
}
</script>
<style scoped>
</style>
添加与更新页面,form.vue
内容如下
<template>
<div class="app-container">
<el-form ref="user" :model="user" :rules="validateRules" label-width="120px">
<el-form-item label="用户名" prop="username">
<el-input v-model="user.openId"/>
</el-form-item>
<el-form-item label="用户昵称">
<el-input v-model="user.nickName"/>
</el-form-item>
<el-form-item v-if="!user.id" label="用户密码" prop="password">
<el-input v-model="user.password"/>
</el-form-item>
<el-form-item>
<el-button :disabled="saveBtnDisabled" type="primary" @click="saveOrUpdate">保存</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import userApi from '@/api/video/auth/user';
const defaultForm = {
openId: '',
nickName: '',
password: ''
}
const validatePass = (rule, value, callback) => {
if (value.length < 6) {
callback(new Error('密码不能小于6位'));
} else {
callback();
}
}
export default {
name: "form",
data() {
return {
user: defaultForm,
// 保存按钮是否禁用,
saveBtnDisabled: false,
validateRules: {
openId: [{required: true, trigger: 'blur', message: '用户名必须输入'}],
password: [{required: true, trigger: 'blur', validator: validatePass}]
}
}
},
// 监听器
watch: {
// 路由变化
$route(to, from) {
this.init();
}
},
// 生命周期方法(在路由切换,组件不变的情况下不会被调用)
created() {
this.init();
},
methods: {
// 表单初始化
init() {
if (this.$route.params && this.$route.params.id) {
const id = this.$route.params.id;
this.fetchDataById(id);
} else {
// 对象拓展运算符:拷贝对象,而不是赋值对象的引用
this.user = {defaultForm};
}
},
saveOrUpdate() {
this.$refs.user.validate(valid => {
if (valid) {
// 防止表单重复提交
this.saveBtnDisabled = true;
if (!this.user.id) {
this.saveData();
} else {
this.updateData();
}
}
});
},
// 新增用户
saveData() {
userApi.save(this.user).then(response => {
// debugger
if (response.success) {
this.$message({
type: 'success',
message: response.message
})
this.$router.push({path: '/auth/user/list'});
}
});
},
// 根据id更新记录
updateData() {
// teacher数据的获取
userApi.updateById(this.user).then(response => {
if (response.success) {
this.$message({
type: 'success',
message: response.message
});
this.$router.push({path: '/auth/user/list'});
}
});
},
// 根据id查询记录
fetchDataById(id) {
userApi.getUserById(id).then(response => {
this.user = response.data.user;
});
}
}
}
</script>
<style scoped>
</style>
绑定角色的选择页面,roleForm.vue
内容如下
<template>
<div class="app-container">
<el-checkbox :indeterminate="isIndeterminate"
v-model="checkAll"
@change="handleCheckAllChange">全选
</el-checkbox>
<div style="margin: 15px 0;"></div>
<el-checkbox-group v-model="checkedRoles" @change="handlecheckedRolesChange">
<el-checkbox v-for="role in roles"
:label="role.id"
:key="role.id">
{{ role.roleName }}
</el-checkbox>
</el-checkbox-group>
<br>
<el-button :disabled="saveBtnDisabled" type="primary" @click="update">保存</el-button>
</div>
</template>
<script>
import userApi from '@/api/video/auth/user';
export default {
name: "roleForm",
data() {
return {
// 是否全部选中
checkAll: false,
// 已选中列表
checkedRoles: [],
// 所有的角色
roles: [],
isIndeterminate: true,
userId: '',
// 保存按钮是否禁用
saveBtnDisabled: false
};
},
created() {
this.init();
},
methods: {
init() {
if (this.$route.params && this.$route.params.id) {
// 获取用户id
this.userId = this.$route.params.id;
// 查询用户
this.getById(this.userId);
}
},
getById(userId) {
userApi.getAssign(userId).then(response => {
// 获取用户角色
let jsonObj = response.data.assignRoles;
// 设置角色选中状态
this.checkedRoles = this.getJsonToList(jsonObj, "id");
this.roles = response.data.allRolesList;
})
},
// 把 json 数据转成 string 再转成对象,根据 Key 获取value数据
getJsonToList(json, key) {
// 把JSON字符串转成对象
let list = JSON.parse(JSON.stringify(json));
let strText = [];
// 遍历这个集合对象,获取key的值
for (let i = 0; i < list.length; i++) {
strText.push(list[i][key]);
}
return strText;
},
// 全选
handleCheckAllChange(val) {
this.checkedRoles = val ? this.roles : [];
this.isIndeterminate = false;
},
// 切换角色
handlecheckedRolesChange(value) {
let checkedCount = value.length;
this.checkAll = checkedCount === this.roles.length;
this.isIndeterminate = checkedCount > 0 && checkedCount < this.roles.length;
},
// 更新提交
update() {
// 防止表单重复提交
this.saveBtnDisabled = true;
let ids = this.checkedRoles.join(",");
//修改权限
userApi.saveAssign(this.userId, ids).then(response => {
if (response.success) {
this.$message({
type: 'success',
message: '保存成功'
});
this.$router.push({path: '/auth/user/list'});
}
});
}
}
};
</script>
自行启动项目进行测试我自己已经测试过了