anchundan
Version:
438 lines (392 loc) • 12.3 kB
Markdown
使用方式 和 eggjs 类似
区别在于插件的设置,简化了插件的配置和使用。
进程管理交给 pm2 .管理
如果你具备一些eggjs ,koa ,的开发经验,以及对sequelize 有相对的了解,可以很轻松的看懂这个份```readme```
这个框架诞生的目的是为了简化初始化的过程,精简eggjs
```javascript
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 启动项的配置
```javascript
/src/config/config.base.js
module.exports = {
port:9000
}
```
```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;
```
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