zoukankan      html  css  js  c++  java
  • 用Express 4和 MongoDB打造Todo List

    本篇文章主要參考自DreamersLab - 用Express和MongoDB寫一個todo list。原文的教學內容是使用Express 3.x版,在這邊做簡單Express 4.12.1的todo list實作。

    功能介紹

    • 用cookie來判斷使用者
    • 新增、讀取、更新、刪除待辦事項(C.R.U.D)

    安裝

    開發環境

    確定已安裝node.js, ExpressMongoDB

    • 安裝Express 4.12.1

      npm install express@4.12.1
      
    • 我們使用Mongoose來當作我們的ORM

    步驟

    用Express command line tool來建立基本框架

    Express預設的template engine為jade,在這範例我們採用ejs

    $ express -e todo
    create : todo
    create : todo/package.json
    create : todo/app.js
    create : todo/public
    create : todo/public/javascripts
    create : todo/public/images
    create : todo/public/stylesheets
    create : todo/public/stylesheets/style.css
    create : todo/routes
    create : todo/routes/index.js
    create : todo/routes/users.js
    create : todo/views
    create : todo/views/index.ejs
    create : todo/views/error.ejs
    create : todo/bin
    create : todo/bin/www
    
    install dependencies:
     $ cd todo && npm install
    
    run the app:
     $ DEBUG=todo:* ./bin/www
    
    ejs-locals以及mongoose加入dependencies

    package.json

    {
      "name": "todo",
      "version": "0.0.0",
      "private": true,
      "scripts": {
        "start": "node ./bin/www"
      },
      "dependencies": {
        "body-parser": "~1.12.0",
        "cookie-parser": "~1.3.4",
        "debug": "~2.1.1",
        "ejs": "~2.3.1",
        "express": "~4.12.2",
        "morgan": "~1.5.1",
        "serve-favicon": "~2.2.0",
        "ejs-locals"      : "1.0.2",
        "mongoose"        : "3.8.17",
        "uid-safe"        : "1.1.0"
      }
    }
    
    安裝dependencies
    $ cd todo && npm install
    
    Hello Wolrd!

    開啟Express server然後打開瀏覽器瀏覽127.0.0.1:3000就會看到歡迎頁面

    $ DEBUG=todo ./bin/www
    
    檔案結構

    此時專案的檔案結構大致為下:

    todo
    |-- node_modules
    |   |-- ejs
    |   |-- ejs-locals
    |   |-- express
    |   `-- mongoose
    |
    |-- public
    |   |-- images
    |   |-- javascripts
    |   `-- stylesheets
    |       |-- style.css
    |
    |-- routes
    |   `-- index.js
    |
    |-- views
    |   |-- index.ejs
    |   `-- layout.ejs
    |
    |-- .gitignore
    |
    |-- app.js
    |
    `-- package.json
    
    • node_modules
      • 包含所有project相關套件
    • public
      • 包含所有靜態檔案
    • routes
      • 所有動作及商業邏輯
    • views
      • 包含action views, partials及layout
    • app.js
      • 包含設定、middlewares以及routes的分配
    • package.json
      • 相關套件的設定檔
    MongoDB以及Mongoose設定

    Ubuntu上MongoDB開機便會自動開啟,若是Mac上就輸入下面指令開啟

    $ mongod
    

    並且在專案根目錄之下新增一個檔案叫做db.js來設定MongoDB和定義Schema

    db.js

    var mongoose = require('mongoose');
    var Schema = mongoose.Schema;
    
    var Todo = new Schema({
      user_id     : String,
      content     : String,
      updated_at  : Date
    });
    
    mongoose.model('Todo', Todo);
    mongoose.connect('mongodb://localhost/express-todo');
    

    並且在app.js裡require剛剛新增的db.js

    app.js

    require('./db');
    

    並且移除掉Express預設產生,我們用不到的user route,並且加上layout support

    var engine = require('/ejs-locals');
    app.engine('ejs', engine);

    var express = require('express');
    var path = require('path');
    var favicon = require('serve-favicon');
    var logger = require('morgan');
    var cookieParser = require('cookie-parser');
    var bodyParser = require('body-parser');
    
    var routes = require('./routes/index');
    
    var app = express();
    var engine = require('/ejs-locals');
    
    // view engine setup
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'ejs');
    app.engine('ejs', engine);
    
    // uncomment after placing your favicon in /public
    //app.use(favicon(__dirname + '/public/favicon.ico'));
    app.use(logger('dev'));
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: false }));
    app.use(cookieParser());
    app.use(express.static(path.join(__dirname, 'public')));
    
    app.use('/', routes);
    
    // 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;
    
    修改project title

    routes/index.js

    原本的預設產生的程式碼如下:

    var express = require('express');
    var router = express.Router();
    
    /* GET home page. */
    router.get('/', function(req, res, next) {
      res.render('index', { title: 'Express' });
    });
    
    module.exports = router;
    

    在這個範例之中我們一律將router的分配寫在app.js當中,因此將程式碼修改為:

    var express = require('express');
    
    exports.index = function(req, res) {
      res.render('index', {title : 'Express Todo Example'});
    };
    
    修改index view

    在這裡我們需要一個textbox來新增待辦事項,並且用POST來傳送資料,另外別忘了設定layout

    views/index.ejs

    <% layout( 'layout' ) -%>
    
    <h1><%= title %></h1>
    <form ac 大专栏  用Express 4和 MongoDB打造Todo Listtion="/create" method="POST" accept-charset="utf-8">
      <input type="text" name="content" />
    </form>
    
    新增待辦事項及存檔

    routes/index.js

    首先先require mongooseTodo model

    var mongoose = require('mongoose');
    var Todo     = mongoose.model('Todo');
    
    //新增成功後將頁面導回首頁.
    exports.create = function(req, res) {
      new Todo({
        content    : req.body.content,
        updated_at : Date.now()
      }).save(function(err, todo, count) {
        res.redirect( '/' );
      });
    };
    

    接著在app.js當中新增對應的route

    app.js

    // 新增下列語法到 routes
    app.post('/create', routes.create);
    
    顯示待辦事項

    routes/index.js

    // 查詢資料庫來取得所有待辦是事項.
    exports.index = function(req, res) {
      Todo.find( function(err, todos, count) {
        res.render('index', {
            title : 'Express Todo Example',
            todos : todos
        });
      });
    };
    

    views/index.ejs

    // 跑迴圈顯示待辦事項
    <% todos.forEach(function(todo) { %>
      <p><%= todo.content %></p>
    <% }); %>
    
    刪除待辦事項

    在每一個待辦事項旁邊增加刪除的連結

    routes/index.js

    // 根據待辦事項的id來做移除
    exports.destroy = function(req, res) {
      Todo.findById(req.params.id, function(err, todo) {
        todo.remove( function(err, todo) {
          res.redirect( '/' );
        });
      });
    };
    

    views/index.ejs

    // 在迴圈裡加一個删除連結
    <% todos.forEach(function(todo) { %>
      <p>
        <span>
          <%= todo.content %>
        </span>
        <span>
          <a href="/destroy/<%= todo._id %>" title="Delete this todo item">Delete</a>
        </span>
      </p>
    <% }); %>
    

    將destroy的動作新增到對應的route

    app.js

    // 新增下列語法到 routes
    app.get('/destroy/:id', routes.destroy);
    
    編輯待辦事項

    當滑鼠點擊事項時,將它轉為一個text input達到編輯效果

    routes/index.js

    exports.edit = function(req, res) {
      Todo.find(function(err, todos) {
        res.render('edit', {
            title   : 'Express Todo Example',
            todos   : todos,
            current : req.params.id
        });
      });
    };
    

    新增Edit view,基本上和index view差不多,唯一不同是在被選取的待辦事項變成text input

    view/edit.js

    <% layout( 'layout' ) -%>
    
    <h1><%= title %></h1>
    <form action="/create" method="post" accept-charset="utf-8">
      <input type="text" name="content" />
    </form>
    
    <% todos.forEach(function(todo) { %>
      <p>
        <span>
          <% if ( todo._id == current ) { %>
          <form action="/update/<%= todo._id %>" method="POST" accept-charset="utf-8">
            <input type="text" name="content" value="<%= todo.content %>" />
          </form>
          <% } else { %>
            <a href="/edit/<%= todo._id %>" title="Update this todo item"><%= todo.content %></a>
          <% } %>
        </code>
        <span>
          <a href="/destroy/<%= todo._id %>" title="Delete this todo item">Delete</a>
        </code>
      </p>
    <% }); %>
    

    待辦事項新增可以連到edit的link

    views/index.ejs

    <% layout( 'layout' ) -%>
    
    <h1><%= title %></h1>
    <form action="/create" method="post" accept-charset="utf-8">
      <input type="text" name="content" />
    </form>
    
    <% todos.forEach(function(todo) { %>
      <p>
        <span>
          <a href="/edit/<%= todo._id %>" title="Update this todo item"><%= todo.content %></a>
        </code>
        <span>
          <a href="/destroy/<%= todo._id %>" title="Delete this todo item">Delete</a>
        </code>
      </p>
    <% }); %>
    

    將連結到編輯的route新增到app.js中

    app.js

    app.get('/edit/:id', routes.edit);
    
    更新待辦事項

    新增update動作來更新待辦事項

    routes/index.js

    exports.update = function(req, res) {
      Todo.findById(req.params.id, function(err, todo) {
        todo.content    = req.body.content;
        todo.updated_at = Date.now();
        todo.save(function(err, todo, count) {
          res.redirect( '/' );
        });
      });
    };
    

    將更新的動作新增到routes

    app.js

    app.post('/update/:id', routes.update);
    
    排序

    現在待辦事項的順序為:較早創建/更新的在上面,我們要將它相反

    routes/index.js

    exports.index = function(req, res) {
      Todo.
        find().
        sort('-updated_at').
        exec(function(err, todos) {
          res.render('index', {
              title : 'Express Todo Example',
              todos : todos
          });
        });
    };
    
    exports.edit = function(req, res) {
      Todo.
        find().
        sort('-updated_at' ).
        exec(function(err, todos) {
          res.render('edit', {
              title   : 'Express Todo Example',
              todos   : todos,
              current : req.params.id
          });
        });
    };
    
    多重使用者

    目前為止,所有使用者看到的都是同一組待辦事項,資料有可能會被外人所修改,因此,我們可利用cookie來記錄使用者資訊,讓每個人都有自己的todo list。
    Express已經有內建的cookie,我們先在app.js當中新增一個middleware就好。

    app.js

    // 將抓取使用者資訊的middleware加入app.js
    app.use( routes.current_user );
    

    接著在routes/index.js增加current_user的運作邏輯

    routes/index.js

    // 我們採用uid-safe package來替我們產生uid,別忘了要npm install uid-safe哦
    var uid = require('uid-safe');
    
    exports.current_user = function(req, res, next) {
      var user_id = req.cookies ?
          req.cookies.user_id : undefined;
      if ( ! user_id ) {
        uid(32).then(function(uid) {
          res.cookie('user_id', uid);
        });
      }
      next();
    };
    
    Error handling

    要處理錯誤我們需要新增next參數到每個action當中,一旦發生錯誤便將他傳給下一個middleware去做處理

    routes/index.js

    ... function ( req, res, next ){
      // ...
    };
    
    ...( function( err, todo, count ){
      if( err ) return next( err );
    
      // ...
    });
    
    最後一步,執行
    $ DEBUG=todo ./bin/www
    
  • 相关阅读:
    sqlserver服务 正在挂起更改,导致无法打开或者停止服务
    menuStrip与toolStrip的使用
    sqlDataCommandBuilder为dataGridView自动生成增删改代码时报错
    visual studio属性面板解释文字看不见
    窗体句柄 控件句柄
    form窗体show不出来
    TextBox密码框变文本框,文本框变密码框
    DataSet数据集手动添加一行记录
    Anaconda3-更换为清华源后依旧报错CondaHTTPError: HTTP 000 CONNECTION FAILED
    Kali Linux 国内源
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12326421.html
Copyright © 2011-2022 走看看