Mask管理系统
后台程序手册
配置 src\config
Midway官方-多环境配置,一般只需要变更开发(local)或部署(prod)环境的配置文件对默认配置进行参数的覆盖。
- default 全部默认配置
- unittest 测试配置(不用管,暂时没用)
- local 和 prod 根据环境配置与默认配置差异的参数进行覆盖
核心 src\framework
封装的各种工具类函数,应用于整个程序。
项目结构
framework
├── cache 目录-缓存
├── constants 目录-常量属性值定义
├── datasource 目录-数据源
├── decorator 目录-装饰器定义
├── enums 目录-枚举类型定义
├── filter 目录-全局异常过滤器定义
├── middleware 目录-中间件定义
├── model 目录-模型对象定义
├── service 目录-服务函数定义
└── utils 目录-工具函数定义
装饰器定义 src\framework\decorator
方法装饰器
@PreAuthorize 用户身份授权认证校验
默认定义的接口都是不需要验证权限角色可以公开访问的,在定义接口访问的方法上面添加注解 @PreAuthorize
来控制访问权限。
超级管理员拥有所有权限,不受权限约束。
方法上使用注解示例:
/// 数据权限示例
@Get()
@PreAuthorize({ hasPermissions: ['system:user:query'] })
async getInfo(): Promise<String> { return "PreAuthorize Permissions OK!"}
// 只需含有其中一项权限 system:user:list 和 system:user:query
@PreAuthorize({ hasPermissions: ['system:user:list', 'system:user:query'] })
// 必须同时匹配含有其中权限 system:user:list 和 system:user:query
@PreAuthorize({ matchPermissions: ['system:user:list', 'system:user:query'] })
/// 角色权限示例
@Get()
@PreAuthorize({ hasRoles: ['user'] })
async getInfo(): Promise<String> { return "PreAuthorize Roles OK!"}
// 只需含有其中一项权限 user 和 admin
@PreAuthorize({ hasRoles: ['user', 'admin'] })
// 必须同时匹配含有其中角色 user 和 admin
@PreAuthorize({ matchRoles: ['user', 'admin'] })
/// 不需要验证权限角色,登录即可访问
@Get()
@PreAuthorize()
async getInfo(): Promise<String> { return "PreAuthorize OK!"}
@RepeatSubmit 防止表单重复提交
在定义接口访问方法上添加注解 @RepeatSubmit
来防止表单重复提交,限定单位时间内禁止相同内容重复请求。
方法上使用注解示例:
/// 防止重复提交示例
@Del('/refreshCache')
@RepeatSubmit(60)
async refreshCache(): Promise<String> { return "RepeatSubmit OK!" }
// 间隔时间(单位秒) 默认:5
@RepeatSubmit()
// 间隔时间设置60秒,同内容参数60秒内只能提交一次
@RepeatSubmit(60)
@RateLimit 限流
在定义接口访问方法上添加注解 @RateLimit
来限制单位时间内最多可以访问次数。
方法上使用注解示例:
/// 限流示例
@Get('/captchaImage')
@RateLimit({ time: 300, count: 60, limitType: LimitTypeEnum.IP })
async captchaImage(): Promise<Result> { return "RateLimit OK!" }
// 120秒内,最多请求60次,无类型时默认针对方法进行限制
@RateLimit({ time: 120, count: 60 })
// 300秒内,最多请求10次,指定类型针对访问者IP进行限制
@RateLimit({ time: 300, count: 10, limitType: LimitTypeEnum.IP })
// 720秒内,最多请求1000次,指定类型针对登录用户进行限制
@RateLimit({ time: 720, count: 1000, limitType: LimitTypeEnum.USER })
@OperLog 访问操作日志记录
在定义接口访问方法上添加注解 @OperLog
来对请求参数和响应数据进行记录。
请在用户身份授权认证校验后使用以便获取登录用户信息
方法上使用注解示例:
/// 访问操作日志记录示例
@Put()
@PreAuthorize()
@OperLog({
title: '编辑信息',
businessType: OperatorBusinessTypeEnum.UPDATE,
})
async edit(): Promise<Result> { return "RateLimit OK!" }
// 日志标题叫xx信息,日志类型为更新行为
@OperLog({ title: 'xx信息', businessType: OperatorBusinessTypeEnum.UPDATE })
// 日志标题叫xx信息,日志类型为授权行为,操作类型为其他
@OperLog({ title: 'xx信息', businessType: OperatorBusinessTypeEnum.GRANT, operatorType: OperatorTypeEnum.OTHER })
// 日志标题叫xx信息,日志类型为更新行为,操作类型默认为后台用户, 不记录请求参数,不记录响应参数
@OperLog({ title: 'xx信息', businessType: OperatorBusinessTypeEnum.UPDATE, isSaveRequestData: false, isSaveResponseData: false })
中间件定义 src\framework\middleware
洋葱模型,常用于验证日志等。
// 路由将忽略此中间件
ignore(ctx: Context): boolean {
return ctx.path === '/api/info'
}
// 匹配到的路由会执行此中间件
match(ctx: Context): boolean { return false }
全局异常过滤器定义 src\framework\filter
当请求结束时,存在异常保持返回数据前
工具函数定义 src\framework\utils
常用可控函数
服务模块开发接口 src\modules
对领域功能进行划分为不同的模块并实现其服务接口
xxx 目录-xxx模块
├── controller 目录-接口路由控制层
├── model 目录-数据对象模型层
├── repository 目录-CURD数据存储层
├── service 目录-业务逻辑服务层
└── ...
接口路由控制层 src\modules\xxx\controller
定义请求路由负责参数接收验证
数据对象模型层 src\modules\xxx\model
对数据库中表的字段属性进行对象模型建立
CURD数据存储层 src\modules\xxx\repository
repository
├── impl 目录-存储层接口实现
├── Ixxx.ts 文件-存储层接口定义
└── ...
对服务层处理后的数据进行存储,一般对各表间存储关系进行关联操作。
在使用时 ts
只能使用实现层的部分,所以定义接口后需要在 impl
目录中实现接口具体的函数行为。
数据库事务
在某些时候需要保证数据的一致性,对数据库的 SQL
操作。
常见场景:用户转账时,A用户-100 => B用户 100,中间发生异常时导致B没收到A的转账
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/decorator';
import { DynamicDataSource } from '../../../../framework/datasource/DynamicDataSource';
@Provide()
@Scope(ScopeEnum.Singleton)
export class xxxRepositoryImpl {
@Inject()
private db: DynamicDataSource;
/**
* 更新操作
*
* @returns true | false
*/
async update_xxx(): Promise<boolean> {
// 获取连接并创建新的queryRunner
const queryRunner = this.db.executeRunner();
// 对此事务执行一些操作
try {
// 开始事务
await queryRunner.startTransaction();
// sql语句
let sql_str = `UPDATE tbl_xxx SET xx = ? WHERE id= ?`;
const up_row1 = await queryRunner.query(sql_str, [101, "101"]);
const up_row2 = await queryRunner.query(sql_str, [102, "102"]);
if (parseInt(up_row1.affectedRows) <= 0 || parseInt(up_row2.affectedRows) <= 0) {
// 有错误做出回滚更改 后释放连接
await queryRunner.rollbackTransaction();
return false;
}
// 提交事务写入库 后释放连接
await queryRunner.commitTransaction();
return true;
} catch (err) {
// 有错误做出回滚更改 后释放连接
await queryRunner.rollbackTransaction();
throw new Error('服务数据异常');
} finally {
//释放连接
await queryRunner.release();
}
}
}
业务逻辑服务层 src\modules\xxx\service
service
├── impl 目录-服务层接口实现
├── Ixxx.ts 文件-服务层接口定义
└── ...
对请求参数进行处理逻辑操作的层面,会包含很多条件判断或调用其他依赖库等。
在使用时 ts
只能使用实现层的部分,所以定义接口后需要在 impl
目录中实现接口具体的函数行为。
队列任务处理 src\modules\xxx\processor
声明执行方法函数逻辑后,在调度任务中创建指定执行方法名称(test)。
@Processor('test')
export class TestProcessor implements IProcessor {
@Inject()
private ctx: Context;
async execute(options: ProcessorOptions): Promise<ProcessorData> {
const log = this.ctx.getLogger();
const ctxJob = this.ctx.job;
// 执行一次得到是直接得到传入的jobId
// 重复任务得到编码格式的jobId => repeat:编码Jobid:执行时间戳
log.info('原始jonId: %s | 当前jobId %s', options.jobId, ctxJob.id);
// 返回结果,用于记录执行结果
return options;
}
}
通用类型定义 src\typings
定义参数结构的类型
内部静态资源文件 src\assets
使用服务函数读取文件流
FileService.readAssetsFile(asserPath: string)
示例:
this.fileService.readAssetsFile('/template/excel/user_import_template.xlsx')
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanfejkf
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
excel下划线不显示怎么办
PHP中文网 06-23 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
photoshop蒙版画笔没反应怎么办
PHP中文网 06-24