node_song------nodejs mvc框架搭建(简化路由匹配)
发布于 8个月前 作者 songbo 909 次浏览

###node_song mvc 框架介绍(基于nodejs+express+ejs+mongoose+controller.js) controller.js:简化路由匹配的工具文件,解析controllers目录下所有~.js文件,对~.js文件内容中的路由url和url对应的action方法进行匹配

###(一)目录介绍(-表示文件夹 ~表示文件 *二级目录)


-项目名 -controllers(action文件夹)
* ~t1Controller.js(controllers文件夹下文件,文件名自定义,主要用来写各种action) * ~t2Controller.js(controllers文件夹下文件,主要用来写各种action) -models(对象模型文件夹) -views(文件夹) * ~test.html -public(公共文件夹) * --css(文件夹) * --js(文件夹) * --images(文件夹) -util(工具文件夹) * ~controller.js(本文主要讲解的重要文件:用于简化路由匹配) -logs(日志文件夹)

~app.js(程序入口)

~appserver.js(系统初始化文件)

~configjs(配置文件)

~database.js(数据库连接文件) ~logger.js(日志打印工具)

-----(二)主要文件介绍----

(1)app.js 文件代码

/**[@filename](/user/filename)   app.js
 * [@author](/user/author) song
 * [@classDescription](/user/classDescription) 程序入口
 * [@version](/user/version) 0.1.0
 */
var config = require('./config'), 
    appserver = require('./appserver.js'),
    log = require('./logger.js'),
    tsweb = appserver.app;
    var fs = require("fs");
    
process.on("uncaughtException", function(err){
  //console.warn('ERROR: -- [' + (new Date).toUTCString() + ' ] Caught unhandled exception:');
  //console.warn('ERROR: -- [' + (new Date).toUTCString() + ' ] 未处理错误事件:'+(err.stack || err));
  log.logger.error('-- [' + (new Date).toUTCString() + ' ] Caught unhandled exception:' + (err.stack || err));
  //log.logger.error('-- [' + (new Date).toUTCString() + ' ] 未处理错误事件:'+(err.stack || err));
  //正式版关闭以下行,防止程序异常中止
  //process.exit();
  
});

process.on('exit',function(){
    //console.error('SYSTEM -- [' + (new Date).toUTCString() + ' ] system exit, Good bye!');
    log.logger.info('SYSTEM -- [' + (new Date).toUTCString() + ' ] system exit, Good bye!');
});

process.on('SIGINT',function(){
    //console.log('SYSTEM -- [' + (new Date).toUTCString() + ' ] system is killed, and now exit !');
    log.logger.info('SYSTEM -- [' + (new Date).toUTCString() + ' ] system is killed, and now exit !');
    process.exit();
});
tsweb.listen(config.serverPort);


(2)appserver.js 代码

/**
*[@filename](/user/filename)   appserver.js
 * [@author](/user/author) songbo
 * [@classDescription](/user/classDescription)  系统初始化
 * [@version](/user/version) 0.1.0
 */

var express = require('express'),
    logger = require('./logger'),
    connect = require('connect'),
    MemoryStore = connect.session.MemoryStore,
    controller  = require("./util/controller"),
    ejs = require('ejs'),
    config = require('./config');

var app_version = "0.0.1";
var app = exports.app = express.createServer();

app.configure(function(){
    //app.set('views', __dirname + '/views');
    //app.set('view engine' , 'jade');
    app.set('view engine' , 'html');
    app.register("html", ejs);
    app.set('view options', {layout: false});
    app.use(connect.favicon(__dirname+ '/public/favicon.ico'));
    app.use(express.logger({ format : ":method :url"}));
    app.use(express.bodyParser());
    app.use(express.cookieParser());
    app.use(express.session({ store: new MemoryStore({ reapInterval: 60 * 1000, maxAge: 15 * 600000 * 1000 }), secret: 'ection' }));
    //app.use(express.session({key: 'sid',cookie: { secure: 'true', maxAge:86400000 }}))
    app.use(express.methodOverride());
    app.use(express.static(__dirname + '/public'));
    app.use(express.static(__dirname + '/views'));

    //使用controller.js的bootControllers方法进行路由匹配
    controller.bootControllers(app);

    console.log("node_song   mvc version " + app_version + " now running on port " + config.serverPort);
});

(3)config.js 代码

/**
*[@filename](/user/filename)   appserver.js
 * [@author](/user/author) song
 * [@classDescription](/user/classDescription)  配置文件
 * [@version](/user/version) 0.1.0
 */
module.exports={
    title               : 'node_song--nodejs  mvc框架',
    serverPort      : 8001,//监听端口
    webTitle            : ' ',//web页面title

         /******* mongodbl*****相关配置*******/
     mongodb               : 'mongodb://127.0.0.1/Songdb',

       /*******mysql*****相关配置*******/
    mysqlHost       : '127.0.0.1',
    mysqlPort       : 3306,
    mysqlDb         : 'SongDb',
    mysqlUser       : 'song',
    mysqlPass       : 'song',
};


(4)database.js 代码

/**
*[@filename](/user/filename)   database.js 
 * [@author](/user/author) song
 * [@classDescription](/user/classDescription)  数据库连接
 * [@version](/user/version) 0.1.0
 */
var util = require('util'), 
    config = require('./config'),
    mysql = require('mysql'), 
    mongoose = require('mongoose'), 
    Schema = mongoose.Schema, 
    ObjectId = Schema.ObjectId;

mongoose.connect(config.mongodb);
/*********这里也可写连接mysql的代码*****/

(4)logger.js 代码

/**
*[@filename](/user/filename)   logger.js 
 * [@author](/user/author) songbo
 * [@classDescription](/user/classDescription)  日志工具
 * [@version](/user/version) 0.1.0
 */
var winston = require('winston');
require('./util/DateFormat.js');

var logger = exports.logger = new winston.Logger({
    transports : [ 
                   new winston.transports.Console(),
                   new winston.transports.File({filename : 'logs/node_song' + new Date().format('yyyy-MM-dd') + '.log'})
                 ]
});

###(三)util目录下controller.js介绍(本文重点文件–路由解析工具文件)

controller.js 代码

/**
*[@filename](/user/filename)   controller.js
 * [@author](/user/author) song
 * [@classDescription](/user/classDescription)  路由解析
 * [@version](/user/version) 0.1.0
 */
var fs = require("fs");
var mappingString = "";

function add_to_mapping_string(method, url, description, auth) {
    mappingString += "<div style='width: 400px; height: 20px; padding: 5px; background-color: " +
            "#ccc; color: #000; font-family: Arial, Verdana, sans-serif'><b>" 
            + method + " " + url + "</b></div><div style='width: 400px; padding: 5px; background-color: " +
            "#eee; color: #000; font-family: Arial, Verdana, sans-serif'>" 
            + description + "<br /><b>Auth:</b> " + auth + "</div><br />";
}
//解析controllers目录下所有.js文件
function bootController(app, file) {
  var name = file.replace('.js', '');
  var actions = require('../controllers/' + name);
   var mapping = actions["mapping"];
    
  Object.keys(actions).map(function(action){
      var fn = actions[action];
      
      if(typeof(fn) === "function") {
          if(a = mapping[action]) {
            add_to_mapping_string(a.method, a.url, a.description, a.auth);
            switch(a.method) {
                case 'get':
                            app.get(a.url, fn);
                            console.log("get " + a.url);
                            break;
                case 'post':
                            app.post(a.url, fn);
                            console.log("post " + a.url);
                            break;
                case 'put':
                            app.put(a.url, fn);
                            console.log("put " + a.url);
                            break;
                case 'delete':
                            app.del(a.url, fn);
                            console.log("delete " + a.url);
                            break;
            }
          } else {
            console.log("WARNING: no mapping for " + action + " defined");
          }
    }
 });
}

module.exports = {
    bootControllers : function(app) {
    fs.readdir(__dirname + '/../controllers', function(err, files){
        if (err) throw err;
        files.forEach(function(file){
            console.log("booting controller " + file);
            if(file != '.svn')
                bootController(app, file);
            else
                console.log("Not booting .svn controller! " );  
        });
       //可查看所有接口的url:/show_available_interfaces
        app.get("/show_available_interfaces", function(req, res){
            res.send(mappingString);
        });
      //404页面
        app.get('*', function(req, res) {  
                console.log('404 handler..') ;
                console.log(req.url);
                res.send('Page Not Found!(404)');
            });
        });
    }
};

##(四)model的写法(User数据模型对象,使用第三方模块mongoose)

/**
 * [@classDescription](/user/classDescription) User数据模型对象
 * [@author](/user/author) song
 * [@version](/user/version) 0.1.0
 */
var mongoose = require('mongoose'), 
    Schema = mongoose.Schema,
    ObjectId = Schema.ObjectId;

var UserSchema = new Schema({
    loginName       :   {type:String,required: true,index:true},
    realName        :   String,
    password        :   String,
    phone           :   String,
    email           :   String,
});

mongoose.model("User",UserSchema);
var User = exports.User = mongoose.model('User');

var UserDao = exports.UserDao = {
        /**
         * 删除所有数据
         */
        delAllData:function(cb){
            User.remove({}, function(err){
                cb(err);
            }); 
        },          
        /**
         * 增加默认数据
         */
        addDefaultData:function(cb){
            var m = new User();
            m.loginName = 'admin';
            m.realName = '系统管理员';
            m.password = tools.md5('admin');
            m.phone = '10086';
            m.email = 'test[@163](/user/163).com';
            m.save();
        },
};
//增加默认用户admin
User.find(function(err,user){
    if(err){
        console.log('无法查询用户数据:'+err);
        //process.exit();
    }else{
        if (user.length == 0) {
            UserDao.addDefaultData();
        }
    }
});

###(四)自定义controller的写法–t1Controller.js介绍(controllers目录下) (1)在controllers目录下新建js文件,名称无要求 (2)例如楼主写的t1Controller.js代码(hello world例子和一个操作users表mongo数据库的例子)

/**
 * [@classDescription](/user/classDescription)  t1Controller.js   
 * [@author](/user/author) song
 * [@version](/user/version) 0.1.0
 */

var config = require('../config'), 
    log = require('../logger.js'),
    db = require('../database.js');
var userModel = require('../models/userModel.js');
module.exports = {

    mapping: {
                
        "Hello": {
            "url": "/test",//访问的url,楼主监听的是8001端口,所以访问路径为localhost:8001/test
            "method": "get",
            "description": "简单的hello world例子",
            "auth": false
        },
        "TestUser": {
            "url": "/testUser",
            "method": "get",
            "description": "操作User表",
            "auth": false
        },
    },
   /**
     *  testUser
     * [@param](/user/param) req
     * [@param](/user/param) res
     */
    Hello: function(req, res){
        console.log("Hello world!!" );
        res.render('./test.html', {
            locals: {
                title: config.title,
                text: "hello world"
            }
        });
    },


   /**
     *  hello world
     * [@param](/user/param) req
     * [@param](/user/param) res
     */
    // GET 方法
    TestUser: function(req, res){
        console.log("TestUser!!" );
               var  loginName="admin";
               //
        userModel.User.findOne({loginName: loginName,}, function(err, results){
            var text="";
                       if (results) {
                              console.log("find admin!!" );
                              // log的使用方法,写入日志
                             log.logger.info('find admin  success!');
                             text="find admin success";
            }else {
                            console.log("not found!!" );
                            text="not found";
            };
                          res.render('./test.html', {
                         locals: {
                              title: config.title,
                                  text: text
                            }
                     });
        });
    },


 }

views文件夹下新建test.htlm文件,body标签内写入代码<%=text%> 调用text对象进行显示 启动mongo后 node app 启动项目后 访问路径localhost:8001/test 访问路径localhost:8001/testUser

###本文旨在交流,转载请指明出处…

4 回复

同样借地方说一下我的小demo http://kmanjs.com 使用 koa.js + MongoDB(mongoose) + Angular.js + Node.js 做的一个小框架. 也是自动根据route的文件位置进行加载. 同时支持使用koa-resource-router添加RESTful风格的API

一看还是用的express 3.x 路由的话,我基于express写了一个比较灵活的路由:https://github.com/yss/express-route-tree

回到顶部