如何在ExpressJS中创建可扩展控制器

时间:2013-09-06 23:17:19

标签: javascript node.js express dot.js

我是Node的新手,我正在尝试使用ExpressJS(http://expressjs.com/)创建一个MVC应用程序。我在GitHub上使用与MVC示例(https://github.com/visionmedia/express/tree/master/examples/mvc)相同的文件夹结构。

在我的控制器文件夹中,我有2个文件夹:main和system。我想要的是在/controllers/system/index.js中定义一个基本控制器,并让/controllers/main/index.js继承系统控制器。每个其他模块都会扩展系统并覆盖一些函数来生成页面。

在另一个教程中,我找到了以下代码。

Base.js

var _ = require("underscore");
module.exports = {
    name: "base",
    extend: function(child) {
        return _.extend({}, this, child);
    },
    run: function(req, res, next) {

    }
};

Home.js

var BaseController = require("./Base"),
    View = require("../views/Base"),
    model = new (require("../models/ContentModel"));

module.exports = BaseController.extend({ 
    name: "Home",
    content: null,
    run: function(req, res, next) {
        model.setDB(req.db);
        var self = this;
        this.getContent(function() {
            var v = new View(res, 'home');
            v.render(self.content);
        })
    },
    getContent: function(callback) {
        var self = this;
        this.content = {};
        model.getlist(function(err, records) {
            if(records.length > 0) {
                self.content.bannerTitle = records[0].title;
                self.content.bannerText = records[0].text;
            }
            model.getlist(function(err, records) {
                var blogArticles = '';
                if(records.length > 0) {
                    var to = records.length < 5 ? records.length : 4;
                    for(var i=0; i<to; i++) {
                        var record = records[i];
                        blogArticles += '\
                            <div class="item">\
                                <img src="' + record.picture + '" alt="" />\
                                <a href="/blog/' + record.ID + '">' + record.title + '</a>\
                            </div>\
                        ';
                    }
                }
                self.content.blogArticles = blogArticles;
                callback();
            }, { type: 'blog' });
        }, { type: 'home' });
    }
});

如果没有Underscore的扩展功能,你怎么做? Express是否有内置的方法来扩展模块?我正在使用doT.js进行模板化,所以我不想为一个函数包含另一个大型库。

谢谢!

编辑:必须进行一些更改才能从dc5中获取基本代码。系统工作,但主要我在继承调用上得到这个错误:

util.js:555
  ctor.prototype = Object.create(superCtor.prototype, {
                          ^
TypeError: Object prototype may only be an Object or null
    at Function.create (native)
    at Object.exports.inherits (util.js:555:27)

/controllers/system/index.js:

var util = require( 'util' ),
    system = { };

system.index = function( req, res, next ) {
    res.render( 'main' );
};

module.exports = system;

/controllers/main/index.js:

var util = require( 'util' ),
    system = require( './../system/index' ),
    main = { };

util.inherits( main, system );

module.exports = main;

2 个答案:

答案 0 :(得分:9)

您可以将util.inherits用于您所描述的内容。它不是_.extend()的替代品,但上述示例所需的只是直接继承。

用法:util.inherits(constructor, superConstructor)

base.js:

var util = require('util');

function Base() {…}

Base.prototype.run = function(req,res,next) {…}
module.exports = Base;

home.js:

var util = require('util');
var BaseController = require("./base");

function Home() {…}

util.inherits(home, BaseController);

Home.prototype.run = function(req,res,next) {…}

或者标准的JS继承模式:

base.js:

function Base() {…}

Base.prototype.run = function(req,res,next) {…}
module.exports = Base;

home.js:

var BaseController = require("./base");

function Home() {
    BaseController.apply(this, arguments);
}

Home.prototype = Object.create(BaseController.prototype);
Home.prototype.run = function(req,res,next) {…}

根据问题中的更新样本,模块应如下所示:

系统:

var util = require('util');

function System() {
    this.txt  = "hello from ";
    this.name = "System"; 
}

System.prototype.sayHello = function() {
    console.log(this.txt + this.name);
}

System.prototype.run = function(req,res,next) {
    this.sayHello();

    console.log('calling ==> overrideMe');
    this.overrideMe();

    console.log('calling ==> noOverride');
    this.noOverride();
    next ? next() : "";
}

System.prototype.overrideMe = function() {
    console.log('System.overrideMe');
}

System.prototype.noOverride = function() {
    console.log('System.noOverride');
}


module.exports = System;

主:

var util = require('util');
var System = require("../system/");

function Main() {
    // Makes sure the System constructor is run
    System.apply(this, arguments);
    this.name = "Main"; 
}

util.inherits(Main, System);

Main.prototype.run = function(req,res,next) {
    this.sayHello();

    console.log('calling ==> overrideMe');
    this.overrideMe();

    console.log('calling ==> noOverride');
    this.noOverride();

    next ? next() : "";
}

Main.prototype.overrideMe = function() {
    console.log('Main.overrideMe');
}

module.exports = Main;

根目录中的app.js - 一个简化的快速服务器:

var System  = require('./controllers/system');
var Main    = require('./controllers/main');
var express = require('express');
var path    = require('path');
var http    = require('http');
var app     = express();
var server;

var system = new System();
var main   = new Main();

app.configure(function() {
    "use strict";
    app.set('port', process.env.PORT || 3000, '127.0.0.1');
    app.use(system.run.bind(system));
    app.use(main.run.bind(main));
    app.use(app.router);
    //app.use(express.compress());
    app.use(express.static(path.join(__dirname, '..', 'public'), {redirect: false}));
    app.use(express.static(path.join("/Users/dave/personal/playground/yo"), {redirect: false}));
});


server = http.createServer(app);
server.listen(app.get('port'), function() {
    "use strict";
    console.log("Express server listening on port " + app.get('port'));
});

从浏览器访问:http://localhost:3000/

控制台输出:

Express server listening on port 3000
hello from System
calling ==> overrideMe
System.overrideMe
calling ==> noOverride
System.noOverride
hello from Main
calling ==> overrideMe
Main.overrideMe
calling ==> noOverride
System.noOverride

重要

由于此示例使用SystemMain的实例来提供路由,因此在将run方法传递给express时,必须将{{1}}方法绑定到该实例。有关详细信息,请参阅:MDN .bind documentation

答案 1 :(得分:0)

为避免复杂的配置和变通方法,使用ZinkyJS,它提供了一种更好的方法来使模块继承成为可能。