登录
注册
node.js 学习社区
使用express4.x版和Jade模板重写《nodejs开发指南》微博实例

于媛媛

2014-12-06 12:17

本实例已经将完整代码上传github了,网址 https://github.com/tonyzhan/microblog 欢迎大家下载!

《nodejs开发指南》是一本好书,但微博开发实例已经过时了。express4.x发布了,Jade模板是express的默认模板。 学习了jade模板后发觉也没什么难的,而且html代码清爽了许多。 网上好多人说ejs模板怎么好,我却觉得仿佛回到了asp时代,凡是像microsoft的东西,我都不感冒。 我使用express4.x版和Jade模板重写《nodejs开发指南》微博实例,请大家参考,欢迎大家多提意见。

Installation 安装

$ npm install express 

快速建立项目

$ npm install -g express-generator 

创建项目目录

$ express /tmp/microblog && cd /tmp/microblog 

安装中间件和依赖项

$ npm install 

启动服务器, 这个有些特别,请注意:

$  cd /tmp/microblog
$ bin/www 

##我的目录,敬请参考

microblog
--bin
  --www
--models
  --db.js
  --post.js
  --user.js
--node_modules
  --body-parser
  --connect-flash
  --connect-mongo
  --cookie-parser
  --debug
  --express
  --express-session
  --jade
  --mongodb
  --morgan
  --static-favicon
--public
  --images
  --javascripts
    --bootstrap.js
    --jquery.js
  --stylesheets
    --bootstrap.css
    --bootstrap-responsive.css
    --style.css
--routes
  --index.js
  --users.js //这个是express自带的,基本没用
--views 
  --error.jade //这个是express自带的,基本没用
  --index.jade
  --layout.jade
  --login.jade
  --posts.jade
  --reg.jade
  --say.jade
  --user.jade //这个是ejs模板需要用到的,在jade模板下发觉没有用,可以使用include直接放在index.jade就可以实现需求了
--app.js
--package.json
--setting.js 

以下是源代码,就不说废话了:

app.js的代码:

var express = require('express');
var path = require('path');
var favicon = require('static-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
//var partials = require('express-partials');用jade模板,不能使用这个中间件
var session    = require('express-session');
var MongoStore = require('connect-mongo')(session);
var settings = require('./settings');
var flash = require('connect-flash');
var routes = require('./routes/index');
var users = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
//app.use(partials());

app.use(favicon());
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());

//cookie解析的中间件
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(flash());

//提供session支持
app.use(session({
    secret: settings.cookieSecret,
    store: new MongoStore({
        db: settings.db,
    })
}));


app.use(function(req, res, next){
  console.log("app.usr local");
  res.locals.user = req.session.user;
  res.locals.post = req.session.post;
  var error = req.flash('error');
  res.locals.error = error.length ? error : null;
 
  var success = req.flash('success');
  res.locals.success = success.length ? success : null;
  next();
});


app.use('/', routes);
app.use('/users', users);


/// catch 404 and forward to error handler
app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

/// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
    app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});
module.exports = app;

## index.js代码
var express = require('express');
var app = express();
var router = express.Router();
var crypto = require('crypto');
var User = require('../models/user.js');
var Post = require("../models/post.js");
/* GET home page. */

router.get('/', function(req, res) {
  Post.get(null, function(err, posts) {
  if (err) {
    posts = [];
  }
  res.render('index', {
    title: '首页',
    posts: posts,
    user : req.session.user,
            success : req.flash('success').toString(),
            error : req.flash('error').toString()
  });
  });
  //res.render('index', { title: '首页' });
});

router.get("/reg", checkNotLogin);
router.get("/reg",function(req,res) {
  res.render("reg",{
    title : "用户注册"
  });
});

router.get("/login", checkNotLogin);
router.get("/login",function(req,res) {
  res.render("login",{
    title:"用户登录",
  });
});

router.get("/logout", checkLogin);
router.get("/logout",function(req,res) {
  req.session.user = null;
  req.flash('success', '退出成功');
  res.redirect('/');
});

router.get("/user", function(req,res){
  res.render("user",{
    title: "用户页面",
  });
});

router.post("/login", checkNotLogin);
router.post("/login",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', req.session.user.name + '登录成功');
    
    res.redirect('/');
  });
});

router.post("/reg", checkNotLogin);
router.post("/reg", function(req, res) {
  console.log(req.body['password']);
  console.log(req.body['password-repeat']);
  if(req.body['password-repeat'] != req.body['password']){
    req.flash('error', '两次输入的密码不一致');
    return res.redirect('/reg');
  }  
  var md5 = crypto.createHash('md5');
  var password = md5.update(req.body.password).digest('base64');

  var newUser = new User({
    name: req.body.username,
    password: password,
  });
  //检查用户名是否已经存在
  User.get(newUser.name, function(err, user) {
    if (user) {
      err = 'Username already exists.';
    }
    if (err) {
  req.flash('error', err);
  return res.redirect('/reg');
    }

    newUser.save(function(err) {
  if (err) {
    req.flash('error', err);
    return res.redirect('/reg');
  }
  req.session.user = newUser;
  req.flash('success', req.session.user.name+'注册成功');
  res.redirect('/');
    });
  });  
});

function checkNotLogin(req, res, next) {
  if (req.session.user) {
    req.flash('error', '用户已经登录');
    return res.redirect('/');
  }
  next();
}
function checkLogin(req, res, next) {
  if (!req.session.user) {
    req.flash('error', '用户尚未登录');
    return res.redirect('/login');
  }
  next();
}

router.post("/post",checkLogin);
router.post("/post",function(req,res) {
  var currentUser = req.session.user;
  var post = new Post(currentUser.name, req.body.post);
  post.save(function(err) {
    if (err) {
      req.flash('error', err);
      return res.redirect('/');
    }
    req.flash('success', '发表成功');
    res.redirect('/u/' + currentUser.name);
  });
});

router.get("/u/:user",function(req,res) {
  User.get(req.params.user, function(err, user) {
    if (!user) {
      req.flash('error', '用户不存在');
      return res.redirect('/');
    }
    Post.get(user.name, function(err, posts) {
      if (err) {
        req.flash('error', err);
        return res.redirect('/');
      }
      res.render('user', {
        title: user.name,
        posts: posts
      });
    });
  });
});
module.exports = router; 

##settings.js

module.exports = {
cookieSecret: 'microblogtony2014',
db: 'blog',
host: 'localhost',
}; 

package.json:

express-partials不需要装,这是ejs模板需要用到了。

#我装了并引用,jade模板就不工作了,费了我好长的时间去找问题。

{
  "name": "microblog",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "express": "~4.2.0",
    "static-favicon": "~1.0.0",
    "morgan": "~1.0.0",
    "cookie-parser": "~1.0.1",
    "body-parser": "~1.0.0",
    "debug": "~0.7.4",
    "jade": "~1.3.0",
    "mongodb": ">= 1.4.8",
    "connect-mongo": ">=0.1.7",
    "express-session": "~1.0.4",
    "connect-flash": "*"
  }
} 

##db.js

var settings = require('../settings'),
    Db = require('mongodb').Db,
    Connection = require('mongodb').Connection,
    Server = require('mongodb').Server;
module.exports = new Db(settings.db, new Server(settings.host, Connection.DEFAULT_PORT, {}), {safe: true}); 

##post.js

var mongodb = require('./db');

function Post(username,post,time) {
  this.user = username;
  this.post = post;

  if(time) {
    this.time = time;
  } else {
    this.time = new Date();
  }
};

module.exports = Post;

Post.prototype.save = function save(callback) {

  var post = {
    user: this.user,
    post: this.post,
    time: this.time,
  };
  mongodb.open(function(err, db) {
    if (err) {
      return callback(err);
    }

    db.collection('posts', function(err, collection) {
      if (err) {
        mongodb.close();
        return callback(err);
      }

      // collection.ensureIndex('user');

      collection.insert(post, {safe: true}, function(err, post) {
        mongodb.close();
        callback(err, post);
      });
    });
  });
};

Post.get = function get(username, callback) {
  mongodb.open(function(err, db) {
    if (err) {
      return callback(err);
    }

    db.collection('posts', function(err, collection) {
      if (err) {
        mongodb.close();
        return callback(err);
      }
      var query = {};
      if (username) {
        query.user = username;
      }
      collection.find(query).sort({time: -1}).toArray(function(err, docs) {
        mongodb.close();
        if (err) {
          callback(err, null);
        }

        var posts = [];
        docs.forEach(function(doc, index) {
          var post = new Post(doc.user, doc.post, doc.time);
          posts.push(post);
        });
        callback(null, posts);
      });
    });
  });
}; 

##user.js

var mongodb = require('./db');

function User(user) {
  this.name = user.name;
  this.password = user.password;
};

module.exports = User;

//存入Mongodb的文档
User.prototype.save = function save(callback) {
  var user = {
    name: this.name,
    password: this.password,
  };

  mongodb.open(function(err, db) {
    if (err) {
      return callback(err);
    }
    //读取users集合
    db.collection('users', function(err, collection) {
      if (err) {
        mongodb.close();
        return callback(err);
      }
      // 为name属性添加索引
      // collection.ensureIndex('name', {unique: true});

      //写入user文档
      collection.insert(user, {safe: true}, function(err, user) {
        mongodb.close();
        callback(err, user);
      });
    });
  });
}

User.get = function get(username, callback) {
  mongodb.open(function(err, db) {
    if (err) {
      return callback(err);
    }
    //读取users集合
    db.collection('users', function(err, collection) {
      if (err) {
        mongodb.close();
        return callback(err);
      }
      //查找name属性为username的文档
      collection.findOne({name: username}, function(err, doc) {
        mongodb.close();
        if (doc) {
          //封装文档为User对象
          var user = new User(doc);
          callback(err, user);
        } else {
          callback(err, null);
        }
      });
    });
  });
}; 

##layout.jade

doctype html
html
  head
    title= title
    link(rel='stylesheet', href='/stylesheets/bootstrap.css')
    link(rel='stylesheet', href='/stylesheets/style.css')
    link(rel='stylesheet', href='/stylesheets/bootstrap-responsive.css')
    script(src='/javascripts/jquery.js')
    script(src='/javascripts/bootstrap.js')  
  body
    div.navbar.navbar-fixed-top
      div.narbar-inner
        div.container
          a(class='btn btn-navbar' data-toggle='collapse' data-target='.nav-collapse') span.icon-bar span.icon-bar span.icon-bar
          a(class='brand' href='/') Microblog
          div.nav-collapse
            ul.nav
              li.active 
                a(href='/') 首页
              - if (!user)
                li
                  a(href='/login') 登录
                li
                  a(href='/reg') 注册
              - else
                li
                  a(href='/logout') 退出
    div#container.container
      - if (success)
        div.alert.alert-success= success
      - if (error)
        div.alert.alert-error= error      
      block content
    div#footer.footer
      !='<hr />'
      p
        a(href='http://www.hotelanywhere.cn' target='_blank') Tony Zhang [@2014](/user/2014) All Right Reserved 

##index.jade

extends layout
block content
   - if (!user)
     div.hero-unit
       h1 Welcome to Microblog
       p Microblog是一个基于Node.js的微博系统。
       p
         a(class='btn btn-primary btn-large' href='/login') 登录
         a(class='btn btn-large' href='/reg') 注册
   - else
     include ./say.jade
   include ./posts.jade 

##reg.jade

extends layout

block content
 
  form(class='form-horizontal' method='post')
    fieldset
      legend 用户注册
      div.control-group
        label(class='control-label' for='username') 用户名
        div.controls
          input(type='text' class='input-xlarge' id='username' name='username')
          p(class='help-block') 你的账户名称,用于登录和显示
      div.control-group
        label(class='control-label' for='password') 密码
        div.controls
          input(type='password' class='input-xlarge' id='password' name='password')
      div.control-group
        label(class='control-label' for='password') 请再次输入密码
        div.controls
          input(type='password' class='input-xlarge' id='password-repeat' name='password-repeat')
      div.form-actions
        button(type='submit' class='btn btn-primary') 注册 

##login.jade

extends layout

block content

  form( class='form-horizontal' method='post')
    fieldset
      legend 用户登录
        div.control-group
          label(class='control-label' for='username') 用户名
          div.controls
            input(type='text' class='input-xlarge' id='username' name='username')
        div.control-group
          label(class='control-label' for='username') 密码
          div.controls
            input(type='password' class='input-xlarge' id='password' name='password')
        div.form-actions
          button(type='submit' class='btn btn-primary') 登录 

##say.jade

form( class='well form-inline center' method='post' action='/post' style='text-align:center;')
    input(type='text' class='span8' id='post' name='post')
    button(type='submit' class='btn btn-success') 发言 

##posts.jade

- for (var i = 3; i < posts.length+3; i = i + 3)
  div.row
  - for(var j = i-3; j < i && j < posts.length; j++)
    div.span4
    h2
       a(href='/u/'+posts[j].user)=posts[j].user 
        !='说'

    p!='<small>' + posts[j].time + '</small>'
    p=posts[j].post 

##user.jade: 以前我以为不需这个模板,后来才发现这个模板的重要,是查看每个用户的发言的必要的模板

extends layout
block content
  include narbar.jade
  div.jumbotron
    div.container
      - if (user)
        include ./say.jade
  div.container
    include ./posts.jade
    include footer.jade 

##error.jade

extends layout

block content
  h1= message
  h2= error.status
  pre #{error.stack} 

原文引自:http://cnodejs.org/topic/53f23e198f44dfa35129c43b

回复 · 0

发表回复

你可以在回复中 @ 其他人