春節期間沒回家留在北京寫了一個基於koa的node MVC框架:koa-grace ,你們有興趣能夠star & fork下,謝謝支持啦!!javascript
項目地址:html
https://github.com/xiongwilee/koa-gracejava
詳細文檔:node
koa-grace是基於koa 1.x的Nodejs多站點MVC框架。react
爲何koa-grace是新一代Nodejs MVC框架:git
一個node服務,多個站點應用;github
yield 異步語法支持,忘掉回調噩夢;mongodb
繼承koa中間件,擴展性更強;數據庫
支持路徑即路由
,更優雅的路由方式;npm
RESTful數據代理支持,先後端徹底解耦;
……
├── 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 // 主文件
在開始使用koa-grace以前請確保您已經安裝並運行了下面的工具:
Nodejs (v4+)
MongoDB (DEMO 演示使用,正式環境能夠配置不用)
$ git clone https://github.com/xiongwilee/koa-grace.git $ cd koa-grace && npm install
在koa-grace目錄下,打開配置文件:
$ vi config/main.js
修改配置項:config.mongo.blog
爲您的本地mongoDB的路徑:
// mongo configuration mongo: { 'blog': 'mongodb://localhost:27017/blog' }
**更多關於配置項的文檔能夠看下面的使用文檔。
在koa-grace目錄下執行,可能須要root權限:
$ npm run dev
而後訪問 http://127.0.0.1:3000 ,就能夠看到koa-grace其中的一個案例站點了!
您也能夠訪問koa-grace的一個線上應用: http://mlsfe.biz 。
雖然說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 , ...
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目錄。
很好,若是你配置好了一個vhost爲'127.0.0.1':'blog'
, koa-grace就會自動生成一個vhost到app/blog
目錄了!接下來,進入app/blog/controller
目錄進行路由配置。
koa-grace基於 koa-grace-router 進行路由管理的,koa-grace-router又是依賴於:koa-router 。
以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
文件是如何控制的呢?
打開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; /*...*/
對,就是你猜的那樣: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__
的配置同理。
剛剛咱們看到了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/
koa-grace引入基於mongoose的koa-grace-mongo ,能夠很是便捷地使用mongoDB。
在配置文件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關閉
依舊以案例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;
主要有四個參數:
model
, 即表名,最好與當前文件同名
schema
, 即mongoose schema
methods
, 即schema擴展方法,推薦把數據庫元操做都定義在這個對象中
statics
, 即靜態操做方法
在控制器中使用很是簡單,主要經過this.mongo
,this.mongoMap
兩個方法。
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; }
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的結果,二者併發執行
除了在控制器中直接進行數據庫操做,Web應用還有可能由其餘服務進行後端部署。針對這種場景,koa-grace引入了基於 Request 的 koa-grace-proxy。
在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 : {...} * } */ }
你也能夠不傳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 : {...} * } */ }
另外,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'}
文件請求代理也很簡單,好比若是須要從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); }
TODO: 文件上傳並代理到其餘服務或者存儲到本地
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 }) }
模板文件在app/blog/views
目錄中。
koa-grace引入koa-mount 及 koa-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。
在開發環境可使用npm命令完成。
1) 普通啓動:
$ npm run start
2) watch啓動:
$ npm run dev # 在80端口啓動 $ npm PORT=80 run dev # DEBUG模式啓動,默認爲DEBUG=koa-grace* $ npm DEBUG=* run dev
在生產環境推薦使用 pm2 進行進程管理:
$ npm install pm2 -g $ pm2 start node ./bin/server.js
更多使用方法,請參看 pm2。
歡迎提PR
給做者提問&提建議:xiongwilee@foxmail.com