开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第9天,点击查看活动详情
前言
前面已经将用户模型与角色模型做了关联。但是用户接口添加及返回的信息还不包含角色,所以接下来我们将对用户接口进行改造。
改造接口
添加用户接口
添加用户的时候也要添加用户所选择的角色信息。所以我们在模型定义的文件中为模型添加方法,从而达到添加用户角色的目的。
添加用户角色的重点: 添加用户角色方法应当有两个操作: 1.添加用户的信息,2.在用户角色表添加用户的角色信息。但这里有一个问题,万一我们添加用户信息成功了,但添加用户的角色没有成功,添加用户信息是否是错误的、不应该的?所以下面的代码我用到了sequelize的事务的概念。这里要是有一个操作没有成功就会回滚(即所有操作都不做),要所有操作都成功才提交。
model/user.js
我们添加角色的第一步为添加用户,然后再读取传来的角色id数组,遍历后再添加到用户角色表
...
const UserModel=sequelize.define(...)
// 添加用户的方法
UsersModel.addUser = async function (data) {
// 首先,我们开始一个事务并将其保存到变量中
const t = await sequelize.transaction();
try {
// 然后,我们进行一些调用以将此事务作为参数传递:
// 添加用户
const user = await UsersModel.create(data);
// 遍历前端传来的用户角色id并添加到用户角色表
const users_roles = data.role_ids.map(function (role_id) {
return {
user_id: user.user_id,
role_id: role_id
};
});
await UsersRolesModel.bulkCreate(users_roles);
// 我们提交事务.
t.commit();
return true;
} catch (e) {
// 如果执行到达此行,则抛出错误.
// 我们回滚事务.
t.rollback();
return e.message;
}
};
...
然后我们修改一下校验规则文件(添加id数组的校验)和添加用户路由回调函数。
schema/user.js
const role_ids = joi.array().items(joi.number()).required();
// 添加用户接口
exports.add_user_schema = joi.object().keys({
username,
password,
role_ids
});
router_handler/user.js
...
const password = value.password;
// 加密
value.password = bcrypt.hashSync(password, 10);
// 将添加的用户设置为可用
value.status = 1;
// 添加用户角色,返回true或错误信息
const result = UsersModel.addUser(value);
result.then(function (ret) {
if (ret=== true) {
return res.send({
code: 0,
message: '新增成功',
data: ret
});
}
})
...
修改角色接口
修改角色方法与添加角色方法基本一致,要做到修改用户的角色时能够修改用户角色表的数据。
但前端传来了一个角色数组,我们得先从用户角色表中取出用户的角色数据将其转为数组,然后比较两个数组再对应进行修改。例如前端传来的角色数组为[1,2],表里例如所存字段信息的是
| user_id | role_id |
|---|---|
| 1 | 1 |
| 1 | 3 |
那么数据库所存的角色信息数组就是[1,3],我们应当将3的角色删掉然后添加2的角色。
那么我们得要获得两个数组的差集。我们用到的是数组的filter方法过滤出交集
// 测试!!!
let arr1 = [1,2,3];
let arr2 = [1,3,4];
let arr3=arr1.filter(function (v) {
return arr2.indexOf(v) === -1;
});
let arr4 = arr2.filter(function (v) {
return arr1.indexOf(v) === -1;
});
console.log(arr3); // 得到[2]为添加的角色数组
console.log(arr4); // 得到[4]为数据库中要删除的角色数组
我们在utils文件夹下新建一个工具类来定义此数组方法。
utils/tools.js
/**
* 获取两个数组差集
* @param arr1
* @param arr2
* @returns {*[]}
*/
const minustArr = function (arr1 = [], arr2 = []) {
return arr1.filter(function (v) {
return arr2.indexOf(v) === -1;
});
};
// 导出工具方法
module.exports = {
minustArr
};
那么我们就可以进行修改角色方法的编写了
model/user.js
const tools=require('../utils/tools')
...
UsersModel.addUser...
UsersModel.updateUser = async function (user_id, data) {
const t = await sequelize.transaction();
try {
// 获得修改时间
data.update_time = new Date();
// 先更新用户
await UsersModel.update(data, {
where: {
user_id: user_id
}
});
// 再得到用户角色表中此用户的角色id
const users_roles = await UsersRolesModel.findAll({
where: { user_id: user_id }
});
// 将表中获得的角色id转换为数组
const role_ids = users_roles.map(function (item) {
return item.role_id;
});
// 新加的角色加到用户角色表中
const add_role_ids = tools.minustArr(data.role_ids, role_ids);
const add_users_roles = add_role_ids.map(function (role_id) {
return { user_id: user_id, role_id: role_id };
});
await UsersRolesModel.bulkCreate(add_users_roles);
// 删除的角色从用户角色表删除
const del_role_ids = tools.minustArr(role_ids, data.role_ids);
if (del_role_ids && del_role_ids.length > 0) {
await UsersRolesModel.destroy({
where: {
user_id: user_id,
role_id: del_role_ids
}
});
}
t.commit();
return true;
} catch (e) {
t.rollback();
return e.message;
}
};
...
然后同样对校验字段和路由回调函数进行修改。
schema/user.js
// 更新用户接口
exports.update_user_schema = joi.object().keys({
username: joi.string().alphanum().min(1).max(10),
status,
nickname,
email,
role_ids // 角色id数组
});
router_handler/user.js
const result = UsersModel.updateUser(user_id, req.body);
result.then(function (ret) {
if (ret === true) {
return res.send({
code: 0,
message: '修改成功',
data: ret
});
}
})
删除用户接口
删除用户只需要删除对应用户表的用户和用户角色表该用户id对应的表记录即可
model/user.js
...
UsersModel.delUser = async function (user_ids) {
const t = await sequelize.transaction();
try {
await UsersModel.destroy({
where: { user_id: user_ids }
});
await UsersRolesModel.destroy({
where: { user_id: user_ids }
});
t.commit();
return true;
} catch (e) {
t.rollback();
return false;
}
};
...
然后修改回调函数
router_handler/user.js
...
const user_ids = req.body.user_id;
UsersModel.delUser(user_ids || []).then(function (user) {
if (user !== true) {
return res.send({
code: 1,
message: '删除失败',
data: null
});
}
...
获取用户列表和根据id获取用户信息接口
都只需要在获取信息的时候添加上角色信息。在sequelize的关联模块中有include参数可以执行预先加载与查询实例一起带回关联的数据。
先导入角色用户模型
router_handler/user.js
const RolesModel = require('../model/roles');
/**
* 获取用户列表
*/
...
UsersModel.findAndCountAll({
attributes: { exclude: ['password'] },
include:[{model:RolesModel}], // 预先加载角色模型
offset: offset,
limit: limit,
where: where
}).then(...)
/**
* 根据id获取用户信息接口
*/
...
UsersModel.findOne({
attributes: { exclude: ['password'] },
include: [{ model: RolesModel }], // 预先加载角色模型
where: {
user_id: user_id
}
}).then(...)
测试
因为暂时还没有角色,所以我们先测试获取用户列表
获取用户列表
可以看到带上了roles字段,说明成功了。下文我们将添加角色信息,到时候看得更加直观。