Node.js+MongoDB建站攻略(一期)参考源码

此程序基于[慕课网](http://www.imooc.com/learn/75)Scott老师的Node.js+MongoDB建站攻略(第一期)视频教程编写,当前所有模块程序均为最新版本,截止2017年4月,代码中包含详细的注释,非常适合初学者。


源码下载地址 :https://github.com/itPoet/i_movie


项目目录结构:


首先schemas下的movie.js

var mongoose = require('mongoose');

var movieSchema = new mongoose.Schema({
    title: String,
    doctor: String,
    language: String,
    country: String,
    summary: String,
    flash: String,
    poster: String,
    year: Number,
    // meta 更新或录入数据的时间记录
    meta: {
        createAt: {
            type: Date,
            default: Date.now()
        },
        updateAt: {
            type: Date,
            default: Date.now()
        },
    }
});

// movieSchema.pre 表示每次存储数据之前都先调用这个方法
movieSchema.pre('save', function (next) {
    if (this.isNew) {
        this.meta.createAt = this.meta.updateAt = Date.now();
    } else {
        this.meta.updateAt = Date.now();
    }
    next();
});

// movieSchema 模式的静态方法
movieSchema.statics = {
    fetch: function (cb) {
        return this
            .find({})
            .sort('meta.updateAt')
            .exec(cb)
    },
    findById: function (id, cb) {
        return this
            .findOne({_id: id})
            .exec(cb)
    }
}

// 导出movieSchema模式
module.exports = movieSchema;

models下movie.js

var mongoose = require('mongoose');
var movieSchema = require('../schemas/movie.js'); //引入'../schemas/movie.js'导出的模式模块

// 编译生成movie模型
var movie = mongoose.model('movie', movieSchema);

// 将movie模型[构造函数]导出
module.exports = movie;
关于mongoose:

https://cnodejs.org/topic/504b4924e2b84515770103dd


最主要的逻辑,程序入口 app.js:

var express = require('express');  // 加载express模块
var app = express(); // 启动Web服务器
var port = process.env.PORT || 3000; // 设置端口号:3000
app.listen(port); // 监听 port[3000]端口
console.log('website start on port' + port);
var path = require('path');
// 引入path模块的作用:因为页面样式的路径放在了bower_components,告诉express,请求页面里所过来的请求中,如果有请求样式或脚本,都让他们去bower_components中去查找
var mongoose = require('mongoose'); // 加载mongoose模块
mongoose.connect('mongodb://localhost:27017/imovie'); // 连接mongodb本地数据库imovie
console.log('MongoDB connection success!');
/*  mongoose 简要知识点补充
* mongoose模块构建在mongodb之上,提供了Schema[模式]、Model[模型]和Document[文档]对象,用起来更为方便。
* Schema对象定义文档的结构(类似表结构),可以定义字段和类型、唯一性、索引和验证。
* Model对象表示集合中的所有文档。
* Document对象作为集合中的单个文档的表示。
* mongoose还有Query和Aggregate对象,Query实现查询,Aggregate实现聚合。
* */
app.locals.moment = require('moment'); // 载入moment模块,格式化日期
var serveStatic = require('serve-static');  // 静态文件处理
app.use(serveStatic('public')); // 路径:public
var bodyParser = require('body-parser');
// 因为后台录入页有提交表单的步骤,故加载此模块方法(bodyParser模块来做文件解析),将表单里的数据进行格式化
app.use(bodyParser.urlencoded({extended: true}));
var _underscore = require('underscore'); // _.extend用新对象里的字段替换老的字段
app.set('views', './views/pages');     // 设置视图默认的文件路径
app.set('view engine', 'jade');  // 设置视图引擎:jade
var movie = require('./models/movie.js'); // 载入mongoose编译后的模型movie
// 编写主要页面路由
// index page 首页
app.get('/', function (req, res) {
    movie.fetch(function (err, movies) {
        if (err) {
            console.log(err);
        }
        res.render('index', {  // 渲染index 首页
            title: '电影首页',
            movies: movies
        });
    });
});

// detail page 详情页
app.get('/movie/:id', function (req, res) {
    var id = req.params.id;
    movie.findById(id, function (err, movie) {
        res.render('detail', {
            title: '电影:' + movie.title,
            movie: movie
        });
    });
});

// admin page 后台录入页
app.get('/admin/movie', function (req, res) {
    res.render('admin', {
        title: '后台录入页',
        movie: {
            title: '',
            doctor: '',
            country: '',
            year: '',
            poster: '',
            flash: '',
            summary: '',
            language: ''
        }
    });
});

// admin update movie 后台更新页
app.get('/admin/update/:id', function (req, res) {
    var id = req.params.id;
    if (id) {
        movie.findById(id, function (err, movie) {
            res.render('admin', {
                title: '后台更新页',
                movie: movie
            });
        });
    }
});

// admin post movie 后台录入提交
app.post('/admin/movie/new', function (req, res) {
    var id = req.body.movie._id;
    var movieObj = req.body.movie;
    var _movie = null;
    if (id !== 'undefined') { // 已经存在的电影数据
        movie.findById(id, function (err, movie) {
            if (err) {
                console.log(err);
            }
            _movie = _underscore.extend(movie, movieObj); // 用新对象里的字段替换老的字段
            _movie.save(function (err, movie) {
                if (err) {
                    console.log(err);
                }
                res.redirect('/movie/' + movie._id);
            });
        });
    } else {  // 新加的电影
        _movie = new movie({
            doctor: movieObj.doctor,
            title: movieObj.title,
            country: movieObj.country,
            language: movieObj.language,
            year: movieObj.year,
            poster: movieObj.poster,
            summary: movieObj.summary,
            flash: movieObj.flash
        });
        _movie.save(function (err, movie) {
            if (err) {
                console.log(err);
            }
            res.redirect('/movie/' + movie._id);
        });
    }
});

// list page 列表页
app.get('/admin/list', function (req, res) {
    movie.fetch(function (err, movies) {
        if (err) {
            console.log(err);
        }
        res.render('list', {
            title: '电影列表',
            movies: movies
        });
    });
});

// list delete movie data 列表页删除电影
app.delete('/admin/list', function (req, res) {
    var id = req.query.id;
    if (id) {
        movie.remove({_id: id}, function (err, movie) {
            if (err) {
                console.log(err);
            } else {
                res.json({success: 1});
            }
        });
    }
});
4个界面,使用了jade模板:
admin.jade:
extends ../layout

block content
  .container
    .row
      form.form-horizontal(method="post", action="/admin/movie/new")
        input(type="hidden", name="movie[_id]", value="#{movie._id}")
        //- 隐藏表单域,用来更新电影数据,存储电影ID
        .form-group
          label.col-sm-2.control-label(for="inputTitle") 电影名称
          .col-sm-10
            input#inputTitle.form-control(type="text", name="movie[title]", value="#{movie.title}")
        .form-group
          label.col-sm-2.control-label(for="inputDoctor") 电影导演
          .col-sm-10
            input#inputDoctor.form-control(type="text", name="movie[doctor]", value="#{movie.doctor}")
        .form-group
          label.col-sm-2.control-label(for="inputCountry") 国家
          .col-sm-10
            input#inputCountry.form-control(type="text", name="movie[country]", value="#{movie.country}")
        .form-group
          label.col-sm-2.control-label(for="inputLanguage") 语种
          .col-sm-10
            input#inputLanguage.form-control(type="text", name="movie[language]", value="#{movie.language}")
        .form-group
          label.col-sm-2.control-label(for="inputPoster") 海报地址
          .col-sm-10
            input#inputPoster.form-control(type="text", name="movie[poster]", value="#{movie.poster}")
        .form-group
          label.col-sm-2.control-label(for="inputFlash") 片源地址
          .col-sm-10
            input#inputFlash.form-control(type="text", name="movie[flash]", value="#{movie.flash}")
        .form-group
          label.col-sm-2.control-label(for="inputYear") 上映年代
          .col-sm-10
            input#inputYear.form-control(type="text", name="movie[year]", value="#{movie.year}")
        .form-group
          label.col-sm-2.control-label(for="inputSummary") 电影简介
          .col-sm-10
            textarea#inputSummary.form-control(type="text", name="movie[summary]", value="#{movie.summary}")
        .form-group
          .col-sm-offset-2.col-sm-10
          button.btn.btn-default(type="submit") 录入

detail.jade:
extends ../layout

block content
  .container
    .row
      .col-md-7
        embed(src="#{movie.flash}", allowFullScreen="true", quality="high", width="700", height="450", align="middle", type="application/x-shockwave-flash")
      .col-md-5
        dl.dl-horizontal
          dt 电影名称
          dd= movie.title
          dt 导演
          dd= movie.doctor
          dt 国家
          dd= movie.country
          dt 语言
          dd= movie.language
          dt 上映年份
          dd= movie.year
          dt 简介
          dd= movie.summary
index.jade:
extends ../layout
block content
  .container
    .row
      each item in movies
        .col-md-2
          .thumbnail
            a(href="/movie/#{item._id}")
              img(src="#{item.poster}", alt="#{item.title}")
            .caption
              h3 #{item.title}
              p: a.btn.btn-primary(href="/movie/#{item._id}", role="button") 观看预告片


list.jade:
extends ../layout
block content
  .container
    .row
      table.table.table-hover.table-bordered
        thead
          tr
            th 电影名称
            th 导演
            th 国家
            th 上映年份
            th 录入时间
            th 查看
            th 更新
            th 删除
        tbody
          each item in movies
            tr(class="item-id-#{item._id}")
              td #{item.title}
              td #{item.doctor}
              td #{item.country}
              td #{item.year}
              td #{moment(item.meta.updateAt).format('MM/DD/YYYY')}
              td: a(target="_blank", href="../movie/#{item._id}") 查看
              td: a(target="_blank", href="../admin/update/#{item._id}") 修改
              td
                button.btn.btn-danger.del(type="button", data-id="#{item._id}") 删除
  script(src="/js/admin.js")
运行效果图:



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值