zoukankan      html  css  js  c++  java
  • nodejs实现简易MVC

      相信大家对于nodejs应该不会陌生,如果真的比较陌生的请访问:http://nodejs.org或者http://cnodejs.org/了解。

      这个简易MVC的结构如下图:

        

      首先需要一个http服务来监听来自客户端的请求,大致代码如下:

    var m_http = require('http');
    var m_querystring = require('querystring');
    
    var m_requestHandler = require('./requestHandler');
    
    exports.run = function (port) {
        port || (port = 80);
    
        m_http.createServer(function (req, res) {
            req.setEncoding('utf8');
    
            var postData = [];
    
            req.on('data', function (chunk) {
                postData.push(chunk);
            }).on('end', function () {
                req.post = m_querystring.parse(postData.join(''));
    
                m_requestHandler.handle(req, res);
            });
    
        }).listen(port);
    
        console.log('服务器启动!');
    };
    

      以上req.on('data', ...)内,使用的是一个postData的数组来保存请求的数据,但是当数据量大的时候,会出现一些问题,这个我们暂时不管,博友么可以自己去完善,^_^

      接收了请求之后,需要通过请求的url和method去查找与之相匹配的Contoller,并调用Controller相应的Action,大致代码如下:

    var m_route = require('./route');
    var m_controllerBase = require('./controllerBase');
    var m_invalidHandler = require('./invalidHandler');
    
    var m_getRequestArgs = { ... };
    
    exports.handle = function (req, res) {
        var method = req.method ? req.method.toLowerCase() : 'get';
        var route = m_route.find(req.url, method);
    
    	var controller = require(m_util.format('./controllers/%s', route.controller));
    	if (controller[route.action]) {
    	    try {
    	        controller[route.action].call(
    	            new m_controllerBase(req, res),
    	            m_getRequestArgs.hasOwnProperty(method) ? m_getRequestArgs[method](req) : {});
    	    }
    	    catch (e) {
    	        m_invalidHandler.handle500(req, res);
    	    }
    	}
    	else {
    	    m_invalidHandler.handle404(req, res);
    	}
    };
    

      在这里引用了另外3个模块,route.js会根据请求的url和method去获取对应的controller和action信息,代码如下:

    //缓存映射信息
    var m_cache = {};
    
    exports.addMap = function (map) {
        if (!(map && map.rule && map.controller))
            return;
    
        var method = (map.method || 'get').toLowerCase();
        m_cache[method] || (m_cache[method] = []);
    
        m_cache[method].push({
            rule: map.rule,
            controller: map.controller,
            action: map.action || 'index'
        });
    };
    
    exports.find = function (url, method) {
        var route = { controller: null, action: null };
    
        var routes;
        if (!(m_cache.hasOwnProperty(method) && (routes = m_cache[method]).length))
            return route;
    
        for (var i = 0, r; r = routes[i]; i++) {
            if (r.rule.test(url)) {
                route.controller = r.controller;
                route.action = r.action;
                break;
            }
        }
        return route;
    };
    

      而controllerBase相当于是所有Controller的基类,会提供诸如缓存,输出html、json、script等方法,代码如下:

    function controllerBase(req, res) {
        this.req = req;
        this.res = res;
    };
    //添加缓存
    controllerBase.prototype.addCache = function (key, value) {
        m_cache[key] = value;
    };
    //添加缓存
    controllerBase.prototype.getCache = function (key) {
        return m_cache[key];
    };
    //返回html
    controllerBase.prototype.html = function (viewName) {
    	//coding
    };
    //根据模板生成的,可以使用其他模板来实现
    controllerBase.prototype.template = function (viewName, obj) {
    	//coding
    };
    //返回json
    controllerBase.prototype.json = function (obj) {
    	//coding
    };
    
    module.exports = controllerBase;
    

      但是在处理这些操作的事情,可能会出现错误,因此就需要一个invalidHandler来处理一些原因导致请求无法返回的情况,代码大致如下:

    //简单实现了404和500 对于其他http状态码大家可以根据情况实现
    
    exports.handle404 = function (req, res) {
        res.writeHead(404, {});
        res.end();
    };
    
    exports.handle500 = function (req, res) {
        res.writeHead(500, {});
        res.end();
    };
    

      当我做到这里的时候,我突然发现并不是所有的请求都会触发Controller和Action,有的仅仅是请求一些如图片、js、css等方面的静态文件,所以我们在处理请求的时候,应该增加一个处理静态文件的,代码如下:

    exports.handle = function (req, res) {
        var url = m_parseURL(req.url);
    	//当请求的文件是网站图标时,不映射到静态文件夹下
        var filePath = url.pathname == m_config.FAVICON ? m_path.join(__dirname, url.pathname) :
            m_path.join(__dirname, m_config.STATIC_FILE_DIR, url.pathname);
    
        m_fs.exists(filePath, function (exists) {
            if (!exists) {
                m_invalidHandler.handle404(req, res);
                return;
            }
    
            m_fs.readFile(filePath, FILE_ENCODING, function (err, file) {
                if (err) {
                    m_invalidHandler.handle500(req, res, err);
                    return;
                }
    
                var ext;
                ext = (ext = m_path.extname(filePath)) ? ext.slice(1) : 'html';
                res.writeHead(200, { 'Content-Type': m_config.CONTENT_TYPE[ext] || m_config.CONTENT_TYPE.html });
                res.write(file, FILE_ENCODING);
                res.end();
            });
        });
    };
    

      写到这里已经将简易的MVC完成了,最后再增加几个功能来跑起来看看吧,代码如下:

    //base.js
    exports.index = function () {
        this.view('index.html');
    };
    
    exports.login = function (data) {
        this.addCache('user', data.name);
        this.json({ success: true });
    };
    
    
    //user.js
    exports.load = function () {
        var msg = this.getCache('user') || '未登录';
        this.template('main.html', { msg: msg });
    };
    
    //index.html
    <div>用户名:<input id="txtName" type="text" value="admin" /></div>
    <input id="btn" type="button" value="登录" />
    
    //main.html
    欢迎你来到建议MVC,{#msg}!
    

      以上增加了controllers和对应的action以及html页面,运行起来发现没效果,检查了代码原来是还没有配置对应route规则,于是我们再添加一些规则,代码如下:

    m_route.addMap({
        rule: /^\/$/,
        controller: 'base'
    });
    m_route.addMap({
        method: 'post',
        rule: /^\/login/,
        controller: 'base',
        action: 'login'
    });
    m_route.addMap({
        rule: /^\/user\/load$/,
        controller: 'user',
        action: 'load'
    });
    

      整个mvc的效果如下:

      

      

      使用用户名登录

      

      直接访问/user/load

      

      简易mvc就完成啦,如有什么错误和建议请给我留言,^_^,源代码在此

  • 相关阅读:
    poj 2488 DFS
    畅通工程 并查集模版
    KMP 模板
    poj 1426 DFS
    poj 2528 线段数
    poj 3468 线段数 修改区间(点)
    CVPR2012文章阅读(2)A Unified Approach to Salient Object Detection via Low Rank Matrix Recovery
    如何制定目标
    Saliency Map 最新综述
    计算机视觉模式识别重要会议杂志
  • 原文地址:https://www.cnblogs.com/ahl5esoft/p/3068888.html
Copyright © 2011-2022 走看看