模块文件一个完整的基于Node.js web应用详解

在改章节中,我们重要绍介模块文件的内容,自我感觉有个不错的议建和大家分享下

    

媒介

    这篇文章所应用的例子是基于《node.js开辟指南》这本书中的例子和源码代来做的。express从2.x到3.x引入了非常大的化变,很多模块都被立独出去,并且用调的接口也发生了很大的化变,所以原有的码代在express3.x上是不能运行的。在试尝的程过中,做了很多移迁的任务,同时将一些模块行进了必定的分离和整合,使得全部项目更加拥有构结性和可扩展性。

    这里首先要荐推一下《node.js开辟指南》这本书,想学习和应用Node.js的学同,这确实是一本非常面全的绍介Node.js的书籍,看完了后以,结合书中的例子码代,基本可以应用Node行进web应用的开辟。

    我这里重要结合这个例子,以自己的解理和对例子的改修报告一下应用Node.js行进web开辟的全部程过。 我就直接从码代开始讲,对于境环的搭建,npm包装安,模块引入等大家可以另外找一些文章,或者从《node.js开辟指南》这本书的响应章节去解了。

    

目录构结:

    首先贴出目录构结:

    模块和文件

    从每一个文件和文件夹的名字上,相信大家能看出他们各自的功能。

    

  • main.js是全部应用的动启文件
  • settings.js中寄存着系统的配置信息
  • server.js是系统服务配置和创立的地方
  • db.js是与数据库相干的内容
  • models模块中中寄存着模型类如User,Post等,相似于Java中的Entity
  • routes中是系统面页转跳和请求发分理处的模块
  • views是系统现展给户用的面页
  • daos分中装了有所对数据库的作操,熟习J2EE的学同该应都解理这一层做的事件
  • web中是一些静态元素,如html,js,css,images
  • package.json中定义了系统须要的其他的第三方模块,如express,ejs等
  • node_modules中则是寄存通过npm装安的第三方包的地方

    接下来会对这些分部分离做细详的绍介和析分。

    

基于express和ejs的MVC

    在后台的各个模块中其实有一个基于express和ejs的MVC模式。对应的三个模块为:models(M)-views(V)-routes(C),详细会在面后解讲他们三者是如何任务的。

    

express

    关于express,我在这里不做细详的绍介,大家可以上它的官网做比拟细详的解了。简略的讲,就是一套在Node.js上创立web应用的框架。供提了包含服务创立、动启、会话、路由等接口和现实。一个最基本的基于express的服务码代如下:

var express = require('express');
var app = express(); //创立服务

app.get('/', function(req, res){ //路由有所的到根目录的请求
  res.send('hello world');
});

app.listen(3000); //动启服务,监听3000端口

ejs

    ejs: ejs是一种基于js的模版技巧,即通过在html段片中插入js码代。在发送到客户端之前在现服务器端行进析解理处,动态设置一些段字或者加添一些节点。JSP就是一种基于java的模版语言。

    在最新的ejs中可以支撑以html文件作为模版文件,并且引入了include机制,可以应用include语句来引入其他的面页内容。这点和jsp很像。

    一个基于ejs的html文件可以写成如下:

<% include header.html %>
 <% if (!locals.user) { %>
  <div class="hero-unit">
    <h1>迎欢离开 Microblog</h1>
    <p>Microblog 是一个基于 Node.js 的微博系统。</p>
    <p>
      <a class="btn btn-primary btn-large" href="/login">录登</a>
      <a class="btn btn-large" href="/reg">当即注册</a>
    </p>
  </div>
<% } else { %>
 <% include say.html %>
<% } %>
<% include footer.html %>
在应用ejs的时候,可以在js码代中用调res.render('index',{user:"Owen"})法方。这个法方有两个参数,第一个为模版文件的名字,第二个为须要传入到模版中应用的参数。
exports.index = function(req, res) {
     res.render('index', {
        title: '首页',
        posts: posts
    });
};
在最新的ejs中,加入了作用域的念概,在模版文件中不能直接用引变量名来访问变量,而须要应用locals.xxx来访问响应的变量。这样做是为了免避全局变量的污染和冲突。

    

MVC

    在这个MVC模式中重要用到了express的route功能和ejs的模版机制。

    在models模块中定义一些模型模块如User,Post等,这些相似与java中的Pojo或者Entity类。定义了模型的一些性属和法方。这些性属与数据库的段字相对应。比如一个简略的User model的模块可以定义如下:

function User(user) {
    this.name = user.name;
    this.password = user.password;
};
module.exports = User;
routes中定义了请求发分理处的程过。比如到有所到根目录(/)的请求都经过必定的理处然后转发到index view中,到/login的请求该应返回login.html面页。这个与j2ee项目中的web.xml或者应用struts时的struts.xml相似。在node中,遵守码代即配置的则原,上面先看一下/routes/index.js模块中的code。
var crypto = require('crypto');
var User = require('../models/User');
var Post = require('../models/Post');
var user = require('./user');

var that = exports;

exports.index = function(req, res) {
    Post.get(null, function(err, posts) {
        if (err) {
            posts = [];
        }
        res.render('index', {
            title: '首页',
            posts: posts
        });
    });
};

exports.login = function(req, res) {
    res.render('login', {
        title: '用戶登入',
    });
};

module.exports = function(app) {
    app.get('/', that.index);

    app.get('/login', checkNotLogin);
    app.get('/login', that.login);

    app.post('/login', checkNotLogin);
    app.post('/login', that.doLogin);

    app.get('/reg', user.reg);
    ....
};
面上的码代段片定义了index函数用来理处有所的到根目录的请求,login函数理处到/login的get请求。 而到注册模块的(/reg)的请求,则被转发到user.reg法方中。在route/user模块中,我们可以定义跟user相干的一些理处函数,如:
    每日一道理
书,各种各样的书。书,寄托着人类热切的希望;书,蕴含着人类丰富的感悟。提起书,会有说不完的话语……
var crypto = require('crypto');
var User = require('../models/User');
var UserDao = require('../daos/UserDao');
var PostDao = require('../dao/PostDao');

exports.view = function(req, res) {
    UserDao.get(req.params.user, function(err, user) {
        if (!user) {
            req.flash('error', '户用不存在');
            return res.redirect('/');
        }
        PostDao.get(user.name, function(err, posts) {
            if (err) {
                req.flash('error', err);
                return res.redirect('/');
            }
            res.render('user', {
                title: user.name,
                posts: posts,
            });
        });
    });
};

exports.reg = function(req, res) {
    res.render('reg', {
        title: '户用注册',
    });
};
通过将理处函数的分拆和封装,可以很好的让这些route模块起到相似java中的servlet或者service的作用。

    Views中则是将要返回给客户端展示的内容,route中通过对model的理处,将理处结果或者model的内容通过ejs的式方植入到html面页中返回给客户端。

    

 routes->models->daos

    routes作为请求收接发分的模块,在收接到请求后以用调models中的接口理处数据,在models中通过daos中的数据库作操接口成完对数据库数据的查询活变动。这样三个层次各自的责职以及之间的赖依关系就非常确明。拿注册程过举例,典范的用调如下:

routes/index.js
app.post('/login', checkNotLogin);
app.post('/login', user.doLogin);

routes/user.js
exports.doLogin = function(req, res) {
    //成生令口的散列值
    var md5 = crypto.createHash('md5');
    var password = md5.update(req.body.password).digest('base64');

    User.get(req.body.username, function(err, user) {
        if (!user) {
            req.flash('error', '户用不存在');
            return res.redirect('/login');
        }
        if (user.password != password) {
            req.flash('error', '密码错误');
            return res.redirect('/login');
        }
        req.session.user = user;
        req.flash('success', '录登功成');
        res.redirect('/');
    });
};

models/User.js
var UserDao = require('../daos/UserDao');

User.get = function get(username, callback) {
    UserDao.get(username, callback);
};

daos/UserDao.js
exports.get = function get(username, callback) {
  mongodb.open(function(err, db) {
    if (err) {
      return callback(err);
    }
    db.collection('users', function(err, collection) {
      if (err) {
        mongodb.close();
        return callback(err);
      }
      collection.findOne({name: username}, function(err, doc) {
        mongodb.close();
        if (doc) {
          var user = new User(doc);
          callback(err, user);
        } else {
          callback(err, null);
        }
      });
    });
  });
};

服务配置和动启

    main.js是系统动启的文件,在终端应用:node main.js将动启全部web应用。 

var server = require('./server');
server.start();
我的这个文件中码代很简略,我将服务的配置和创立程过移到了server.js中:
var express = require('express');
var ejs = require('ejs');
var flash = require('connect-flash');
var MongoStore = require('connect-mongo')(express);
var settings = require('./settings');
var routes = require('./routes');

var app = express();
app.configure(function() {
    console.log(__dirname);
    app.set('views', __dirname + '/views');
    // app.set('view engine', 'ejs');
    app.engine('.html', ejs.__express);
    app.set('view engine', 'html');
    app.use(express.bodyParser());
    app.use(flash());
    app.use(express.methodOverride());
    app.use(express.cookieParser());
    app.use(express.session({
        secret: settings.cookieSecret,
        store: new MongoStore({
            db: settings.db
        })
    }));
    app.use(function(req, res, next) {
        res.locals.error = req.flash('error').toString();
        res.locals.success = req.flash('success').toString();
        res.locals.user = req.session ? req.session.user : null;
        next();
    });
    app.use(app.router);
    routes(app);
    app.use(express.static(__dirname + '/web'));
});

app.configure('development', function() {
    app.use(express.errorHandler({
        dumpExceptions: true,
        showStack: true
    }));
});

app.configure('production', function() {
    app.use(express.errorHandler());
});

exports.start = function() {
    app.listen(settings.port);
    console.log("Express server listening on port %d in %s mode", settings.port, app.settings.env);
}
这里重点绍介几个症结的地方:

    app.engine('.html', ejs.__express);
app.set('view engine', 'html');

    这两句设置让ejs将.html文件作为模版文件。

    app.use(flash());

    express3.0后以移除了req.flash()法方,所以只有通过应用'connect-flash'中间件模块才能继承应用req.flash()法方。

    app.use(function(req, res, next) {
res.locals.error = req.flash('error').toString();
res.locals.success = req.flash('success').toString();
res.locals.user = req.session ? req.session.user : null;
next();
});

    由于express3.0移除了app.dynamicHelper()接口,所以要继承应用相似的功能,可以应用如上的码代,将flash或者session中的内容动态绑定到locals局部对象上。这样在模版文件中可以直接应用locals.xxx的式方来访问到这些变量。

 

    到这里项目中比拟症结的码代分部都绍介完了,项目码代我放到了github上:https://github.com/owenXin/microblogByOwen

    我当地win7境环运行畸形(记得起mongodb哦 )。这是我第一次在Node上做项目,只是开端想设的构结,迎欢大家起一交流,供提名贵的见意和议建。

文章结束给大家分享下程序员的一些笑话语录: 古鸽是一种搜索隐禽,在中国快绝迹了…初步的研究表明,古鸽的离去,很可能导致另一种长着熊爪,酷似古鸽,却又习性不同的猛禽类——犤毒鸟


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值