zoukankan      html  css  js  c++  java
  • 一种nodejs的MVC框架

    mvc会针对请求进行分发,分发一般有controller(针对模块),action(针对模块中的方法),args(请求的参数)。

    1.先对http请求的url进行设置,解析url中的各种参数:

    //config.js
    var route = require('./route');
    //针对ajax请求
    route.map({
    method:'get', url: /^/category/mailCategory/i, controller: 'mailCategory', action: 'getMailCategory' });
    //controller为空,针对页面,针对页面 route.map({ method:
    'get', url: /^/$/i, controller: '', action: 'list.html' });

    server.js的入口:

    exports.runServer = function(port){
        port = port || 10088;
        /*
          function(req,res){}它将会自动加入到 'request' 事件的监听队列。
          它是http.IncomingMessage的一个实例。
         */
        var server = http.createServer(function(req, res){
            var _postData = '';
            //on用于添加一个监听函数到一个特定的事件
            req.on('data', function(chunk)
            {
                _postData += chunk;
            })
            .on('end', function()
            {
              req.post = querystring.parse(_postData);
                handlerRequest(req, res);
            });
            
        }).listen(port);   //程序运行的入口 
        console.log('Server running at http://180.150.189.25:'+ 10088 +'/');
    };

     当接收完请求的URL之后,执行handlerRequest(req, res);

    /**
     * 所有请求的统一入口
     */
    var handlerRequest = function(req, res){
        //通过route来获取controller和action信息
        var actionInfo = route.getActionInfo(req.url, req.method);
        //如果route中有匹配的action,则分发给对应的action
        if(actionInfo.action){
            var controller = actionInfo.controller;
            //直接跳转页面
            if(controller == ""){
                viewEngine.forward(req, res, actionInfo.action);
                return;
            }
            //加载action
        if(controller[actionInfo.action]){
            var ct = new controllerContext(req, res);
                //如果是post请求,从重新设置参数
                if(req.method.toLowerCase() == "post"){
                    actionInfo.args = req.post;
                }
                //通过apply将controller的上下文对象传递给action,路径转化就在这里。
                controller[actionInfo.action].call(ct, actionInfo.args);
            }else{
                handler500(req, res, 'Error: controller "' + actionInfo.controller + '" without action "' + actionInfo.action + '"')
            }
        }else{
            //如果route没有匹配到,则当作静态文件处理
            staticFileServer(req, res);
        }
    };
    viewEngine.forward代码如下:
    var staticFileServer = function(req, res, filePath){
        if(!filePath){
            filePath = path.join(__dirname, config.staticFileDir, url.parse(req.url).pathname);
        }
        fs.exists(filePath, function(exists) {  
            if(!exists) {  
                //目录不存在的情况
                handler404(req, res);  
                return;  
            }  
      
            var raw = fs.createReadStream(filePath);      
            var ext = path.extname(filePath);
            ext = ext ? ext.slice(1) : 'html';
            var acceptEncoding = req.headers['accept-encoding'];
            var head = {'Content-Type': contentTypes[ext] || 'text/html'};
            if (!acceptEncoding) {
                acceptEncoding = '';
            }
            //根据请求头部信息,返回相应的数据
           if(acceptEncoding.match(/gzip/)) {
                head["content-encoding"] = "gzip";
                res.writeHead(200, head);
                raw.pipe(zlib.createGzip()).pipe(res);
            }else if (acceptEncoding.match(/deflate/)) {
                head["content-encoding"] = "deflate";
                res.writeHead(200, head);
                raw.pipe(zlib.createDeflate()).pipe(res);
            } else {
                res.writeHead(200, head);
                raw.pipe(res);
            } 
      
        });
    };
     ct的上下文如下:
    //controller的上下文对象
    var controllerContext = function(req, res){
        this.req = req;
        this.res = res;
        this.dbPool = dbPool;
        this.contextPath = __dirname;
        this.handler404 = handler404;
        this.handler500 = handler500;
    };

    2.controller

    通过上面的转发就可以把URL与module中的方法映射起来,我们写方法就可以按照模块来写了,例如mailCategory中的getMailCategory的方法如下:

    在src模块中的action模块的MailCategory.js中:

    /*MailCategory.js,提供两个action  
        getMailList 和 getMailCategory
    */
    exports.getMailList = function(args){
        var context = this;
        var result = {errCode: 0, msg: 'success', categoryId: categoryId, data:[]};
        
        //参数校验
        var categoryId = args.categoryId;
        if(!categoryId){
            emitter.emit("invalidCategoryId", result, context);
            return false;
        }  
    
    /**
     * 获取邮件栏目信息
     * @param isList 1 只是返回栏目列表 0 返回栏目及模块信息
     * @returns {errCode:0, msg:'success', data:[{id:'', name: '', alias: ''},...]}
     * @returns {errCode:0, msg:'success', data: [{id:'', name:'', alias:'', modules:[{id:'', name:''}, ...]}]}
     */
    exports.getMailCategory = function(args){
    }

    3.module

      为controller层提供数据,直接与数据库连接,或者中间加一道缓存,例如redis。刚刚看到在映射的过程中,传递对象的成员

       this.dbPool = dbPool;
    它的定义如下:
    dbManager = require('./src/utilities/DbManager');
    //数据库链接池
    var dbPool = dbManager.getPool();

    DbManager.js封装了连接数据库,或者一个连接池的对象

    //创建mysql数据库链接
    var mysql = require('mysql');
    //连接池
    var dbConfig = {
        host: '180.150.189.25',
        port: '3306',
        user: 'iyy',
        password: 'iyy@2015',
        database: 'anthony',
        connectionLimit: 20       //连接池最大连接数
        //waitForConnections: false
    }
    
    //从数据库获取一个链接
    exports.getConnection = function(){
        return mysql.createConnection(dbConfig);    
    }
    
    exports.getPool = function(){
        var pool = mysql.createPool(dbConfig);
        return pool;
    }
    这样就可以在controller模块中直接操作数据库,如下:
    context.dbPool.getConnection(function(err,connection){
            if(err){
                emitter.emit("connectFailed", result, context);
                return false;
            }
            //可以进一步拆分到module中。
            connection.query("delete from MailModule  where id="+intDeleteId,function(err,res){
                if(err) {
                    emitter.emit("queryFailed", result, context);
                    return false;
                }
                /*
                emitter.on("success", function(result, context){
                    result.errCode = 0;
                    result.msg = "success";
                    var str='updateuserinfo_callback({"ret":2,"errmsg":"asdas"})';
                    context.renderJson(str);
                });
                 */
                emitter.emit("success", result, context);
            });
            //释放链接
            connection.end();
        });
     
  • 相关阅读:
    EAX、ECX、EDX、EBX寄存器的作用
    MFC VS2005 添加Override 和 Message
    ActiveX添加测试工程, 出现的问题[非选择性参数][找不到成员]
    两种应该掌握的排序方法--------2.quick Sort
    关于I/O的那点事
    整理一下 编码、解码库
    VC一些经验系列: 《分享泄漏检测工具:内存、DC、GDI、Handle... 》
    golang安装卸载 linux+windows+raspberryPI 平台
    (转)如何正确使用C++多重继承
    单播、多播(也称组播)、广播
  • 原文地址:https://www.cnblogs.com/liuyinlei/p/5380729.html
Copyright © 2011-2022 走看看