美文网首页我爱编程服务端开发
MongoDB + Express 搭建电影网站笔记

MongoDB + Express 搭建电影网站笔记

作者: 已经不在简书了 | 来源:发表于2018-06-06 20:52 被阅读46次

    imooc 网项目源码: https://github.com/shinytang6/imoocMovie
    项目地址: https://github.com/husky520/movie-site.git

    0. 准备工作

    homebrew 安装 mongodb

    brew install mongodb
    

    注意:
    如果出现以下问题

    mongodb: A full installation of Xcode.app 8.3.2 is required to compile this software.
    Installing just the Command Line Tools is not sufficient.
    Xcode 8.3.2 cannot be installed on macOS 10.11.
    You must upgrade your version of macOS.
    Error: An unsatisfied requirement failed this build.
    

    可以直接安装低版本的 mongodb, 例如 mongodb@3.4

    创建默认数据库存放位置:

    sudo mkdir /data
    sudo mkdir /data/db
    

    启动数据库

    sudo mongod
    

    1. 项目简介

    项目 UI 使用 bootstrap, 后台使用 node.js 搭建, 具体为 express 搭建服务器, moogoose 连接 mongodb 数据库, jade 作为模版引擎, 另外还有 moment.js 用来格式化时间等 ...

    目录结构预览

    - movie-site         // 项目目录
      - schemas          // mongoose schemas
        movie.js         // scheme
      - models           // mongoose models
        movie.js         // model
      - views            // 静态资源目录
        - includes       // 页面所包含的公共部分模版
          head.jade      // bootstrap 和 jquery 引入
          header.jade    // 页面基本信息
        - pages          // 不同页面内容模版
          detail.jade    // 电影详情页
          list.jade      // 电影列表页
          index.jade     // 电影网站首页
          admin.jade     // 后台录入页
        layout.jade      // 布局框架
      app.js             // 入口文件
    

    页面路由

    首页     http://localhost:3000/
    电影列表  http://localhost:3000/list
    电影详情  http://localhost:3000/movie/:id
    后台录入  http://localhost:3000/admin/movie
    后台更新  http://localhost:3000/admin/update/:id
    

    2. 基本页面和初步的入口文件

    • 新建 app.js 入口文件
    const express = require('express')
    const path = require('path')
    const bodyParser = require('body-parser')
    
    const port = process.env.PORT || 3000
    const app = express()
    
    app.set('views', './views')
    app.set('view engine', 'jade')
    
    app.use(bodyParser.urlencoded({extended: false}))
    app.use(bodyParser.json())
    
    app.use(express.static(path.join(__dirname, 'bower_components')))
    app.listen(port)
    
    console.log('Movie Site 已启动 ! 端口为: ', port)
    
    // 配置路由
    // index page
    app.get('/', (req, res) => {
        res.render('pages/index', {
            title: '电影首页',
            movies: movies  // 传入 mock 数据
        })
    })
    
    // movie page
    app.get('/movie/:id', (req, res) => {
        res.render('pages/detail', {
            title: '电影详情: ' + movie.title,
            movie: movie
        })
    })
    
    // list page
    app.get('/list', (req, res) => {
        res.render('pages/list', {
            title: '电影列表',
            movies: movies
        })
    })
    
    // admin page
    app.get('/admin/movie', (req, res) => {
        res.render('pages/admin', {
            title: '后台录入',
            movie: {  // 录入时传入空数据给页面表单
                doctor: '',
                country: '',
                title: '',
                year: '',
                poster: '',
                language: '',
                flash: '',
                summary: ''
            }
        })
    })
    
    // admin update movie 和录入同页面
    app.get('/admin/update/:id', function (req, res) {
        res.render('pages/admin', {
            title: '更新电影:' + movie.title,
            movie: movie  // 更新时传入原来数据, 在此基础上修改
        })
    })
    
    // admin post movie 该页面为接收录入, 更新页提交的数据
    app.post('/admin/movie/new', function (req, res) {
        // ...
    })
    

    • 各页面模版

    layout.jade

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

    head.jade - ( 此处使用绝对路径, 否则子页面无法正确访问到静态资源 ! )

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

    header.jade

    .container
        .row
            .page-header
                h1= title
    

    index.jade

    extends ../layout
    
    block content
        .container
            .row
                each item in movies
                    .col-6.col-md-3
                        .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.createdAt).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}") 删除
    
    

    detail.jade

    extends ../layout
    
    block content
        .container
            .row
                .col-12
                    video(src="#{movie.flash}", width="100%", controls="controls")
                .col-12
                    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
    

    admin.jade

    extends ../layout
    
    block content
        .container
            form(method="post", action="/admin/movie/new")
                //- 使用隐藏的 input 标签提交电影的 id
                input(type="hidden", name="_id", value="#{movie._id}")
                .form-group.row
                    label.col-sm-2.col-form-label(for="inputTitle") 电影名字
                    .col-sm-10
                        input#inputTitle.form-control(type="text", name="title", value="#{movie.title}")
                .form-group.row
                    label.col-sm-2.col-form-label(for="inputDoctor") 电影导演
                    .col-sm-10
                        input#inputDoctor.form-control(type="text", name="doctor", value="#{movie.doctor}")
                .form-group.row
                    label.col-sm-2.col-form-label(for="inputCountry") 国家
                    .col-sm-10
                        input#inputCountry.form-control(type="text", name="country", value="#{movie.country}")
                .form-group.row
                    label.col-sm-2.col-form-label(for="inputLanguage") 语种
                    .col-sm-10
                        input#inputLanguage.form-control(type="text", name="language", value="#{movie.language}")
                .form-group.row
                    label.col-sm-2.col-form-label(for="inputPoster") 海报地址
                    .col-sm-10
                        input#inputPoster.form-control(type="text", name="poster", value="#{movie.poster}")
                .form-group.row
                    label.col-sm-2.col-form-label(for="inputFlash") 片源地址
                    .col-sm-10
                        input#inputFlash.form-control(type="text", name="flash", value="#{movie.flash}")
                .form-group.row
                    label.col-sm-2.col-form-label(for="inputYear") 上映年份
                    .col-sm-10
                        input#inputYear.form-control(type="text", name="year", value="#{movie.year}")
                .form-group.row
                    label.col-sm-2.col-form-label(for="inputSummary") 电影简介
                    .col-sm-10
                        textarea#inputSummary.form-control(name="summary")
                .form-group.row
                    .offset-sm-2.col-sm-10
                        button.btn.btn-primary(type="submit") 录入
    

    • mongoose 创建数据库模型

    在 schemas 目录下创建 movie.js 文件, 导出 MovieSchema

    movie.js

    const mongoose = require('mongoose')
    
    // 设计数据库结构
    const MovieSchema = new mongoose.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()
            }
        }
    })
    
    // Schema 钩子, 以下用以在保存时创建或更新修改时间
    MovieSchema.pre('save', function (next) {
        if (this.isNew) {
            this.meta.createAt = this.meta.updateAt = Date.now()
        } else {
            this.meta.updateAt = Date.now()
        }
        next()
    })
    
    // 静态方法, fetch 查询所有数据, findById 查询单条数据
    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, 导出 model

    const mongoose = require('mongoose')
    const MovieSchema = require('../schemas/movie')
    
    const Movie = mongoose.model('Movie', MovieSchema)
    
    module.exports = Movie
    

    • 连接数据库

    app.js

    const mongoose = require('mongoose')
    mongoose.connect('mongodb://localhost/movie-site')  // movie-site 为数据库名
    

    • 数据的增删改查

    首先引入创建的 model

    const Movie = require('./models/movie')
    

    // 创建一个数据
    const data = new Movie({
        // 数据内容
        // title: 'title'
        // ....
    })
    
    // 存入数据
    Movie.save(function (err, data) {
        if (err) {
            console.error(err)
        }
        // 其他操作 ...
    })
    

    // 删除 _id 为 id 的项, 并为结果作出相应的回应
    Movie.remove({'_id': id}, function (err) {
        if (err) {
            console.error(err)
            res.json({status: 0})
        } else {
            res.json({status: 1})
        }
    })
    

    // 这里使用一个插件 ‘underscore’
    const underscore = require('underscore')
    
    // 在原数据的基础上拓展新数据 (更新数据)
    const data = underscore.extend(oldData, newData)
    
    // 存入数据库
    Movie.save(function (err, data) {
        if (err) {
            console.error(err)
        }
        // 其他操作 ...
    })
    

    // 使用在 ‘/schemas/ movie.js’ 中所封装的静态方法进行查询
    
    // 查询所有数据
    Movie.fetch(function (err, data) {
        if (err) {
            console.error(err)
        }
        // 其他对已查询到的 data 的操作 ...
    })
    
    // 按 id 查找数据
    Movie.findById(function (err, data) {
        if (err) {
            console.error(err)
        }
        // 其他对已查询到的 data 的操作 ...
    })
    

    3. 注意点

    1. jQuery.slim.js 是精简版, 其中不含 $.ajax
    2. 在列表页删除了一条数据后, 可以刷新页面, 以保证列表页和数据库的同步 (无法通过重定向实现刷新)

    最终的源码参考开头的链接

    相关文章

      网友评论

        本文标题:MongoDB + Express 搭建电影网站笔记

        本文链接:https://www.haomeiwen.com/subject/fvevsftx.html