anchundan v2.0.7
鹌鹑蛋 🥚
使用方式 和 eggjs 类似
区别在于插件的设置,简化了插件的配置和使用。
进程管理交给 pm2 .管理
如果你具备一些eggjs ,koa ,的开发经验,以及对sequelize 有相对的了解,可以很轻松的看懂这个份readme
这个框架诞生的目的是为了简化初始化的过程,精简eggjs
npm install anchundan
or
yarn add anchundan
or
yarn add https://github.com/shinku/anchundan
项目初始化
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 启动项的配置
监听端口设置
/src/config/config.base.js
module.exports = {
port:9000
}
新建 controller
//方式与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 对象。
this.context.set("X-PATH",this.context.path);
- send(content,option?)
this.send("hello~")
- get request
获取当前的request对象,post的场景下使用
/// postdata 为 : {userid:"123"} let {userid} = this.request.body;
- get query
获取当前的 query 对象,get 的场景下使用
/// postdata 为 : {userid:"123"} let {userid} = this.query;
- get params
路由格式类似为 /path/:id/:pagenum 使用
/// postdata 为 : {userid:"123"} let {id,pagenum} = this.params;
- get services
获取当前应用的所有service 组件时使用
let userdata = this.services.userdata; let result = await userdata.find({where:{userid}});
- get plugins 获取当前应用的所有application 插件
路由
//结合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);
}
路由增加中间件
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);
}
中间件
- 创建中间件
/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 一致
/src/config/config.base.js module.exports = { port:9000, middlewares:['apiproxy'], apiproxy:{ abc:"test" } }
插件
- context 插件,挂载在context上下文
- 插件可以是 一个Object 或者一个function
PS:如果想通过插件访问到 具体的 context 或者application 内部数据,定义函数插件的时候用
function(){}
定义,而不() =>{}
/src/plugins/sendresult/context.js //使用 function abc(){} 的方式新建函数,可以直接使用this 操作当前上下文 //使用箭头函数无法操作,application 插件类似。 module.exports = function (result){ this.body = result; this.set('Content-Type',"html/text"); }
- application 插件,挂载在application
/src/plugins/getfile/application.js //使用 function abc(){} 的方式新建函数,可以直接使用this 操作当前上下文 //使用箭头函数无法操作,application 插件类似。 module.exports = function (filepath){ return fs.readFileSync(filepath); }
- sample
//方式与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
/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
// 在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 使用
/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
let users = this.services.users; let data = await users.getInfo(userid);
通过
service
操作数据的方式更加安全,也存在更好的可读性,并且可以集成除了操作数据库意外的其他方法。
通过this.plugins.sequelize.DB[{MODULENAME}]
的方式直接操作sequelize对象,可以更加灵活的操作数据
数据库事务
以在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属性
/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
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
4 years ago