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就完成啦,如有什么错误和建议请给我留言,^_^,源代码在此

  • 相关阅读:
    Postgresql主从流复制+Redis集群部署
    数据仓库实时数据同步方案
    数据库与WEB服务器的配置
    HOSTS文件
    Android 命令设置获取、IP地址、网关、dns
    转:mysqld与mysqld_safe的区别
    mysql 5.7 创建用户报错ERROR 1364 (HY000): Field 'ssl_cipher' doesn't have a default value
    MySql 5.7中添加用户,新建数据库,用户授权,删除用户,修改密码
    监控网卡设备流量
    获取进程所有信息
  • 原文地址:https://www.cnblogs.com/ahl5esoft/p/3068888.html
Copyright © 2011-2022 走看看