node_song------nodejs mvc框架搭建(简化路由匹配)
发布于 10 年前 作者 songbo 9871 次浏览 最后一次编辑是 8 年前

###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

不错哦…

学习了…

回到顶部