【翻译】Node.js+Express站点中的简易MVC架构
原文:http://timstermatic.github.io/blog/2013/08/17/a-simple-mvc-framework-with-node-and-express/
我喜欢框架。一旦我放弃了程序员的自我,学会了拥抱严格的约定,立即就在开发和部署的时间上感受到了好处。另一方面,我也喜欢了解引擎盖下是如何运转的,如果你看不到框架下面的东西,可能就会遇到危险。
这就是我为什么喜欢node.js和express。它们提供了一套框架样板,可以让我快速建立我自己的约定。
当然,使用express建立一个网站非常简单,而且,让express设置的更接近MVC也很简单。
MVC的通俗解释
当我第一次使用我的MVC框架(cakephp)的时候,我很受伤。不难看出作为一个模式,它为什么能够经受住时间的考验。你只需要知道这些:
- M是指model,用来定义数据结构和与数据打交道的方法的地方。
- V是指view,用来管理所有用户最终在屏幕上看到的东西的地方。
- C是指controller,用来接收用户的请求,从model里取出数据,并传递给view的地方。
嗯,知道这些就够了。下面是我如何组织我的express项目,把它变成一个最基本的MVC结构的。
首先,在根目录下,我需要三个子目录:
- models
- views
- controllers
来看看app.js:
var express = require('express');
,http = require('http');
,path = require('path');
,app = express();
,fs = require('fs');
// database connection
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/mydb');
// some environment variables
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser('your secret here'));
app.use(express.session());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
// dynamically include routes (Controller)
fs.readdirSync('./controllers').forEach(function (file) {
if(file.substr(-3) == '.js') {
route = require('./controllers/' + file);
route.controller(app);
}
});
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
这里的内容大部分是express自动为你生成的,不过有几行内容比较重要。第5行我引入了fs模块,这样我们可以动态读取我们的controllers,然后在25到30行,我们读进controllers目录下所有的js文件。第13行也很重要,它告诉引擎我们的views模板保存在哪里。
现在如果我们往controllers目录里增加一个js文件,我们可以按照这个格式,让它包含一系列的routes,比如controllers/users.js
var mongoose = require('mongoose')
var Video = require('../models/user');
module.exports.controller = function(app) {
app.get('/signup', function(req, res) {
// any logic goes here
res.render('users/signup')
});
app.get('/login', function(req, res) {
// any logic goes here
res.render('users/login')
});
}
我让它加载了所有的models,因为有缓存机制,每个model实际只加载一次并缓存起来,所以这样没有什么负作用。 下面export了一个controller函数,其实包含我们所有的routes。注意我们使用view的方式:res.render(‘users/signup’),这意味着我们要把文件放在views/users/signup.jade。
最后,models/user.js的内容是这样的:
var mongoose = require('mongoose')
,Schema = mongoose.Schema
userSchema = new Schema( {
username: String,
password: String
}),
User = mongoose.model('user', userSchema);
module.exports = User;
我喜欢用这种方式,用controller来融合model和view,这才是MVC的灵魂所在。这样组织文件还有个巨大的好处,如果我要修改users/signup页面,我立即知道我的model在models/user.js,route在controllers/users.js,页面在views/users/signup.jade。
这就是为什么MVC是这么棒的一个模式。