关于权限校验这块,笔者所在的供应链金融团队是这么去实现的,在保理业务中,会有很多个部门,比如市场部、财务部、风控部、董事会等等。每个部门里又有经办、审核、复核等等角色。所以在处理这类业务中的权限控制,需要将用户身上绑定一个按钮权限,比如说他是市场的经办角色,那么他就可以绑定市场经办这个角色的按钮码子上。前端这边除了要在我们楼上的基础上对列表返回的做对比之外,还有对用户的做进一步对比。这里的按钮也不能够像上面一样detail、modify这样去写,因为角色多了每个角色这么叫不好,更科学的应该是,整理成一份excel表,然后按照相应的按钮权限去配置相应的code(比如说 20001, 20002),然后根据这个去处理业务。
后端 eggjs中的三层模型(model-service-controller)model层是对数据库的相关表进行相应的映射和CRUD,service层是处理相关的业务逻辑,controller层是为相关的业务逻辑暴露接口。这三者层序渐进,一环扣一环。
Model 一些约定原则上,不允许对Model层SQL语句返回的结果进行相关操作,返回什么就是什么。
统一下数据返回的格式
语法错误 null
查不到数据 false
查到数据 JSON | Number
统一下model层文件类的通用方法
add: 新增
set: 更新
del: 删除(本系统由于数据需要,所以不会真的删除这条数据,而是取一哥isDelete字段去软删除它)
get: 获取单条数据,getById可简写成get, 若有查询条件, 按getByCondition
getAll: 获取多条记录,若有查询条件 按getAllByCondition
getAllLimit: 分页获取 若有查询条件 按getAllLimitByCondition
has: 若有查询条件, 按hasAttributes
目前本系统业务就用到这么多,其他的参见sequelize文档:
这样做的好处是,一些概念和语义更加清晰了,比如有个user.js,里面用add表示新增还是addUser表示新增好,我认为是前者,在user.js里面, 除了新增user用户,难不成还有别的新增,还能新增个鬼啊。除此之外,还方便了新生代农民工的复制粘贴,提高编码效率。
抄表字段真的好累啊试想一下这样一个场景,这个数据库有一百张表,每张表有100个字段,难道你真的要人肉去一个一个敲出来对应的数据库映射吗?那要敲到什么时候啊,人都快搞没了,我们可是新生代农民工唉,当然要跟上时代。 这里介绍一下egg-sequelize-auto, 它可以快速的将数据库的字段映射到你的代码中,减少很多工作量。
安装
npm i egg-sequelize-auto -g npm i mysql2 -g使用
egg-sequelize-auto -h 'your ip' -d 'your database' -u 'db user' -x 'db password' -e mysql -o 'project model path' -t 'table name'egg-sequelize-auto: https://www.npmjs.com/package/egg-sequelize-auto
sequelize连表查询的应用在表的关系中,有一对一,一对多,多对多。本系统一对多用的比较多,这里就以银行卡结合银行的的连表做个演示。
主要是三个地方,一个是引入相关表的Model, 第二个是字段初始化,第三个是通过associate方法建立联系,阉割后的示例代码如下:
'use strict'; const OrganizationModel = require('./organization'); module.exports = app => { const { logger, Sequelize, utils } = app; const { DataTypes, Model, Op } = Sequelize; class BankcardModel extends Model { static associate() { const { Organization } = app.model; BankcardModel.belongsTo(Organization, { foreignKey: 'bankId', targetKey: 'id', as: 'bank', }); } static async getAllLimit(name, prefix, bankId, { page = 0, limit = 10 }) { let where = {}; if (name) { where = { name: { [Op.like]: `%${name}%` } }; } if (prefix) { where.prefix = { [Op.like]: `%${prefix}%` }; } if (bankId) { where.bankId = bankId; } where.isDelete = 0; try { const offset = page < 1 ? 1 : (page - 1) * limit; const total = await this.count({ where }); const last = Math.ceil(total / limit); const list = total === 0 ? [] : await this.findAll({ raw: true, where, order: [ ['createTime', 'DESC'], ['updateTime', 'DESC'], ], offset, limit, attributes: [ 'id', 'name', 'prefix', 'bankId', [Sequelize.col('bank.name'), 'bankName'], ], include: { model: app.model.Organization, as: 'bank', attributes: [], }, }); logger.info(this.getAllLimit, page, limit, where, list); return { page, pageSize: limit, list, total, last, }; } catch (e) { logger.error(e); return false; } } } BankcardModel.init( { id: { type: DataTypes.UUID, defaultValue() { return utils.generator.generateUUID(); }, allowNull: false, primaryKey: true, }, name: { type: DataTypes.STRING(255), allowNull: true, }, prefix: { type: DataTypes.STRING(255), allowNull: true, }, bankId: { type: DataTypes.STRING(255), allowNull: false, references: { model: OrganizationModel, key: 'id', }, }, isDelete: { type: DataTypes.INTEGER(1), allowNull: true, defaultValue: 0, }, createTime: { type: DataTypes.INTEGER(10), allowNull: true, }, updateTime: { type: DataTypes.INTEGER(10), allowNull: true, }, }, { sequelize: app.model, tableName: 't_bankcard', } ); return BankcardModel; };sequelize中的表关系: https://sequelize.org/master/manual/assocs.html
Service