UNPKG

anchundan

Version:
438 lines (392 loc) 12.3 kB
### 鹌鹑蛋 🥚 使用方式 和 eggjs 类似 区别在于插件的设置,简化了插件的配置和使用。 进程管理交给 pm2 .管理 如果你具备一些eggjs ,koa ,的开发经验,以及对sequelize 有相对的了解,可以很轻松的看懂这个份```readme``` 这个框架诞生的目的是为了简化初始化的过程,精简eggjs ```javascript npm install anchundan or yarn add anchundan or yarn add https://github.com/shinku/anchundan ``` [toc] ### 项目初始化 ``` anchundan-init ``` 目录 ├─ src │ ├─ app │ ├─ config │ │ ├─ config.base.js │ │ ├─ config.dev.js │ │ ├─ config.pro.js │ │ ├─ config.uat.js │ ├─ middleware │ ├─ modules │ ├─ plugins │ ├─ routers │ │ ├─ index.js │ ├─ static │ ├─ controller │ └─ index.js ├─ application.dev.config.js ├─ application.uat.config.js ├─ application.pro.config.js 启动应用: ``` yarn start or yarn start_uat or yarn start_prod ``` #### 配置文件 /config/config.base.js 这个文件存储基本的配置信息。 其次,dev对应开发环境。uat 对应预发,pro对应 生产环境的配置 配置的相关过程跟eggjs类似。 application.{env}.config.js 对应的是pm2 启动项的配置 #### 监听端口设置 ```javascript /src/config/config.base.js module.exports = { port:9000 } ``` #### 新建 controller ```javascript //方式与eggjs 一致 /src/controller/index.js const Controller = require('anchundan').Controller; class Index extends Controller{ async start(ctx){ this.send("hello~",{ "Content-Type":"text/plain" }); } } module.exports = Index; ``` 同时 ```anchundan.Controller ```内置了其他一些方法,方便某些场景的调用 + [get/set] context 获取/设置 当前的上下文对象,context 是一个KOA 的context 对象。 ```javascript this.context.set("X-PATH",this.context.path); ``` + send(content,option?) ```javascript this.send("hello~") ``` + [get] request 获取当前的request对象,post的场景下使用 ```javascript /// postdata  为 : {userid:"123"} let {userid} = this.request.body; ``` + [get] query 获取当前的 query 对象,get 的场景下使用 ```javascript /// postdata  为 : {userid:"123"} let {userid} = this.query; ``` + [get] params 路由格式类似为 /path/:id/:pagenum 使用 ```javascript /// postdata  为 : {userid:"123"} let {id,pagenum} = this.params; ``` + [get] services 获取当前应用的所有service 组件时使用 ```javascript let userdata = this.services.userdata; let result = await userdata.find({where:{userid}}); ``` + [get] plugins 获取当前应用的所有application 插件 #### 路由 ```javascript //结合controller /src/routers/index.js module.exports = (router,app)=>{ let { index, } = app.controllers; router.get(vpath+'/test',index.start); router.post(vpath+'/test',index.start); } ``` #### 路由增加中间件 ```javascript const mid = async (ctx,next)=>{ //do something await next(); } module.exports = (router,app)=>{ let { index, } = app.controllers; router.get(vpath+'/test',mid,index.start); router.post(vpath+'/test',mid,index.start); } ``` #### 中间件 +  创建中间件 ```javascript /src/middleware/apiproxy.js module.exports = (config,app)=>{ return async (ctx,next)=>{ //console.log("api proxy"); //dosomething //这里可以使用 app 参数获取到 controllers,services,plugins let {index} = app.controllers; let {plugins,services} = app; // index.context = ctx; await index.start(); await next(); } } ``` +  配置中间件 与eggjs 一致 ```javascript /src/config/config.base.js module.exports = { port:9000, middlewares:['apiproxy'], apiproxy:{ abc:"test" } } ``` #### 插件 + context 插件,挂载在context上下文 + 插件可以是 一个Object 或者一个function + PS:如果想通过插件访问到 具体的 context 或者application 内部数据,定义函数插件的时候用 `function(){}`定义,而不`() =>{}` ```javascript /src/plugins/sendresult/context.js //使用 function abc(){}  的方式新建函数,可以直接使用this 操作当前上下文 //使用箭头函数无法操作,application 插件类似。 module.exports = function (result){ this.body = result; this.set('Content-Type',"html/text"); } ``` + application 插件,挂载在application ```javascript /src/plugins/getfile/application.js //使用 function abc(){}  的方式新建函数,可以直接使用this 操作当前上下文 //使用箭头函数无法操作,application 插件类似。 module.exports = function (filepath){ return fs.readFileSync(filepath); } ``` - sample ```javascript //方式与eggjs 一致 /src/controller/index.js const Controller = require('anchundan').Controller; class Index extends Controller{ async start(ctx){ let file = this.app.plugins.getfile("/static/index.html"); this.context.plugins.sendresult(file); } } module.exports = Index; ``` #### sequelize anchundan 默认集成 sequelize,并在此基础上做了封装 + 初始化sequelize 在配置文件中,配置sequelize 关键字 ``` /src/config/config.base.js let config ={ sequelize:{ /** 基本配置*/ host:"localhost", username:"root", password:"**********", database:'DATA_BASE', dialect:"mysql", port:'3306', /**其他配置 */ options:{ //开启连接池 pool:{ //开启10个连接池 max: 10, idle: 30000 } } } } module.exports = config; ``` + 新建module ```javascript /src/modules/user.js const { Sequelize, DataTypes, Model } = require('sequelize'); const SequelizeOperate = require('anchundan').Sequelize; class users extends SequelizeOperate{ init(){ this.define('users',{ id:{ type:DataTypes.INTEGER, autoIncrement:true, primaryKey:true, allowNull: false, comment:"自增ID" }, userid:{ type:DataTypes.STRING(50), comment:"用户ID", allowNull: false, }, pwd:{ type:DataTypes.STRING(100), comment:"密码", allowNull: false, }, },{ comment:"是否有效", //增加索引 indexes:[{ unique:true, fields:['userid'] }] }); this.sync({force:false}).then(_res=>{}) } } module.exports = users ``` 该module 将以插件的形式挂载在application中,如下方式可直接使用,已封装了常规的sequelize 方法 ```find,count,update,query``` ```javascript // 在controller 中使用: let userdatatable =  this.plugins.sequelize.DB.users; let result = await userdatatable.find({where:{userid}}); result = await userdatatable.count({where:{userid}}); result = await userdatatable.query("select * from users"); ``` + module 结合services 使用 ```javascript /src/services/users.js const ADbService = require("anchundan").Services; class users extends ADbService{ constructor(app) { super(app); //绑定 users module this.tableName = 'users'; } getInfo(userid,...params){ return this.table.find({where:{userid}},...params) } } module.exports = users; ``` 之后在controller 中使用services ```javascript let users = this.services.users; let data = await users.getInfo(userid); ``` 通过 ```service``` 操作数据的方式更加安全,也存在更好的可读性,并且可以集成除了操作数据库意外的其他方法。 通过 ```this.plugins.sequelize.DB[{MODULENAME}]``` 的方式直接操作sequelize对象,可以更加灵活的操作数据 #### 数据库事务 ```javascript 以在controller中使用为例子 //假设建两个 module,users 和infos,需要通过数据库事务处理数据,并已经通过anchuandan.Services 实例做了绑定 let users =this.services.users; let infos = this.service.infos; let sequelize = this.plugins.sequelize.sequelize; //以plugins.sequelize.sequelize; 获取数据库链接实例 let transaction = await sequelize.transaction(); try{ await users.addData({userid},{transaction}); await infos.addData({userid},{transaction}); //提交事务 await transaction.commit(); //something else } catch(e){ //遇到报错,关闭事务 await transaction.rollback(); } ``` #### 跨域 在config 中配置cors属性 ```javascript /src/config/config.dev.js let base = require('./config.base') let config = { ...base, port:9000, middlewares:['apiproxy'] cors:{ //允许你的域名,http和https需要分别设置 origins:["http://test.local.com","https://www.anchundan.com"], //针对于headers中的:Access-Control-Allow-Headers 字段,已包含:Content-Type,Cookie,Content-Length, Authorization, Accept, X-Requested-With,如想设置允许所有的字段,则 headers为 ”*“,多过定向规定一些其他字段,则用逗号分割,例如:BIZ,Connection, headers:"", //针对于headers中的 Access-Control-Allow-Methods 字段,默认为 DELETE,PUT,POST,GET,OPTIONS, methods:"DELETE,PUT,POST,GET,OPTIONS", // 针对于headers中的 Access-Control-Allow-Credentials 字段,默认未空 credentials:true, } } module.exports = config; ``` ### 启动其他应用 全局的application 中可以捆绑其他服务,比如性能的监听,socket服务等。 ``` src/app/start/ {newapp}.js module.exports = (application)=>{ //console.log(application); let {config,server} = application; //获取到了当前应用的 config 和 koa 应用 //server 为koa的一个实例,可以直接用server.use(XXX)的方式增加一个新的中间件,但不建议这么处理, //中间件的使用方式按照框架约定的方式处理最为安全 } ``` ### 全局错误捕获 全局的报错由 `process` 的 `unhandledRejection` 和 `uncaughtException` 捕获,并由config.js 配置 `handleUncaughtException`和`handleUncaughtException` 配合业务做报错处理 ``` ../config.base.js const config = { ...., handleUncaughtException:(app,error)=>{ //全局未捕获的报错 //app 为当前application 实例,可以在此调用 applicaation 的插件,例如注册的 log 插件,以下类似 // app.plugins.logger().info('xxxxx'); }, handleUnhandledRejection:(app,error)=>{ //app 为当前application 实例,可以在此调用 app 的插件。 //全局未处理的Promise 的rejection 的报错处理 } } ``` ### 增加扩展 ``` // 首先安装扩展 app.addExtension({ controllers:path.join(__dirname,'./controllers'), middlewares:path.join(__dirname,'./middlewares'), services:path.join(__dirname,'./services'), plugins:path.join(__dirname,'./plugins'), }) // 启动app app.startApp(); ``` ### 宏函数 + getAppPlugins (): Object< string, Object | Function > 获取全局的app 插件 + getAppPluginByName( pluginname ): Object | Function 根据插件名字获取插件内容 + getAppConfig(): Object <string, any> 获取当前的应用配置信息 + getControllers(): Object <string, anchuandan.Controller> 获取所有挂载的Controller字典 + getServices() : Object <string, anchuandan.Service> 获取所有挂载的Service