用 Express 和 MongoDB 寫一個 todo list
練習一種語言或是 framework 最快的入門方式就是寫一個 todo list 了. 他包含了基本的 C.R.U.D. ( 新增, 讀取, 更新, 刪除 ). 這篇文章將用 node.js 裡最通用的 framework Express 架構 application 和MongoDB 來儲存資料.
功能
無需登入, 用 cookie 來辨別每一問使用者
可以新增, 讀取, 更新, 刪除待辦事項( todo item )
安裝
開發環境
開始之前請確定你已經安裝了 node.js, Express 和 MongoDB, 如果沒有可以餐搞下列文章.
How to setup a node.js development environment on Mac OSX Lion
How to setup a node.js development environment on Ubuntu 11.04
How to setup a node.js development environment on Windows
node.js 套件
參考文件 : npm basic commands
安裝 Express
$ npminstall express -g
這個練習裡我們用 Mongoose 這個 ORM. 為何會需要一個必須定義 schema 的 ORM 來操作一個 schema-less 的資料庫呢? 原因是在一般的網站資料結構的關聯, 驗證都是必須處理的問題. Mongoose 在這方面可以幫你省去很多功夫. 我們會在後面才看如何安裝.
步驟
用 Express 的 command line 工具幫我們生成一個 project 雛形
預設的 template engine 是 jade, 在這裡我們改用比較平易近人的 ejs.
$ express todo -t ejs
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/views
create : todo/views/layout.ejs
create : todo/views/index.ejs
在專案根目錄增加 .gitignore 檔案
.DS_Store
node_modules
*.sock
將 connect 以及 mongoose 加入 dependencies
編輯 package.json
{
"name" : "todo",
"version" : "0.0.1",
"private" : true,
"dependencies" : {
"connect" : "1.8.7",
"express" : "2.5.9",
"ejs" : ">= 0.0.1",
"mongoose" : "2.6.7"
}
}
安裝 dependencies
$ cd todo && npm install -l
Hello world
開啟 express server 然後打開瀏覽器瀏覽 127.0.0.1:3000 就會看到歡迎頁面.
$ node app.js
Project 檔案結構
todo
|-- node_modules
| |-- ejs
| |-- 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 還有 layouts.
app.js
包含設定, middlewares, 和 routes 的分配.
package.json
相關套件的設定檔.
MongoDB 以及 Mongoose 設定
在 Ubuntu 上 MongoDB 開機後便會自動開啟. 在 Mac 上你需要手動輸入下面的指令.
$ mongod --dbpath/usr/local/db
在根目錄下新增一個檔案叫做 db.js 來設定 MongoDB 和定義 schema.
varmongoose = require('mongoose');
varSchema = mongoose.Schema;
varTodo =newSchema({
user_id : String,
content : String,
updated_at : Date
});
mongoose.model('Todo', Todo );
mongoose.connect('mongodb://localhost/express-todo');
在 app.js 裡 require 他.
require('./db' );
將 require routes 移動到 db config 之後.
var express = require( 'express' );
var app = module.exports = express.createServer();
// 設定 mongoose
require( './db' );
// 設定 middleware
// 移除 methodOverride, 新增 favicon, logger 並將 static middleware 往上移
app.configure( function (){
app.set( 'views', __dirname + '/views' );
app.set( 'view engine', 'ejs' );
app.use( express.favicon());
app.use( express.static( __dirname + '/public' ));
app.use( express.logger());
app.use( express.bodyParser());
app.use( app.router );
});
app.configure( 'development', function (){
app.use( express.errorHandler({ dumpExceptions : true, showStack : true }));
});
app.configure( 'production', function (){
app.use( express.errorHandler());
});
// Routes
var routes = require( './routes' );
app.get( '/', routes.index );
app.listen( 3000, function (){
console.log( 'Express server listening on port %d in %s mode', app.address().port, app.settings.env );
});
修改 project title
routes/index.js
exports.index =function( req, res ){
res.render('index', { title :'Express Todo Example'});
};
修改 index view
我們需要一個 text input 來新增待辦事項. 在這裡我們用 POST form 來傳送資料.
views/index.ejs
<h1><%= title %></h1>
<form action="/"method="post"accept-charset="utf-8">
<input type="text"name="content"/>
</form>
新增待辦事項以及存檔
routes/index.js
首先先 require mongoose 和 Todo model.
varmongoose = require('mongoose');
varTodo = mongoose.model('Todo');
新增成功後將頁面導回首頁.
exports.create =function( req, res ){
newTodo({
content : req.body.content,
updated_at : Date.now()
}).save(function( err, todo, count ){
res.redirect('/');
});
};
將這個新增的動作加到 routes 裡.
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 %>
</code>
<span>
<ahref="/destroy/<%= todo._id %>" title="Delete this todo item">Delete</a>
</code>
</p>
<% }); %>
將這個刪除的動作加到 routes 裡.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.
views/edit.ejs
<h1><%= title %></h1>
<formaction="/create"method="post"accept-charset="utf-8">
<inputtype="text"name="content"/>
</form>
<% todos.forEach( function ( todo ){ %>
<p>
<span>
<% if( todo._id == current ){ %>
<formaction="/update/<%= todo._id %>" method="post" accept-charset="utf-8">
<inputtype="text"name="content"value="<%= todo.content %>" />
</form>
<% }else{ %>
<ahref="/edit/<%= todo._id %>" title="Update this todo item"><%= todo.content %></a>
<% } %>
</code>
<span>
<ahref="/destroy/<%= todo._id %>" title="Delete this todo item">Delete</a>
</code>
</p>
<% }); %>
將待辦事項包在一個 link 裡, link 可以連到 edit 動作.
views/index.ejs
<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>
<% }); %>
將這個編輯的動作加到 routes 裡.
app.js
// 新增下列語法到 routes
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
// 新增下列語法到 routes
app.post( '/update/:id', routes.update );
排序
現在待辦事項是最早產生的排最前面, 我們要將他改為最晚產生的放最前面.
routes/index.js
exports.index = function ( req, res ){
Todo.
find().
sort( 'updated_at', -1).
run( function ( err, todos ){
res.render( 'index', {
title : 'Express Todo Example',
todos : todos
});
});
};
exports.edit = function ( req, res ){
Todo.
find().
sort( 'updated_at', -1 ).
run( function ( err, todos ){
res.render( 'edit', {
title : 'Express Todo Example',
todos : todos,
current : req.params.id
});
});
};
多重使用者
現在所有使用者看到的都是同一份資料. 意思就是說每一個人的 todo list 都長得一樣, 資料都有可能被其他人修改. 我們可以用 cookie 來記錄使用者資訊讓每個人有自己的 todo list. Express 已經有內建的 cookie, 只要在 app.js 新增一個 middleware 就好. 另外我們也會需要新增一個依據 cookie 來抓取當下的使用者的 middleware.
app.js
var express = require( 'express' );
var app = module.exports = express.createServer();
// 設定 mongoose
require( './db' );
// 將 routes 移到 middlewares 設定上面
var routes = require( './routes' );
// 設定 middleware
// 移除 methodOverride, 新增 favicon, logger 並將 static middleware 往上移
app.configure( function (){
app.set( 'views', __dirname + '/views' );
app.set( 'view engine', 'ejs' );
app.use( express.favicon());
app.use( express.static( __dirname + '/public' ));
app.use( express.logger());
app.use( express.cookieParser());
app.use( express.bodyParser());
app.use( routes.current_user );
app.use( app.router );
});
app.configure( 'development', function (){
app.use( express.errorHandler({ dumpExceptions : true, showStack : true }));
});
app.configure( 'production', function (){
app.use( express.errorHandler());
});
// Routes
app.get( '/', routes.index );
app.post( '/create', routes.create );
app.get( '/destroy/:id', routes.destroy );
app.get( '/edit/:id', routes.edit );
app.post( '/update/:id', routes.update );
app.listen( 3000, function (){
console.log( 'Express server listening on port %d in %s mode', app.address().port, app.settings.env );
});
routes/index.js
var mongoose = require( 'mongoose' );
var Todo = mongoose.model( 'Todo' );
var utils = require( 'connect' ).utils;
exports.index = function ( req, res, next ){
Todo.
find({ user_id : req.cookies.user_id }).
sort( 'updated_at', -1 ).
run( function ( err, todos, count ){
if( err ) return next( err );
res.render( 'index', {
title : 'Express Todo Example',
todos : todos
});
});
};
exports.create = function ( req, res, next ){
new Todo({
user_id : req.cookies.user_id,
content : req.body.content,
updated_at : Date.now()
}).save( function ( err, todo, count ){
if( err ) return next( err );
res.redirect( '/' );
});
};
exports.destroy = function ( req, res, next ){
Todo.findById( req.params.id, function ( err, todo ){
if( todo.user_id !== req.cookies.user_id ){
return utils.forbidden( res );
}
todo.remove( function ( err, todo ){
if( err ) return next( err );
res.redirect( '/' );
});
});
};
exports.edit = function( req, res, next ){
Todo.
find({ user_id : req.cookies.user_id }).
sort( 'updated_at', -1 ).
run( function ( err, todos ){
if( err ) return next( err );
res.render( 'edit', {
title : 'Express Todo Example',
todos : todos,
current : req.params.id
});
});
};
exports.update = function( req, res, next ){
Todo.findById( req.params.id, function ( err, todo ){
if( todo.user_id !== req.cookies.user_id ){
return utils.forbidden( res );
}
todo.content = req.body.content;
todo.updated_at = Date.now();
todo.save( function ( err, todo, count ){
if( err ) return next( err );
res.redirect( '/' );
});
});
};
// ** 注意!! express 會將 cookie key 轉成小寫 **
exports.current_user = function ( req, res, next ){
if( !req.cookies.user_id ){
res.cookie( 'user_id', utils.uid( 32 ));
}
next();
};
Error handling
要處理錯誤我們需要新增 next 參數到每個 action 裡. 一旦錯誤發生遍將他傳給下一個 middleware 去處理.
routes/index.js
...function( req, res, next ){
// ...
};
...(function( err, todo, count ){
if( err )returnnext( err );
// ...
});
Run application
$ node app.js
到次為止我們已經完成了大部分的功能了. 原始碼裡有多加了一點 css 讓他看起來更美觀. 趕快開啟你的 server 來玩玩看吧 :)
相关推荐
网络与通信:数据传输、信号处理、网络协议、网络与通信硬件、网络安全网络与通信是一个非常广泛的领域,它涉及到计算机科学、电子工程、数学等多个学科的知识。 云计算与大数据:包括云计算平台、大数据分析、人工...
在本教程中,我们将深入学习如何使用Node.js、Express框架和MongoDB数据库构建一个简单的Todo List应用。这将涵盖三个核心技术栈的基础知识,帮助初学者理解后端开发的核心概念。 **一、Node.js** Node.js是一个...
这是一个基于Next.js、Mongoose和MongoDB构建的待办事项(Todo List)应用程序。这个项目展示了如何使用这些技术栈创建一个完整的前后端分离的应用。让我们深入探讨这些技术及其在项目中的应用。 **Next.js** Next....
在本项目"todo-list-using-mongodb"中,我们将探讨如何使用MongoDB数据库和JavaScript来创建一个功能完备的待办事项(Todo List)应用。MongoDB是一个流行的NoSQL数据库,以其灵活性、高性能和易于使用而受到开发者...
在网站制作过程中,一个有效的`Todo List`是项目管理的关键,它可以帮助开发者组织思路,确保所有必要的步骤都得到妥善处理。这个名为"源代码:网站制作todo list.rar"的压缩包很可能包含了一份详细的待办事项清单,...
nodejs-todo-list描述使用后端的Node.js,Express和MongoDB创建的完整CRUD Todo List Web应用程序,对于前端的模板使用EJS创建的完整CRUD Todo List Web应用程序。 待办事项存储在MongoDB数据库中。 IP地址已列入白...
【Express-Todo-List】是一个基于Node.js的Web应用程序,利用了流行的Express框架、模板引擎EJS以及NoSQL数据库MongoDB来实现一个简单的待办事项管理功能。这个项目旨在帮助用户创建、查看、编辑和删除他们的待办...
【描述】"Todo List-js-mongodb是一个典型的Web应用实例,展示了如何将现代前端技术与后端技术和数据库整合,以创建一个功能齐全的待办事项管理工具。" 项目的核心特点和知识点包括: 1. **React**: React是...
总的来说,"todo-list-express"项目是一个基础的Web应用教程,通过使用Express、JavaScript和MongoDB,开发者可以学习到如何构建一个简单的待办事项列表应用,涉及到数据库连接、路由处理、视图渲染等核心概念。
在本项目"todo-list-exercise"中,我们探讨了如何使用Node.js和MongoDB构建一个简单的待办事项列表应用。这个练习旨在帮助开发者熟悉这两项技术,并了解它们如何协同工作来实现后端功能。 首先,Node.js是一个基于...
【标题】"todolist-with-node:带有节点和mongodb的Todo App"揭示了这是一个基于Node.js技术构建的Todo应用程序,它利用MongoDB作为数据库存储待办事项,并且可能使用了Mongoose库来操作数据。 【描述】提到“带有...
在这个项目中,我们利用Node.js和Express这两个强大的工具来创建一个Todo List API。Node.js是基于Chrome V8引擎的JavaScript运行环境,允许我们在服务器端使用JavaScript编写代码。而Express则是Node.js中最受欢迎...
"todo-list-express" 是一个基于 Express 框架开发的简单待办事项(Todo List)应用程序。Express 是一个流行的、轻量级的 Node.js Web 应用程序框架,它极大地简化了构建 web 服务的过程。 **描述分析:** 描述...
使用的技术: HTML,CSS,JavaScript,Node,Express,MongoDB,EJS模板 最佳化 如果时间允许,我想添加CSS并练习UX设计,以制作出更具吸引力和用户登录功能的应用程序。 得到教训: 建立资料库 如何使用EJS模板 ...
本文将深入探讨"MERN-todo-list"项目,这是一个使用MERN堆栈创建的简单待办事项列表应用,适合初学者了解和实践MERN堆栈。 ### 1. MongoDB MongoDB是一个基于分布式文件存储的开源文档数据库,适合处理大量数据。...
Todo_List_Complete 这个项目是使用 node.js、express、ejs 和 mongoose 创建的。 应用链接: : 在新项目中添加类型并按加号按钮将其添加到列表中。 要删除单击复选框。
综合以上,"Todo-List-Shubham-"项目展示了如何将EJS、Express和MongoDB结合使用来构建一个完整的web应用。EJS用于生成动态视图,Express处理HTTP请求并连接后端逻辑,MongoDB作为数据存储,提供数据持久化和检索。...
【标题】"todo-master.zip" 是一个包含Node.js开发项目的压缩包,主要针对Node.js初学者,旨在帮助他们了解和掌握如何搭建一个基础的Node.js工程。Node.js是一款基于Chrome V8引擎的JavaScript运行环境,它让开发者...
在本项目"todo-list"中,我们探讨了一个使用AJAX技术来实现实时任务清单管理的应用。这个应用基于Node.js构建,提供了一种简洁而有效的界面来管理个人的任务列表,支持任务的添加、删除和状态查询。以下是项目的详细...