【翻译】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是这么棒的一个模式。