美文网首页
Node + MongoDB 建站 2期 -1

Node + MongoDB 建站 2期 -1

作者: LiuliuZhang | 来源:发表于2018-04-20 10:05 被阅读0次

    Grant

    npm install grunt grant-cli -g全局安装grant及grant命令行工具,

    npm install grunt-contrib-watch --save-dev  //文件修改重新执行注册的任务
    npm install grunt-nodemon --save-dev    //监听app.js修改
    npm install grunt-concurrent --save-dev //慢任务如sass
    

    建立grunt.js文件

    module.exports = function(grunt) {
    
      grunt.initConfig({
        watch: {
          jade: {
            files: ['views/**'],
            options: {
              livereload: true
            }
          },
          js: {
            files: ['public/js/**', 'models/**/*.js', 'schemas/**/*.js'],
            //tasks: ['jshint'],
            options: {
              livereload: true
            }
          }
        },
    
        nodemon: {
          dev: {
            options: {
              file: 'app.js',
              args: [],
              ignoredFiles: ['README.md', 'node_modules/**', '.DS_Store'],
              watchedExtensions: ['js'],
              watchedFolders: ['app','config'],
              debug: true,
              delayTime: 1,
              env: {
                PORT: 3000
              },
              cwd: __dirname
            }
          }
        },
    
        concurrent: {
          tasks: ['nodemon', 'watch'],
          options: {
            logConcurrentOutput: true
          }
        }
      })
    
      grunt.loadNpmTasks('grunt-contrib-watch')
      grunt.loadNpmTasks('grunt-nodemon')
      grunt.loadNpmTasks('grunt-concurrent')
      grunt.option('force', true)  //避免一些错误影响后续执行
    
      grunt.registerTask('default', ['concurrent'])  //默认任务
    
    }
    

    根目录下执行grunt命令启动

    用户登陆注册

    1)用户模型及密码处理

    安装bcrypt进行密码加盐处理 npm install bcrypt --save-dev,创建schema user.js

    var mongoose = require('mongoose')
    var bcrypt = require('bcrypt')
    var SALT_WORK_FACTOR = 10
    
    var UserSchema = new mongoose.Schema({
      name: {
        unique: true,
        type: String
      },
      password: String,
      meta: {
        createAt: {
          type: Date,
          default: Date.now()
        },
        updateAt: {
          type: Date,
          default: Date.now()
        }
      }
    })
    
    UserSchema.pre('save', function(next) {
      var user = this
    
      if (this.isNew) {
        this.meta.createAt = this.meta.updateAt = Date.now()
      }
      else {
        this.meta.updateAt = Date.now()
      }
    
      bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) {
        if (err) return next(err)
    
        bcrypt.hash(user.password, salt, function(err, hash) {
          if (err) return next(err)
    
          user.password = hash
          next()
        })
      })
    })
    
    UserSchema.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 = UserSchema
    

    2)登录注册前端视图

    修改header.jade,添加navbar,添加注册与登陆两个按钮,分别为其添加模态视图

    .container
      .row
        .page-header
          h1= title
          small 重度科幻迷
    
    .navbar.navbar-default.navbar-fixed-bottom
      .container
        .navbar-header
          a.navbar-brand(href="/") 重度科幻迷
        if user
          p.navbar-text.navbar-right
            span 欢迎您,#{user.name}
            span  | 
            a.navbar-link(href="/logout") 登出
        else
          p.navbar-text.navbar-right
            a.navbar-link(href="#", data-toggle="modal", data-target="#signupModal") 注册
            span  | 
            a.navbar-link(href="#", data-toggle="modal", data-target="#signinModal") 登录
    #signupModal.modal.fade
      .modal-dialog
        .modal-content
          form(method="POST", action="/user/signup")
            .modal-header 注册
            .modal-body
              .form-group
                label(for="signupName") 用户名
                input#signupName.form-control(name="user[name]", type="text")
              .form-group
                label(for="signupPassword") 密码
                input#signupPassword.form-control(name="user[password]", type="text")
            .modal-footer
              button.btn.btn-default(type="button", data-dismiss="modal") 关闭
              button.btn.btn-success(type="submit") 提交
    #signinModal.modal.fade
      .modal-dialog
        .modal-content
          form(method="POST", action="/user/signin")
            .modal-header 登录
            .modal-body
              .form-group
                label(for="signinName") 用户名
                input#signinName.form-control(name="user[name]", type="text")
              .form-group
                label(for="signinPassword") 密码
                input#signinPassword.form-control(name="user[password]", type="text")
            .modal-footer
              button.btn.btn-default(type="button", data-dismiss="modal") 关闭
              button.btn.btn-success(type="submit") 提交
    

    3)注册用户后台存储

    添加Model user.js

    var mongoose = require('mongoose')
    var UserSchema = require('../schemas/user')
    var User = mongoose.model('User', UserSchema)
    
    module.exports = User
    

    在app.js中引入user model,并添加路由

    var User = require('./models/user')
    ......
    app.post('/user/signup',function(req,res){
        var _user = req.body.user
        var user = new User(_user)
    
        user.save(function(err,user){
            if (err) {
                console.log(err)
            }
            res.redirect('/')
        })
    })
    

    添加用户列表页

    extends ../layout
    
    block content
      .container
        .row
          table.table.table-hover.table-bordered
            thead
              tr
                th 名字
                th 时间
                th 查看
                th 修改
                th 删除
            tbody
              each item in users
                tr(class="item-id-#{item._id}")
                  td #{item.name}
                  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}") 删除
    

    在app.js中添加路由

    //user list page
    app.get('/admin/userlist', function(req, res) {
        Movie.fetch(function(err,users){
            if (err) {
                console.log(err)
            }
            res.render('userlist', {
                title: 'imooc 用户列表页',
                users: users
            })
        })
    })
    

    登陆时判断用户是否存在,更改app.js signup路由

    app.post('/user/signup',function(req,res){
        var _user = req.body.user
    
        User.findOne({name:_user.name}, function(err,user){
            if (err) {
                console.log(err)
            }
            if (user) {
                return res.redirect('/')
            } else {
                var user = new User(_user)
    
                user.save(function(err,user){
                    if (err) {
                        console.log(err)
                    }        
                    res.redirect('/admin/userlist')
                })
            }
        })
    })
    

    4)实现登陆逻辑

    添加signin路由

    app.post('/user/signin',function(req,res){
        var _user = req.body.user
        var name = _user.name
        var password = _user.password
    
        User.findOne({name:_user.name}, function(err,user){
            if (err) {
                console.log(err)
            }
            if (!user) {
                return res.redirect('/')
            } 
            user.comparePassword(password, function(err, isMatch){
                if (err) {
                    console.log(err)
                }
                if (isMatch){
                    console.log('Password is match')
                    return res.redirect('/')
                } else {
                    console.log('Password not match')
                }
            })
        })
    })
    

    在user schema中添加comparePassword方法

    UserSchema.methods = {
      comparePassword: function(_password, cb) {
        bcrypt.compare(_password, this.password, function(err, isMatch) {
          if (err) return cb(err)
          cb(null, isMatch)
        })
      }
    }
    

    5)保持用户状态

    在app.js中安装并引用cookie-session,index中打印当前user,在/user/signin的post中,如果密码匹配,存储user到session

    var cookieSession = require('cookie-session')
    app.use(cookieSession({
        secret: 'imooc'
    }))
    ......
    //index page
    app.get('/', function(req, res) {
        console.log('user in session:')
        console.log(req.session.user)
    ......
    
    if (isMatch){
                    console.log('Password is match')
                    req.session.user = user
                    return res.redirect('/')
                } 
    

    6)利用MongoDB做会话的持久化

    安装 express-session connect-mongo

    var session = require('express-session')
    var MongoStore = require('connect-mongo')(session);
    
    app.use(session({
        secret: 'imooc',
        store: new MongoStore({
            url:'mongodb://localhost/imooc',
            collection: 'sessions'
        })
    }))
    

    7)注销功能实现

    header.jade中修改,判断user显示

        if user
          p.navbar-text.navbar-right
            span 欢迎您,#{user.name}
            span  | 
            a.navbar-link(href="/logout") 登出
        else
          p.navbar-text.navbar-right
            a.navbar-link(href="#", data-toggle="modal", data-target="#signupModal") 注册
            span  | 
            a.navbar-link(href="#", data-toggle="modal", data-target="#signinModal") 登录
    

    添加登出路由,在index路由中,赋予locals user值

        console.log('user in session:')
        console.log(req.session.user)
        var _user = req.session.user
        if(_user) {
            app.locals.user = _user
        }
        Movie.fetch(function(err,movies){
    ......
    app.get('/logout',function(req,res){
        delete req.session.user
        delete app.locals.user  
        res.redirect('/')
    })
    

    8)会话持久逻辑预处理

    将index路由中的赋值移到预处理逻辑中

    app.use(function(req,res,next){
        var _user = req.session.user
        if(_user) {
            app.locals.user = _user
        }
        return next()
    })
    

    9)调整目录,独立路由

    添加config/routes.js,将路由相关代码移到该文件

    var _ = require('underscore')
    var Movie = require('../models/movie')
    var User = require('../models/user')
    
    module.exports = function(app){
    
        app.use(function(req,res,next){
            var _user = req.session.user
            if(_user) {
                app.locals.user = _user
            }
            return next()
        })
    //index page
    app.get('/', function(req, res) {
        console.log('user in session:')
        console.log(req.session.user)
    
        Movie.fetch(function(err,movies){
            if (err) {
                console.log(err)
            }
    
            res.render('index', {
                title: 'imooc 首页',
                movies: movies
            })
        })
    
    })
    
    app.post('/user/signup',function(req,res){
        var _user = req.body.user
    
        User.findOne({name:_user.name}, function(err,user){
            if (err) {
                console.log(err)
            }
            if (user) {
                return res.redirect('/')
            } else {
                var user = new User(_user)
    
                user.save(function(err,user){
                    if (err) {
                        console.log(err)
                    }
            
                    res.redirect('/admin/userlist')
                })
            }
        })
    
    })
    
    app.post('/user/signin',function(req,res){
        var _user = req.body.user
        var name = _user.name
        var password = _user.password
    
        User.findOne({name:_user.name}, function(err,user){
            if (err) {
                console.log(err)
            }
            if (!user) {
                return res.redirect('/')
            } 
            user.comparePassword(password, function(err, isMatch){
                if (err) {
                    console.log(err)
                }
                if (isMatch){
                    console.log('Password is match')
                    req.session.user = user
                    return res.redirect('/')
                } else {
                    console.log('Password not match')
                }
            })
        })
    
    })
    
    app.get('/logout',function(req,res){
        delete req.session.user
        delete app.locals.user  
        res.redirect('/')
    })
    
    //user list page
    app.get('/admin/userlist', function(req, res) {
        User.fetch(function(err,users){
            if (err) {
                console.log(err)
            }
    
            res.render('userlist', {
                title: 'imooc 用户列表页',
                users: users
            })
        })
    })
    
    
    //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
            })
        })
    })
    
    //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})
                }
            })
        }
    })
    }
    

    app.js中引入routes文件

    app.use(session({
        secret: 'imooc',
        store: new MongoStore({
            url:'mongodb://localhost/imooc',
            collection: 'sessions'
        })
    }))
    
    require('./config/routes')(app)
    

    10)配置入口文件

    安装morgan,

    var logger = require('morgan')
    
    if('development' === app.get('env')){
        app.set('showStackError', true)
        app.use(logger(':method :url :status'))
        app.locals.pretty = true
        mongoose.set('debug',true)
    }
    

    11)调整目录,分离mvc

    新建app文件夹,将models/schemas/views文件夹移到该文件夹,添加controllers文件夹,将routes中代码移到新建的文件中
    index.js

    var Movie = require('../models/movie')
    
    exports.index = function(req, res) {
        console.log('user in session:')
        console.log(req.session.user)
    
        Movie.fetch(function(err,movies){
            if (err) {
                console.log(err)
            }
            res.render('index', {
                title: 'imooc 首页',
                movies: movies
            })
        })
    }
    

    user.js

    var User = require('../models/user')
    
    
    exports.signup = function(req,res){
        var _user = req.body.user
    
        User.findOne({name:_user.name}, function(err,user){
            if (err) {
                console.log(err)
            }
            if (user) {
                return res.redirect('/')
            } else {
                var user = new User(_user)
    
                user.save(function(err,user){
                    if (err) {
                        console.log(err)
                    }
            
                    res.redirect('/admin/userlist')
                })
            }
        })
    
    }
    
    exports.signin = function(req,res){
        var _user = req.body.user
        var name = _user.name
        var password = _user.password
    
        User.findOne({name:_user.name}, function(err,user){
            if (err) {
                console.log(err)
            }
            if (!user) {
                return res.redirect('/')
            } 
            user.comparePassword(password, function(err, isMatch){
                if (err) {
                    console.log(err)
                }
                if (isMatch){
                    console.log('Password is match')
                    req.session.user = user
                    return res.redirect('/')
                } else {
                    console.log('Password not match')
                }
            })
        })
    
    }
    
    exports.logout = function(req,res){
        delete req.session.user
        // delete app.locals.user  
        res.redirect('/')
    }
    
    //user list page
    exports.list = function(req, res) {
        User.fetch(function(err,users){
            if (err) {
                console.log(err)
            }
    
            res.render('userlist', {
                title: 'imooc 用户列表页',
                users: users
            })
        })
    }
    

    movie.js

    var _ = require('underscore')
    var Movie = require('../models/movie')
    
    //detail page
    exports.detail = function(req, res) {
        var id = req.params.id
        Movie.findById(id,function(err,movie){
            res.render('detail', {
                title: 'imooc 详情页',
                movie: movie
            })
        })
    
    }
    
    //admin page
    exports.new =  function(req, res) {
        res.render('admin', {
            title: 'imooc 后台录入页',
            movie: {
                title: '',
                doctor: '',
                country: '',
                year: '',
                poster: '',
                flash: '',
                summary: '',
                language: ''
            }
        })
    }
    
    //admin update movie
    exports.update = 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
    exports.save =  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
    exports.list =  function(req, res) {
        Movie.fetch(function(err,movies){
            if (err) {
                console.log(err)
            }
    
            res.render('list', {
                title: 'imooc 列表页',
                movies: movies
            })
        })
    }
    
    //list delete movie
    exports.del = 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})
                }
            })
        }
    }
    

    routes.js修改为如下

    var Index = require('../app/controllers/index')
    var User = require('../app/controllers/user')
    var Movie = require('../app/controllers/movie')
    
    module.exports = function(app){
    
        app.use(function(req,res,next){
            var _user = req.session.user
            // if(_user) {
                app.locals.user = _user
            // }
            next()
        })
    //index page
    app.get('/', Index.index)
    //user
    app.post('/user/signup',User.signup)
    app.post('/user/signin',User.signin)
    app.get('/logout',User.logout)
    app.get('/admin/userlist', User.list)
    
    //movie
    app.get('/movie/:id', Movie.detail)
    app.get('/admin/movie', Movie.new)
    app.get('/admin/update/:id',Movie.update)
    app.post('/admin/movie/new', Movie.save)
    app.get('/admin/list', Movie.list)
    app.delete('/admin/list',Movie.del)
    }
    

    修改app.js文件中路径app.set('views', './app/views/pages')

    12)添加注册登陆跳转页面

    添加signin与signup jade文件

    extends ../layout
    
    block content
      .container
        .row
          .col-md-5
            form(method="POST", action="/user/signin")
              .modal-body
                .form-group
                  label(for="signinName") 用户名
                  input#signinName.form-control(name="user[name]", type="text")
                .form-group
                  label(for="signinPassword") 密码
                  input#signinPassword.form-control(name="user[password]", type="text")
              .modal-footer
                button.btn.btn-default(type="button", data-dismiss="modal") 关闭
                button.btn.btn-success(type="submit") 提交
    

    添加路由

    app.get('/signin', User.showSignin)
    app.get('/signup', User.showSignup)
    

    添加controller方法,修改signup signin重定向地址

    // signup
    exports.showSignup = function(req, res) {
        res.render('signup', {
          title: '注册页面'
        })
      }
      
    exports.showSignin = function(req, res) {
        res.render('signin', {
          title: '登录页面'
        })
      }
    exports.signup = function(req,res){
        var _user = req.body.user
    
        User.findOne({name:_user.name}, function(err,user){
            if (err) {
                console.log(err)
            }
            if (user) {
                return res.redirect('/signin')
            } else {
                var user = new User(_user)
    
                user.save(function(err,user){
                    if (err) {
                        console.log(err)
                    }
            
                    res.redirect('/')
                })
            }
        })
    
    }
    
    exports.signin = function(req,res){
        var _user = req.body.user
        var name = _user.name
        var password = _user.password
    
        User.findOne({name:_user.name}, function(err,user){
            if (err) {
                console.log(err)
            }
            if (!user) {
                return res.redirect('/signup')
            } 
            user.comparePassword(password, function(err, isMatch){
                if (err) {
                    console.log(err)
                }
                if (isMatch){
                    console.log('Password is match')
                    req.session.user = user
                    return res.redirect('/')
                } else {
                    return res.redirect('/signin')
                    console.log('Password not match')
                }
            })
        })
    }
    

    13)用户权限管理

    在user schema中添加role字段

      password: String,
      // 0: nomal user
      // 1: verified user
      // 2: professonal user
      // >10: admin
      // >50: super admin
      role: {
        type: Number,
        default: 0
      },
    

    在routes.js文件中,访问userlist添加参数 app.get('/admin/userlist', User.signinRequired, User.adminRequired, User.list),在user controller中添加方法,如果没有登陆则调到signin,如果没有权限则调到signin

    // midware for user
    exports.signinRequired = function(req, res, next) {
      var user = req.session.user
      if (!user) {
        return res.redirect('/signin')
      }
      next()
    }
    
    exports.adminRequired = function(req, res, next) {
      var user = req.session.user
      if (user.role <= 10) {
        return res.redirect('/signin')
      }
      next()
    }
    

    给其他路由也加上admin权限管理

    //index page
    app.get('/', Index.index)
    //user
    app.post('/user/signup',User.signup)
    app.post('/user/signin',User.signin)
    app.get('/signin', User.showSignin)
    app.get('/signup', User.showSignup)
    app.get('/logout',User.logout)
    app.get('/admin/userlist', User.signinRequired, User.adminRequired, User.list)
    
    //movie
    app.get('/movie/:id', Movie.detail)
    app.get('/admin/movie', User.signinRequired, User.adminRequired, Movie.new)
    app.get('/admin/update/:id',User.signinRequired, User.adminRequired, Movie.update)
    app.post('/admin/movie/new',User.signinRequired, User.adminRequired, Movie.save)
    app.get('/admin/list',User.signinRequired, User.adminRequired, Movie.list)
    app.delete('/admin/list',User.signinRequired, User.adminRequired, Movie.del)
    

    相关文章

      网友评论

          本文标题:Node + MongoDB 建站 2期 -1

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