1.3.1 • Published 2 years ago
koa-decorator-resolver v1.3.1
koa-decorator-resolver :zap:
这是一个可以在koa框架中使用装饰器的解决方案
// 测试基于以下版本,取自2022/8/2最新版本
{
"dependencies": {
"@types/jest": "^27.4.1",
"@types/request": "^2.48.8",
"chalk": "^2.4.1",
"console-writer": "^1.0.0-beta.1.1",
"crypto-js": "^4.1.1",
"exceljs": "^4.3.0",
"fs-extra": "^10.0.0",
"jest": "^27.5.1",
"jest-fast-config": "^1.0.3",
"jest-html-reporter": "^3.4.2",
"koa": "^2.13.4",
"koa-body": "^5.0.0",
"koa-bodyparser": "^4.3.0",
"koa-decorator-resolver": "^1.2.5",
"koa-router": "^12.0.0",
"koa-send": "^5.0.1",
"koa-websocket": "^7.0.0",
"lodash": "^4.17.21",
"moment": "^2.23.0",
"mysql2": "^2.3.3",
"request": "^2.88.2",
"require-all": "^3.0.0",
"sequelize": "^6.21.3",
"sqlite": "^4.0.23",
"sqlite3": "^5.0.11",
"ts-jest": "^27.1.4",
"ts-node": "^10.9.1",
"tsconfig-paths": "^4.0.0",
"typescript": "^4.7.4",
"uuid": "^8.3.2",
"xlsx": "^0.17.4"
},
"devDependencies": {
"@types/node": "^10.17.44",
"chai": "^4.3.4",
"copy": "^0.3.2",
"dotenv": "^10.0.0",
"dotenv-cli": "^6.0.0",
"mocha": "^9.1.3",
"nodemon": "^2.0.15",
"npm-run-all": "^4.1.5",
"nyc": "^15.1.0",
"ts-mocha": "^8.0.0"
}
}
安装
# 安装依赖
npm install koa-decorator-resolve
数据库支持
# 如果要用到mysql数据库,则需要安装驱动,如下:
npm install mysql2@2.x.x
# 如果要用到postgres数据库,则需要安装驱动,如下:
npm install pg@7.x.x pg-hstore@2.x.x
# 如果要用到sqlite数据库,则需要安装驱动,如下:
npm install sqlite@4.x.x sqlite3@5.x.x
完全依赖于Sequelize对数据库的支持,详细参照:https://www.sequelize.com.cn/
默认请求
不需要定义restful,单纯的通过定义类和函数的方式自动解析成restful请求,请求的Url格式是“类名/函数名”,默认解析成的是Post,如果想要解析成Get或其他请求可以通过自定义插件的方式生成相应装饰器来解决。
使用方法
- 文件: index.ts
// 这是koa工程的入口文件
import * as Koa from 'koa';
import * as Router from 'koa-router';
import { routeBinder } from 'koa-decorator-resolve';
import * as serviceModules from './serviceModules';
const router = new Router();
// 把模块注册在路由上
routeBinder(router,serviceModules);
app.use(router.routes());
app.listen(8080, () => {
console.log('server start on 8080');
});
- 文件: serviceModules.ts
// 这是注册在路由上的模块列表
export class serviceModule1 {
func1(data){
return {name:data.name + ' func1',msg:'success'}
}
func2(data){
return {name:data.name + ' func2',msg:'success'}
}
}
export class serviceModule2 {
func3(data){
return {name:data.name + ' func3',msg:'success'}
}
}
- 在前端发送几个请求
// 通过“类名/函数”就可以发送出去
axios.post('/serviceModule1/func1',{name:'m1f1'}).then(res=>{
console.log(res); // 结果 : {name:'m1f1 func1',msg'success'}
})
axios.post('/serviceModule2/func3',{name:'m2f3'}).then(res=>{
console.log(res); // 结果 : {name:'m2f3 func3',msg'success'}
})
定义插件
自定义装饰器,用来扩展一些功能
1. 定义装饰器和插件函数
- 文件: plugins.ts
// 这个文件用于配置和注册插件 import {injectorBuilder,Injector,ModuleFuncArgsType} from 'koa-decorator-resolve'; // 定义装饰器 type Option = {value:string} // Transfer是装饰器名 export const Transfer: Injector<Option> = injectorBuilder('Transfer'); // 配置装饰器 export const config = { Transfer: { // Transfer是装饰器名,一定要与injectorBuilder里参数中的名字一致 method: 'get', // 被装饰的方法反射的restful类型,默认是post,如果一个方法有多个装饰插件,则以第一个为主 before: { // 被装饰方法执行前,所执行的钩子方法 plugin: (ctx: any, option?: Option) => { return {'transfer-before':option.value}; }, replaceProps: true, // 是否把钩子方法的返回值替换给被装饰方法的第一个参数 }, after: { // 被装饰方法执行结束后,所执行的钩子方法 plugin: (res: any, ctx: any, option?: Option) => { return {'transfer-after':res} }, replaceProps: true, // 是否把钩子方法的返回值替换给请求返回值的body }, intercept: (func: (...args: ModuleFuncArgsType) => any, args: ModuleFuncArgsType, option?: Option) => { // 拦截器钩子,如果多个装饰器定义了拦截器钩子,只生效第一个 return func(...args) } } }
2. 注册插件
- 文件: index.ts
// the entry of project import * as Koa from 'koa'; import * as Router from 'koa-router'; import {routeBinder} from 'koa-decorator-resolve'; import * as serviceModules from './serviceModules'; import {config} from './plugins'; // 上一步定义的插件配置 const router = new Router(); // 通过注册路由方法的第三个参数注册插件 routeBinder(router,serviceModules,config); app.use(router.routes()); app.listen(8080, () => { console.log('server start on 8080'); });
3. 使用装饰器
- 文件: serviceModules.ts
// the restful modules
import {Transfer} from './plugins';
export class serviceModule {
// 用定义的装饰器直接注解方法
@Transfer({value:123})
func(data){
// 根据上面的逻辑,data的值 : {'transfer-before':123}
return 456
}
// 根据上面的逻辑,请求response的值 : {'transfer-after':456}
}
使用数据库
通过装饰器注入数据库实例
配置数据库
创建数据库连接实例
首先要创建数据库连接
- 文件: initTables.ts
// 引入sequelize的类型 import { STRING, INTEGER, BIGINT, DATE, TIME, DATEONLY, BOOLEAN, FLOAT, DOUBLE } from 'sequelize'; // 引入定义函数 import {defineTables} from 'koa-decorator-resolve'; // 以下是表模型的构造器 export const tablesStructure = { ACCESS:[{ id: { type: BIGINT, primaryKey: true, }, user_name: STRING(20), role: STRING(4), access: INTEGER, begin_date: DATE, end_date: DATE, }, {version: true}], USER:[{ user_id: { type: BIGINT, primaryKey: true, }, user_name: STRING(20), password: STRING(20) }, {version: true}], } // 表与表的关系模型可以定义在这里,基于sequelize的关系模型定义方式 export const relationCallback = (tables) => { tables.ACCESS.hasOne(tables.USER); // ... } export const { Database, // 装饰器 connect // 连接函数(下面参数useAlwaysConnection=true的场合需要在入口手动调用这个函数来创建连接) } = new defineTables(tablesStructure, relationCallback, { // 使用长连接,短连接是每次执行方法的时候连接一次,执行完释放连接 useAlwaysConnection: false, // 默认false // // 是否使用基础配置文件(基础配置方式请查看文档最后的说明) // useBaseConfig: false, // 默认true // 直接传入sequelize参数, 数组内为实例化sequelize的参数,详细参数用法,请参照sequelize库 sequelizeArgs: [ "default_db", "root", "root", { host: "localhost", port: 3306, dialect: "mysql", }, ] });
调用Sequelize数据库关系模型库
装饰器注入DB实例
// the restful modules import {OrmSequelize} from 'koa-decorator-resolve'; import {Database,tablesStructure} from './initTables'; export class serviceModule extends OrmSequelize<typeof tablesStructure> { @Database({ tables: ['ACCESS','USER'], relation: (tables) => { // 配合tables用于动态表关联 } }) async func(data){ return await this.db.tables.ACCESS.findAll() // 通过表模型直接操作数据库,参照Sequelize } }
开启事务
事务中,成功commit,异常rollback
// the restful modules import {OrmSequelize} from 'koa-decorator-resolve'; import {Database,tablesStructure} from './initTables'; export class serviceModule extends OrmSequelize<typeof tablesStructure> { @Sqlite({ useTransaction:true // 开启事务 }) async func(data){ return await this.db.tables.ACCESS.findAll() } }
文件配置数据库
通过配置文件配置数据库 1. useBaseConfig = true 使用基本配置
import {defineTables} from 'koa-decorator-resover'; export const {Database,connect} = new defineTables(tablesStructure, relationCallback, { // 是否使用基础配置文件 useBaseConfig: true, // 默认true // 注意: sequelizeArgs参数不能添加,否则会优先于sequelizeArgs对数据库的配置 });
# 在工程根目录下的.env文件中配置当前连接到哪个数据库,每个数据库有单独的配置文件,短连接的时候支持热替换(服务运行当中替换数据库)
[base] -- .env
| -- db.mysql.js
| -- db.postgres.js
# 以下是.env文件的格式
--------------------------------
| # 此时加载根目录下的db.mysql.js, 如果DB_DRIVER=postgres则会加载根目录下的db.postgres.js文件
| # DB_DRIVER=mysql
--------------------------------
// db.mysql.js 和 db.postgres.js的配置方法
module.exports = {
database: 'test_db',
username: 'test_user',
password: 'test_pw',
host: 'localhost',
port: 2001,
pool: { // 池化参数同样参照sequelize
max: 5,
min: 0,
acquire: 30000,
idle: 10000,
};
}
// db.sqlite.js文件的配置方法
module.exports = {
path: '/etc/test.db',
pool: { // 池化参数同样参照sequelize
max: 5,
min: 0,
acquire: 30000,
idle: 10000,
};
}
注意:基本配置只支持mysql、postgres、sqlite
- useBaseConfig = false 使用标准配置
import {defineTables} from 'koa-decorator-resover';
export const {Database,connect} = new defineTables(tablesStructure, relationCallback, {
// 是否使用基础配置文件
useBaseConfig: false, // 默认true
// 注意: sequelizeArgs参数不能添加,否则会优先于sequelizeArgs对数据库的配置
});
# 在工程根目录下只需要配置db.config.js文件
[base] -- db.config.js
// 默认标准配置,完全sequelize参数,不需要.env
module.exports = {
driver: "mysql",
options: {
mysql: [
"default_db",
"root",
"root",
{
host: "localhost",
port: 3306,
dialect: "mysql",
},
],
postgres: [
"default_db",
"postgres",
"password",
{
host: "localhost",
port: 2345,
dialect: "postgres",
},
],
sqlite: [
{
dialect: "sqlite",
storage: require("path").resolve("dbfile", "sqlite.db"),
},
],
},
};
注意:标准配置参数完全准寻sequelize参数,详细参照sequelize即可
方法、参数一览
- service.binder
- service.injector
- FservInjector - 服务注入器,注入插件,生成controller函数和method类别
- decorator.builder
- decorator.factory
- decorator.restful
- database.baseDefined (orm共通)
- database.configurator(orm共通)
- database.loader.sequelize.loader
- COrmLoader - sequelize加载器类
- TCombine - 类型继承
- TCombineAny - 类型继承,元素转换成any类型
- TCombineColumnModel - 继承Model并注入column字段的类型
- TTablesModelType - TablesStructure推断表结构
- TDefineModel - 简化sequelize.define方法
- TTablesStructureProps - 表结构callback中的参数
- TTablesStructure - 表结构定义
- TRelation - 关系函数
- TDatabaseOptions - Database装饰器参数
- TGlobalOptions - 全局参数,defineTables的第三个参数类型
- TDB - 注入的db的类型,通过this.db.获取
- IOrmSequelize - 用于Service模块db对象注入的继承类,实现this.db.tables.???自动提示,并能提示字段
- IOrmInterface - 模块接口
- TRewriteModelCtor - 解析重写Model方法类型
- TRewriteModelProps - 重写Model方法的类型
- TRewriteModelKeys - 重写Model方法名称的list
- TBaseConfigType - 配置文件内容格式接口类型
- database.loader.sequelize.binder
- type
1.2.0
2 years ago
1.2.5
2 years ago
1.2.4
2 years ago
1.2.3
2 years ago
1.3.1
2 years ago
1.2.2
2 years ago
1.3.0
2 years ago
1.2.1
2 years ago
1.1.1
2 years ago
1.1.0-alpha.1
2 years ago
1.1.0
2 years ago
1.0.7
2 years ago
1.0.6
2 years ago
1.0.5
2 years ago
1.0.4
2 years ago
1.0.3
2 years ago
1.0.2
2 years ago
1.0.1
2 years ago
1.0.0-beta.1.2
2 years ago
1.0.0-beta.1.1
2 years ago
1.0.0-beta.1.0
2 years ago