zoukankan      html  css  js  c++  java
  • 【原创】打造nodejs的一个简单MVC框架:ihttpframework

    我也是前段时间才接触到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/ 获取,本人才疏学浅,有不对的地方还望提出、指点指点。

  • 相关阅读:
    JQuery Easy UI 1.7官网最新版附1.7API
    JS时间戳转换日期格式,附JS脚本详细用法
    JS原生对象实现异步请求以及JQ的ajax请求四种方式
    WebService跨域配置、Ajax跨域请求、附开发过程源码
    反射DataTable转实体类
    前端分页、及分页原理
    源码剖析之sun.misc.Unsafe
    JAVA并发编程学习笔记之CLH队列锁
    java 中的Unsafe
    AbstractQueuedSynchronizer源码解析之ReentrantLock(二)
  • 原文地址:https://www.cnblogs.com/ppoo24/p/2343064.html
Copyright © 2011-2022 走看看