【原創】打造nodejs的一個簡單MVC框架:ihttp-framework


我也是前段時間才接觸到nodejs,感覺寫起來挺爽的,大致學了下,就自己順手寫個簡單(准確應該說是簡陋)的MVC框架,當是練習了。

廢話不多說,直接開上。

0.整體目錄結構

大致說下,run.js是服務器監聽入口,通過命令“node run”就可以開啟服務了,server.js是HTTP服務器的創建代碼,application.js則是MVC框架程序的入口,其他的就不一一介紹了。

1.搭建一個HTTP服務器

這部分就相當簡單了,直接來官網的代碼基本也可以搞定,我自己的代碼如下:

exports.class = function(port){
this._port = port;
}
exports.class.prototype = {
runApplication: function(appClass) {
http.createServer(function(req, res) {
console.log('[' + req.method + ']', req.url);
var _postData = '';

//提取POST數據
req.on('data', function(data) {
_postData += data;
console.log('[Received]' + data.length);
});

req.on('end', function() {
//保存POST數據
req.post = querystring.parse(_postData);
//交由dispatcher
new appClass(req, res);
});

}).listen(this._port);
console.log('Server is running at port ' + this._port);
}
}

這里不僅創建了一個HTTP服務器監聽,並針對POST參數進行了處理。(注意我這里使用了exports,即構建了一個nodejs模塊[關於模塊,請參考相關nodejs教程],並將該類作為該模塊的一個屬性class,要引用該類的話,就使用像這樣的代碼:var Server = require('./server').class后面的類定義也將遵循此格式。)在此,我們也得改變以往的過程式代碼書寫,轉變思維為“事件驅動”型,熟悉前端JS/Jquery的童鞋都應該比較了解:

req.on('data', function(data) {
//TODO
});

這種書寫格式吧(即這些代碼並不是立即就順序執行的),當然,nodejs的高性能也在於此,“事件驅動”使得各個方面的IO都是無阻塞的,從而能夠最大化利用資源。上面的代碼通過on('data',function(){})來監聽'data'事件,該事件即是瀏覽器向服務器POST數據時觸發的事件,我們就只需要_postData += data;這樣將數據一部分一部分保存到內存即可,一旦POST數據接收完畢,就會觸發'end'事件,這時我們通過nodejs的內置庫querystring來解析POST參數。(注意:這里僅僅是簡單的解析了鍵值對(表單是application/x-www-form-urlencoded)這種形式的POST參數,如果有文件上傳(表單是multipart/form-data)的話,那么要處理文件數據,格式就完全不一樣了,具體可以參考:http://cnodejs.org/blog/?p=2207)。處理完畢后,我們將new appClass(req, res)創建一個application(即我們這里的MVC框架應用),用它來handle這些請求。

2.一個Application類(相當於MVC應用的入口)

這里Application的構造函數如下:

exports.class = function(req, res) {
this._req = req, this._res = res;
this.dispatcher();
}

初始化完成后就直接調用了dispatcher函數,dispatcher函數主要的工作就是判斷該請求是請求一個“動態資源”還是一個“靜態資源(圖片、css什么的)”(怎么判斷的?這里我模仿apache的rewrite功能,使用正則來匹配,配置暫時寫死在了core/route.js中),如果是請求“靜態資源”,則我們直接讀取該文件,然后輸出。后面我們會着重講“動態資源”(也就是請求動態網頁了)。

3.完成C的部分

如果請求的是“動態資源”,那么就相當於是在調用我們的Controller部分了,這里我實現了一個Controller基類,所有的controller都將繼承自這個基類,里面主要是一個vendor()方法,用於渲染網頁。

至於如何定位controller及它下面的action,看看下面代碼:

 

var classPath = path.join(CONTROLLER_PATH, actionInfo.controller);
var classRef = require(classPath).class; //類的一個引用
var c = new classRef(this._req, this._res);
if (typeof(c[actionInfo.action]) != 'function') {
actionInfo.action = config.defaultAction; //使用默認action
if(typeof(c[actionInfo.action]) != 'function') {
throw new Error('No callable action');
}
}

actionInfo是通過route.getActionInfo(this._req)解析而來,它包含了最終我們理解出來的controller和action以及GET參數,然后通過這些信息來定位具體的controller文件,初始化並執行它的action。

4.完成V的部分

這部分我主要實現了一個簡陋的Template用於解析並渲染html模板,上面C的vendor函數就是調用的這個Template,而這個Template就相當簡陋了,主要代碼如下:

var content = fs.readFileSync(file, 'utf8');
//替換變量
if(content) {
result = content.replace(/\{\$(\w+)?\}/g, function() {
return assign[arguments[1]]; //取第一個匹配項 即為 變量名
});
}

說白了就是一個正則替換,在html模板里面,我們就可以這樣“{$var}”調用變量了:

 

<hr />This is:{$var1} <br />

是不是很簡單:-)

5.完成M的部分

由於時間關系,這部分還沒完成,主要也就是數據庫連接與操作相關的了。。

結語

nodejs現在發展挺好的,相信你試用了之后,也會感覺到她的強大與舒適,js到時前后通吃了,呵呵。

上面項目的所有代碼可以在http://code.google.com/p/ihttp-framework/ 獲取,本人才疏學淺,有不對的地方還望提出、指點指點。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM