koa-grace:一個基于koa的node多應用MVC框架

MinPrins 8年前發布 | 24K 次閱讀 MVC模式 數據庫 MongoDB Node.js 開發

來自: https://segmentfault.com/a/1190000004465603

春節期間沒回家留在北京寫了一個基于koa的node MVC框架: koa-grace ,大家有興趣可以star & fork下,謝謝支持啦!!

項目地址:

https://github.com/xiongwilee/koa-grace

詳細文檔:

1. 簡介

koa-grace是基于 koa 1.x 的Nodejs多站點MVC框架。

1.1 特征

為什么koa-grace是新一代Nodejs MVC框架:

  • 一個node服務,多個站點應用;

  • yield 異步語法支持,忘掉回調噩夢;

  • 繼承koa中間件,擴展性更強;

  • 支持 路徑即路由 ,更優雅的路由方式;

  • RESTful數據代理支持,前后端完全解耦;……

1.2 目錄結構

├── app                        // 站點總目錄
│   ├── blog                     // 站點:blog目錄
│   │   ├── controller                 // 站點:blog的路由(控制器)目錄
│   │   ├── model                     // 站點:blog的模型目錄,包括公共控制器、mongo等
│   │   ├── static                     // 站點:blog的靜態文件目錄
│   │   └── views                     // 站點:blog的html模板目錄
│   ├── reactjs-boilerplate     // 站點:reactjs-boilerplate目錄
│   └── shop                     // 站點:shop目錄
├── bin                        // server啟動器目錄
│   ├── koa-grace                 // TODO:命令行工具
│   └── server.js                  // server啟動器
├── config                     // 配置文件目錄
│   └── main.js                    // 主配置文件
├── package.json
└── src                        // 核心文件
    └── app.js                    // 主文件

2. 快速開始

在開始使用koa-grace之前請確保您已經安裝并運行了下面的工具:

  • Nodejs (v4+)

  • MongoDB (DEMO 演示使用,正式環境可以配置不用)

2.1 安裝

$ git clone https://github.com/xiongwilee/koa-grace.git 
$ cd koa-grace && npm install

2.2 配置

在koa-grace目錄下,打開配置文件:

$ vi config/main.js

修改配置項: config.mongo.blog 為您的本地mongoDB的路徑:

// mongo configuration
mongo: {
  'blog': 'mongodb://localhost:27017/blog'
}

**更多關于配置項的文檔可以看下面的使用文檔。

2.3 運行

在koa-grace目錄下執行,可能需要root權限:

$ npm run dev

然后訪問 http://127.0.0.1 :3000 ,就可以看到koa-grace其中的一個案例站點了!

您也可以訪問koa-grace的一個線上應用: http://mlsfe.biz

3. 詳細使用文檔

雖說koa-grace是一個完整的MVC框架 , 但其本質是基于一種多站點解決方案的koa中間件的集合。其核心中間件包括但不僅限于: koa-router , koa-views , koa-mount , koa-static , koa-grace-vhost , koa-grace-router , koa-grace-proxy , koa-grace-model , koa-grace-mongo , ...

3.1 多站點配置 - Vhost

koa-grace是基于 koa-grace-vhost 進行vhost管理,基本原理是:

一個域名對應一個應用,一個應用對應一個目錄

如此一來,配置多站點就很簡單了,在配置文件 config/main.js 中:

// vhost配置
vhost: {
  'test.mlsfe.biz':'blog',
  '127.0.0.1':'blog',
  'localhost':'shop',
  '0.0.0.0':'reactjs-boilerplate'
}

其中,vhost配置中 127.0.0.1 是URI的 hostname , blog 是站點總目錄app下的一個目錄 app/blog 。如果當前請求URI為: http://127.0.0.1/home 則koa-grace會自動訪問 app/blog 目錄里的路由、模型、靜態文件。

需要說明的是, 多站點配置僅以URI的hostname為主鍵 ;也就是說,訪問帶端口號的 http://127.0.0.1 :3000/home 也會定位到app/blog目錄。

3.2 路由及控制器 - Router&Controller

很好,如果你配置好了一個vhost為 '127.0.0.1':'blog' , koa-grace就會自動生成一個vhost到 app/blog 目錄了!接下來,進入 app/blog/controller 目錄進行路由配置。

koa-grace基于 koa-grace-router 進行路由管理的,koa-grace-router又是依賴于: koa-router

3.2.1 文件路徑即路由

以 blog 站點為例, koa-grace-router 會找到 app/blog/* 目錄下的所有 .js 后綴的文件,并以文件路徑生成路由。我們再看一下案例中 blog 的路由文件:

├── api
│   └── post.js
├── dashboard
│   ├── post.js
│   ├── site.js
│   ├── user.js
│   └── userAuthor.js
├── error.js
├── home.js
├── post.js
└── user.js

如果當前請求URI為: http://127.0.0.1/dashboard/post/ * 則路由將自動落在 dashboard/post.js 文件中。

那么,如果請求路徑如果是 http://127.0.0.1/dashboard/post/list ,這個 dashboard/post.js 文件是如何控制的呢?

3.2.2 路由文件詳細說明

打開 app/blog/controller/dashboard/post.js 文件:

/.../
exports.list = function* () {
  // 綁定默認控制器
  yield this.bindDefault();
  // 獨立權限控制
  if (!userAuthor.checkAuth(this, this.userInfo)) {return};

// 獲取請求query參數 let pageNum = this.query.page; // 獲取數據 let PostModel = this.mongo('Post'); let posts = yield PostModel.page(pageNum,20); let page = yield PostModel.count(pageNum,20);

// 渲染模板 yield this.render('dashboard/post_list',{ breads : ['文章管理','文章列表'], posts:posts, page:page, userInfo: this.userInfo, siteInfo: this.siteInfo }) } exports.list.method = 'get'; exports.list.regular = null; /.../</pre>

對,就是你猜的那樣:koa-grace-router是通過post.js的module.exports進行下一步的路由控制。

另外,需要說明以下幾點:

  • 如果需要配置dashboard/post/list請求為 POST 方法,則post.js中聲明 exports.list.__method__ = 'post' 即可(不聲明默認為get請求),更多方法類型請參看: koa-router#routergetputpostpatchdelete--router ;

  • 如果要進一步配置dashboard/post/list/id路由,則在post.js中聲明 exports.list.__regular__ = '/:id'; 即可,更多相關配置請參看: koa-router#named-routes

  • 如果當前文件路由就是一個獨立的控制器,則 module.exports 返回一個yield方法即可,可以參考案例 blog 中的 controll/home.js

  • 如果當前文件僅僅是一個依賴,僅僅被其他文件引用;則在文件中配置 exports.__controller__ = false ,該文件就不會生成路由了

當然,如果一個路由文件中的控制器方法都是post方法,您可以在控制器文件最底部加入: module.exports.__method__ = 'post' 即可。 __regular__ 的配置同理。

3.2.3 控制器

剛剛我們看到了post.js中的exports.list方法,事實上它就是一個控制器(controller)了。

您可以新建一個 app/blog/controller/hello.js 文件

exports.koagrace = funtion* (){
    this.body = 'hello koa-grace!';
}

訪問 http://127.0.0.1/hello/koagrace ,就可以看到“hello koa-grace!”輸出。它是典型的一個基于上下文(context)的yield方法。幾個關鍵方法/參數使用如下:

context屬性 類型 說明
this.query object get參數
this.request.body object post參數,由于koa-grace默認引入了 koa-bodypaser ,您可以直接在this.request.body中獲取到post參數
this.bindDefault function 公共控制器,相當于 require('app/blog/model/defaultCtrl.js')
this.render function 模板引擎渲染方法,請參看:3.5 模板引擎- Template engine
this.mongo function 數據庫操作方法,請參看:3.3 數據庫 - Database
this.mongoMap function 并行數據庫多操作方法,請參看:3.3 數據庫 - Database
this.proxy function RESTful數據請求方法,請參看:3.4.1 數據代理
this.download function 文件請求代理方法,請參看:3.4.2 請求代理
this.upload function 文件上傳方法,請參看: 3.4.3 文件上傳

更多context文檔請參看 koa官網 ,或 http://koajs.in/doc/

3.3 數據庫 - Database

koa-grace引入基于 mongoose 的 koa-grace-mongo ,可以非常便捷地使用mongoDB。

3.3.1 連接數據庫

在配置文件 config/main.js 中進行配置:

  // mongo配置
  mongo: {
    options:{
      // mongoose 配置
    },
    api:{
      'blog': 'mongodb://localhost:27017/blog'
    }
  },

其中, mongo.options 配置mongo連接池等信息, mongo.api 配置站點對應的數據庫連接路徑。

值得注意的是, 配置好數據庫之后,一旦koa-grace server啟動mongoose就啟動連接,直到koa-grace server關閉

3.3.2 mongoose的schema配置

依舊以案例 blog 為例,參看 app/blog/model/mongo 目錄:

└── mongo
    ├── Category.js
    ├── Link.js
    ├── Post.js
    └── User.js

一個js文件即一個數據庫表即相關配置,以 app/blog/model/mongo/Category.js :

'use strict';

// model名稱,即表名 let model = 'Category';

// 表結構 let schema = [{ id: {type: String,unique: true,required: true}, name: {type: String,required: true}, numb: {type: Number,'default':0} }, { autoIndex: true, versionKey: false }];

// 靜態方法:http://mongoosejs.com/docs/guide.html#statics let statics = {}

// 方法擴展 http://mongoosejs.com/docs/guide.html#methods let methods = { /**

  • 獲取博客分類列表 / list: function () { return this.model('Category').find(); } }

module.exports.model = model; module.exports.schema = schema; module.exports.statics = statics; module.exports.methods = methods;</pre>

主要有四個參數:

  • model , 即表名,最好與當前文件同名

  • schema , 即mongoose schema

  • methods , 即schema擴展方法, 推薦把數據庫元操作都定義在這個對象中

  • statics , 即靜態操作方法

3.3.3 在控制器中調用數據庫

在控制器中使用非常簡單,主要通過 this.mongo , this.mongoMap 兩個方法。

1) this.mongo(name)

調用mongoose Entity對象進行數據庫CURD操作

參數說明:

@param [string] name : 在 app/blog/model/mongo 中配置Schema名,

返回:

@return [object] 一個實例化Schema之后的Mongoose Entity對象,可以通過調用該對象的methods進行數據庫操作

案例

參考上文中的Category.js的配置,以 app/blog/controller/dashboard/post.js 為例,如果要在博客列表頁中獲取博客分類數據:

// http://127.0.0.1/dashboard/post/list
exports.list = function* (){
    let cates = yield this.mongo('Category').list();
    this.body = cates;
}

2) this.mongoMap(option)

并行多個數據庫操作

參數說明

@param [array] option

@param [Object] option[].model mongoose Entity對象,通過this.mongo(model)獲取

@param [function] option[].fun mongoose Entity對象方法

@param [array] option[].arg mongoose Entity對象方法參數

返回

@return [array] 數據庫操作結果,以對應數組的形式返回

案例

  let PostModel = this.mongo('Post');
  let mongoResult = yield this.mongoMap([{
      model: PostModel,
      fun: PostModel.page,
      arg: [pageNum]
    },{
      model: PostModel,
      fun:PostModel.count,
      arg: [pageNum]
    }]);

let posts = mongoResult[0];// 獲取第一個查詢PostModel.page的結果 let page = mongoResult[1]; // 獲取第二個查詢PostModel.count的結果,兩者并發執行</pre>

3.4 代理 - Proxy

除了在控制器中直接進行數據庫操作,Web應用還有可能由其他服務進行后端部署。針對這種場景,koa-grace引入了基于 Requestkoa-grace-proxy

3.4.1 數據代理

在koa-grace的控制器中使用 this.proxy 方法進行數據代理非常簡單:

exports.list = function* (){
    yield this.proxy({
        userInfo:'github:post:user/login/oauth/access_token?client_id=**',
        otherInfo:'github:other/info?test=test',
    });

console.log(this.backData);
/**
 *    {
 *        userInfo : {...},
 *        otherInfo : {...}
 *    }
 */

}</pre>

你也可以不傳 this.backData 參數,默認注入到上下文的 this.backData 對象中:

exports.list = function* (){
    yield this.proxy({
        userInfo:'github:post:user/login/oauth/access_token?client_id=**',
        otherInfo:'github:other/info?test=test',
    });

console.log(this.backData);
/**
 *    {
 *        userInfo : {...},
 *        otherInfo : {...}
 *    }
 */

}</pre>

另外, github:post:user/login/oauth/access_token?client_id=**** 說明如下:

  • github : 為在 config.main.js 的 api 對象中進行配置;

  • post : 為數據代理請求的請求方法,該參數可以不傳,默認為 get

  • path : 后面請求路徑中的query參數會覆蓋當前頁面的請求參數(this.query),將query一同傳到請求的接口

  • 你也可以寫完整的路徑: {userInfo:'https://api.github.com/user/login?test=test'}

3.4.2 文件代理

文件請求代理也很簡單,比如如果需要從github代理一個圖片請求返回到瀏覽器中,參考: http://mlsfe.biz/user/avatar?img=https ://avatars.githubusercontent.com/u/1962352?v=3

exports.avatar = function* (){
    let imgUrl = query.img;
    yield this.download(imgUrl);
}

3.4.3 文件上傳

TODO: 文件上傳并代理到其他服務或者存儲到本地

3.5 模板引擎- Template engine

koa-grace引入 koa-views , 進行模板引擎管理。默認的模板引擎為 swig , 您可以在 config/main.js 中配置 template 屬性您想要模板引擎:

  // 模板引擎配置
  template: 'swig'

目前支持的模板引擎列表在這里: consolidate.js#supported-template-engines

在控制器中調用 this.render 方法渲染模板引擎:

exports.home = function* () {
  yield this.bindDefault();

yield this.render('dashboard/site_home',{ breads : ['站點管理','通用'], userInfo: this.userInfo, siteInfo: this.siteInfo }) }</pre>

模板文件在 app/blog/views 目錄中。

3.6 靜態文件服務 - Static server

koa-grace引入 koa-mountkoa-static ,將靜態文件代理到 /static :

  // 配置靜態文件路由
  vapp.use(mount('/static',
    koastatic(appPath + '/static')
  ));

以案例中 blog 的靜態文件為例,靜態文件在blog項目下的路徑為: app/blog/static/image/bg.jpg ,則訪問路徑為 http://127.0.0.1/static/image/bg.jpg

3.7 啟動服務及調試 - Process & DEBUG

3.7.1 開發環境

在開發環境可以使用npm命令完成。

1) 普通啟動:

$ npm run start

2) watch啟動:

$ npm run dev

在80端口啟動

$ npm PORT=80 run dev

DEBUG模式啟動,默認為DEBUG=koa-grace*

$ npm DEBUG=* run dev </pre>

3.7.2 生產環境

在生產環境推薦使用 pm2 進行進程管理:

$ npm install pm2 -g
$ pm2 start node ./bin/server.js

更多使用方法,請參看 pm2

5. 貢獻

 本文由用戶 MinPrins 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!