Node + MongoDB 建站 1期

项目初始化

建立Imooc文件夹,在文件夹根目录下安装模块

npm install express  jade  mongoose  bootstrap@3
npm install bower -g

项目结构目录如下

- Imooc/
    -node_modules/
    -bower_components/
    -views/
        -index.jade
        -detail.jade
        -admin.jade
        -list.jade
    -app.js

测试地址

localhost:3000/
localhost:3000/movie/1
localhost:3000/admin/movie
localhost:3000/admin/list

入口文件app.js

var express = require('express')
var app = express()

app.set('view engine','jade')
app.set('port',3000)

app.get('/',function(req,res){
    res.render('index',{title:'imooc'})
})

创建入口文件及视图

修改app.js文件,配置路由

var express = require('express')
var port = process.env.port || 3000 
var app = express()

app.set('views', './views')
app.set('view engine','jade')
app.listen(port)

console.log('Imooc started on port' + port)

//index page
app.get('/',function(req,res){
    res.render('index',{title:'imooc 首页'})
})

//detail page
app.get('/movie/:id',function(req,res){
    res.render('detail',{title:'imooc 详情页'})
})

//admin page
app.get('/admin/movie',function(req,res){
    res.render('admin',{title:'imooc 后台录入页'})
})

//list page
app.get('/admin/list',function(req,res){
    res.render('list',{title:'imooc 列表页'})
})

创建4个jade视图,代码如下

doctype
html
    head
        meta(chareset="utf-8")
        title #{title}
    body
        h1 #{title}

在cmd命令中以node app 启动项目,查看浏览器

页面开发

创建如下view结构



head文件中引入js css

link(href="/bootstrap/dist/css/bootstrap.min.css", rel="stylesheet")
script(src="/jquery/dist/jquery.min.js")
script(src="/bootstrap/dist/js/bootstrap.min.js")

header文件中为公用代码

.container
  .row
    .page-header
      h1= title
      small 重度科幻迷

layout文件如下

doctype
html
    head
        meta(chareset="utf-8")
        title #{title}
        include ./includes/head
    body
        include ./includes/header
        block content
        h1 #{title}

修改index,继承layout,根据movies创建thumbnail缩略图

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
                      h4 #{item.title}
                      p: a.btn.btn-primary(href="/movie/#{item._id}", role="button") 观看预告片

修改detail,左边flash插件,右边movie内容

extends ../layout

block content
  .container
    .row
      .col-md-7
        embed(src="#{movie.flash}", allowFullScreen="true", quality="high", width="720", height="600", align="middle", type="application/x-shockwave-flash")
      .col-md-5
        .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

修改admin,加入form表单组件

extends ../layout

block content
 .container
   .row
     form.form-horizontal(method="post", action="/admin/movie")
       .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="uploadPoster") 海报上传
         .col-sm-10
           input#uploadPoster(type="file", name="uploadPoster")
       .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]")= movie.summary
       .form-group
         .col-sm-offset-2.col-sm-10
         button.btn.btn-default(type="submit") 录入

修改list 加入table组件

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/movie/update/#{item._id}") 修改
              td
                button.btn.btn-danger.del(type="button", data-id="#{item._id}") 删除

修改app.js ,添加path模块来制定文件夹,在page中传入mock数据

var express = require('express')
var path = require('path')
var port = process.env.PORT || 3000
var app = express()
var bodyParser = require('body-parser')

app.set('views', './views/pages')
app.set('view engine', 'jade')
app.use(bodyParser.urlencoded({extended:true}))
app.use(express.static(path.join(__dirname, 'node_modules')))
app.listen(port)

console.log('imooc stated on port ' + port)

//index page
app.get('/', function(req, res) {
    res.render('index', {
        title: 'imooc 首页',
        movies: [{
            title: '机械战警',
            _id: 1,
            poster: 'http://r3.ykimg.com/05160000530EEB63675839160D0B79D5'
        },
        {
            title: '机械战警',
            _id: 2,
            poster: 'http://r3.ykimg.com/05160000530EEB63675839160D0B79D5'
        },
        {
            title: '机械战警',
            _id: 3,
            poster: 'http://r3.ykimg.com/05160000530EEB63675839160D0B79D5'
        },
        {
            title: '机械战警',
            _id: 4,
            poster: 'http://r3.ykimg.com/05160000530EEB63675839160D0B79D5'
        },
        {
            title: '机械战警',
            _id: 5,
            poster: 'http://r3.ykimg.com/05160000530EEB63675839160D0B79D5'
        },
        {
            title: '机械战警',
            _id: 6,
            poster: 'http://r3.ykimg.com/05160000530EEB63675839160D0B79D5'
        }]
    })
})

//detail page
app.get('/movie/:id', function(req, res) {
    res.render('detail', {
        title: 'imooc 详情页',
        movie: {
        doctor: '何塞·帕迪里亚',
        country: '美国',
        title: '机械战警',
        year: '2014',
        poster: 'http://r3.ykimg.com/05160000530EEB63675839160D0B79D5',
        language: '英语',
        flash: 'http://player.youku.com/player.php/sid/XNjA1Njc0NTUy/v.swf',
        summary: '《机械战警》是由何塞·帕迪里亚执导,乔尔·金纳曼、塞缪尔·杰克逊、加里·奥德曼等主演的一部科幻电影,改编自1987年保罗·范霍文执导的同名电影。影片于2014年2月12日在美国上映,2014年2月28日在中国大陆上映。影片的故事背景与原版基本相同,故事设定在2028年的底特律,男主角亚历克斯·墨菲是一名正直的警察,被坏人安装在车上的炸弹炸成重伤,为了救他,OmniCorp公司将他改造成了生化机器人“机器战警”,代表着美国司法的未来。'
        }
    })
})

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

//list page
app.get('/admin/list', function(req, res) {
    res.render('list', {
        title: 'imooc 列表页',
        movies: [{
            title: '机械战警',
            _id: 1,
            doctor: '何塞·帕迪里亚',
            country: '美国',
            year: 2014,
            language: '英语',
            flash: 'http://player.youku.com/player.php/sid/XNjA1Njc0NTUy/v.swf',
            summary: '《机械战警》是由何塞·帕迪里亚执导,乔尔·金纳曼、塞缪尔·杰克逊、加里·奥德曼等主演的一部科幻电影,改编自1987年保罗·范霍文执导的同名电影。影片于2014年2月12日在美国上映,2014年2月28日在中国大陆上映。影片的故事背景与原版基本相同,故事设定在2028年的底特律,男主角亚历克斯·墨菲是一名正直的警察,被坏人安装在车上的炸弹炸成重伤,为了救他,OmniCorp公司将他改造成了生化机器人“机器战警”,代表着美国司法的未来。'
        }]
    })
})

启动应用查看浏览器


项目数据库实现

Mongo DB 通过 Schema Model Document来进行数据库的定义操作



建立模式 schemas/movie.js,定义MovieSchema结构,添加pre方法及静态方法,最后将其导出

var mongoose = require('mongoose')
var Schema = mongoose.Schema

var MovieSchema = new Schema({
  doctor: String,
  title: String,
  language: String,
  country: String,
  summary: String,
  flash: String,
  poster: String,
  year: Number,
  meta: {
    createAt: {
      type: Date,
      default: Date.now()
    },
    updateAt: {
      type: Date,
      default: Date.now()
    }
  }
})

MovieSchema.pre('save', function(next) {
    if (this.isNew) {
      this.meta.createAt = this.meta.updateAt = Date.now()
    }
    else {
      this.meta.updateAt = Date.now()
    }  
    next()
  })
  
MovieSchema.statics = {
    fetch: function(cb) {
      return this
        .find({})
        .sort('meta.updateAt')
        .exec(cb)
    },
    findById: function(id, cb) {
      return this
        .findOne({_id: id})
        .exec(cb)
    }
  }
  
module.exports = MovieSchema

建立模型 models/movie.js,通过MovieSchema对模式进行编译建立模型,最后将其导出

var mongoose = require('mongoose')
var MovieSchema = require('../schemas/movie')
var Movie = mongoose.model('Movie', MovieSchema)

module.exports = Movie

修改app.js如下,安装npm install underscore moment,本地MongoDB创建DB imooc。
index page中,Movie模型调用fetch方法得到movies数据集
detail page中,Movie模型调用findById方法,通过req中参数取得id
admin page中,提交表单调用post方法,id为空创建新对象,id不为空扩展对象
list page中,与index类似读取movies数据集
添加update路由

var express = require('express')
var path = require('path')
var mongoose = require('mongoose')
var _ = require('underscore')
var Movie = require('./models/movie')
var port = process.env.PORT || 3000
var app = express()
var bodyParser = require('body-parser')

mongoose.connect('mongodb://localhost/imooc')

app.set('views', './views/pages')
app.set('view engine', 'jade')
app.use(bodyParser.urlencoded({extended:true}))
app.use(express.static(path.join(__dirname, 'node_modules')))
app.locals.moment = require('moment')
app.listen(port)

console.log('imooc stated on port ' + port)

//index page
app.get('/', function(req, res) {
    Movie.fetch(function(err,movies){
        if (err) {
            console.log(err)
        }

        res.render('index', {
            title: 'imooc 首页',
            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: 'imooc 详情页',
            movie: movie
        })
    })

})

//admin page
app.get('/admin/movie', function(req, res) {
    res.render('admin', {
        title: 'imooc 后台录入页',
        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: 'Imooc 后台更新页',
                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

    if (id !=='undefined') {
        Movie.findById(id, function(err,movie){
            if (err){
                console.log(err)
            }

            _movie = _.extend(movie, movieObj)
            _movie.save(function(err,movie) {
                if (err){
                    console.log(err)
                }
                res.redirect('/movie/'+movie._id)
            })
        })
    } else {
        _movie = new Movie({
            dector: movieObj.dector,
            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: 'imooc 列表页',
            movies: movies
        })
    })
})

在admin.jade添加隐藏的input,记录id

block content
  .container
    .row
      form.form-horizontal(method="post", action="/admin/movie/new")
        input(type="hidden",name="movie[_id]", value="#{movie._id}" )
        .form-group
          label.col-sm-2.control-label(for="inputTitle") 电影名字
          .col-sm-10

删除功能及配置文件

创建public目录,创建文件public/js/admin.js,添加异步删除方法

$(function() {
    $('.del').click(function(e) {
      var target = $(e.target)
      var id = target.data('id')
      var tr = $('.item-id-' + id)
  
      $.ajax({
        type: 'DELETE',
        url: '/admin/list?id=' + id
      })
      .done(function(results) {
        if (results.success === 1) {
          if (tr.length > 0) {
            tr.remove()
          }
        }
      })
    })
 })

在list.jade文件末尾引入admin.js

script(src="/js/admin.js")

创建.bowerrc文件,制定bower安装目录

{
    "directory": "public/libs"
}

用bower安装bootstrap bower install bootstrap@3
修改app.js中path路径 app.use(express.static(path.join(__dirname, 'public')))
修改head.jade

link(href="/libs/bootstrap/dist/css/bootstrap.min.css", rel="stylesheet")
script(src="/libs/jquery/dist/jquery.min.js")
script(src="/libs/bootstrap/dist/js/bootstrap.min.js")

在app.js添加delete路由

//list delete movie
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})
            }
        })
    }
})

前端配置文件生成 bower init
后端配置文件生成 npm init

上传项目到GIT

在码云上创建项目



复制SSH地址



项目目录下创建.gitignore文件,忽略下列文件夹
/node_modules/
/public/libs

在项目根目录下启用Git Bash,git init初始化
git remote add origin (ssh copy)将本地目录与github关联
git pull origin master拉取master分支
git status查看状态
git add .把文件追踪上
git commit -am 'test' / git ca 'test'提交并加上test注释
git push --set-upstream origin master推送到远程master分支
git checkout -b v1.0.0创建v1.0.0分支并checkout
git branch查看分支



查看github

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容