前言
昨天,我們跟着這位大哥的博客(https://github.com/nswbmw/N-blog/wiki/_pages)進行了nodeJS初步的學習,最后也能將數據插入數據庫了
但是一味的跟着別人博客寫代碼肯定不行,所以我們今天就來做一個簡單的新聞發布系統,系統第一階段不需要太難,主要有以下功能
① 新聞類型管理
② 新聞管理(具有圖片上傳功能)
③ 新聞瀏覽
功能雖然不多,但是也涵蓋很多基本操作了,程序不過增刪查改嘛,外加上傳附件,夠了。於是開始我們今天的學習吧
准備工作
根據昨天的折騰后,我們已經有了nodeJS與mongoDB環境了,現在直接新建工程文件與數據庫文件即可
第一步,打開命令符切換到D盤后輸入
D:\>express -e news
於是系統會自動開開心心構建基本環境
很明顯,里面很多模塊依賴沒有,這個時候將昨天的package.json直接考過來:
{ "name": "application-name", "version": "0.0.1", "private": true, "scripts": { "start": "node app.js" }, "dependencies": { "express": "3.4.8", "ejs": "*", "mongodb": "*" } }
然后切換到項目目錄下:
nmp install
依賴文件全部搞下來了,然后我們輸入
D:\news>node app
Express server listening on port 3000
於是,我們的程序高高興興的運行起來了,打開網址一看,確實沒問題
PS:這里有個問題需要注意,我們下載下來的文件不是UTF-8編碼,所以中文可能有亂碼,文件編碼需要各位自己統一
程序跑起來了就需要數據庫相關的配置了
① 首先在mongoDB目錄中新建news文件夾
② 為項目新增配置文件settings.js
module.exports = { cookieSecret: 'myNews', db: 'news', host: 'localhost' };
③ 新建models目錄,新建db.js
var settings = require('../settings'), Db = require('mongodb').Db, Connection = require('mongodb').Connection, Server = require('mongodb').Server; module.exports = new Db(settings.db, new Server(settings.host, Connection.DEFAULT_PORT), { safe: true });
④ 在桌面新建news.bat程序
d:\mongodb\bin\mongod.exe -dbpath d:\mongodb\news
以后要啟動數據庫,只需要運行他即可,如此,我們初步的准備工作基本結束
但是這里有兩個比較煩的事情,一個是每次要啟動news程序很煩,二個是修改任何東西都需要重啟,於是我們這里先解決這兩個問題
① 在桌面新建news_app.bat,以后運行他就可以啟動程序了
node d:\news\app
② supervisor為一進程保護程序,我們可以使用他幫我們重啟程序,首先按照,然后調整我們的node_app.bat
supervisor d:\news\app
當然之前需要安裝:
npm install -g supervisor
這個樣子后,修改了文件就不需要手動重啟了(需要將news_app放到項目目錄下),於是准備工作到此為止
項目結構
第一步結束后,我們就需要思考下項目結構了
① 首頁為index這里將列出所有新聞類型以及對於新聞條目
② 各個新聞條目擁有編輯/刪除/查看 三個按鈕
③ 首頁具有增加新聞按鈕(增加時候可上傳圖片)
基本功能如上
於是,我們去掉app里面的路由功能,將路由全部放到index里面
//將路由功能放入index //app.get('/', routes.index); //app.get('/users', user.list); routes(app);
module.exports = function (app) { //主頁,現在也是首頁 app.get('/', function (req, res) { res.render('index', { title: 'Express' }); }); app.get('/add', function (req, res) { res.send('增加新聞請求'); }); app.get('/delete', function (req, res) { res.send('刪除新聞請求'); }); app.get('/view', function (req, res) { res.send('查看新聞請求'); }); app.get('/update', function (req, res) { res.send('修改新聞請求'); }); };
第一步簡單如此,因為增加新聞應該有單獨的頁面,而具體點擊增加按鈕又會有其他處理,所以內部還得細分各個請求,現在規定如下:
/ 默認頁面,該頁面顯示所有類型以及新聞,並帶有刪除按鈕
/add 進入添加新聞頁面
/addNews 添加新聞具體post請求地址(點擊按鈕時候的響應)
/delete 刪除新聞請求
/view 具體新聞查詢
於是稍微修改下上述路由:
module.exports = function (app) { //主頁,現在也是首頁 app.get('/', function (req, res) { res.render('index', { title: 'Express' }); }); app.get('/add', function (req, res) { res.send('添加新聞頁面'); }); app.post('/addNews', function (req, res) { res.send('處理添加新聞請求'); }); app.get('/delete', function (req, res) { res.send('刪除新聞請求'); }); app.get('/view', function (req, res) { res.send('查看新聞請求'); }); };
於是我們需要新建幾個模板組織我們的網頁,這里我們先不分離頭尾只要最簡單的頁面即可
新增add與view兩個模板文件,暫時表現與index.ejs一致,並且修改導航相關
module.exports = function (app) { //主頁,現在也是首頁 app.get('/', function (req, res) { res.render('index', { title: 'Express' }); }); app.get('/add', function (req, res) { res.render('add', { title: '添加新聞頁面' }); }); app.post('/addNews', function (req, res) { res.send('處理添加新聞請求'); }); app.get('/delete', function (req, res) { res.send('刪除新聞請求'); }); app.get('/view', function (req, res) { res.render('view', { title: '查看新聞請求' }); }); };
至此項目結構結束
數據操作
整體結構出來后,我們就需要進行數據操作了:
① 增加數據(增加新聞)
② 展示數據(展示新聞)
③ 刪除數據(刪除新聞)
本來還涉及到類型操作的,但是做着做着給搞沒了,暫時不管他吧,因為首次做容易迷糊
增加新聞
這里,我們就不使用表單提交了,我們用ajax......這里順便引入zepto庫,於是我們的頁面成了這樣
<!DOCTYPE html> <html> <head> <title> <%= title %></title> <link rel='stylesheet' href='/stylesheets/style.css' /> <script src="javascripts/zepto.js" type="text/javascript"></script> </head> <body> <h1> <%= title %></h1> <div> 標題:<input type="text" id="title" /> </div> <div> 內容:<textarea id="content"></textarea> </div> <div> <input type="button" type="button" id="ok" value="添加新聞" /> </div> <script type="text/javascript"> $(document).ready(function () { $('#ok').click(function () { var param = {}; param.title = $('#title').val(); param.content = $('#content').val(); $.post('/addNews', param, function () { console.log('添加成功'); }); }); }); </script> </body> </html>
雖然現在還沒有請求響應程序,所以數據並不會被處理,另外我們這里的附件也沒有(現在附件只允許一個好了),於是再修改下代碼,加入圖片:
PS:比較麻煩的是圖片經過ajax處理有點麻煩,所以我們這里乖乖的換回form操作算了,不然又要搞多久......
<html> <head> <title> <%= title %></title> <link rel='stylesheet' href='/stylesheets/style.css' /> </head> <body> <h1> <%= title %></h1> <form enctype="multipart/form-data" method="post" action="/addNews"> <div> 標題:<input type="text" id="title" name="title" /> </div> <div> 圖片:<input type="file" id="pic" name="pic" /> </div> <div> 內容:<textarea id="content" name="content"></textarea> </div> <div> <input type="submit" id="ok" value="添加新聞" /> </div> </form> </body> </html>
這個樣子就不需要過多的考慮附件問題,先暫時如此吧,現在先處理請求程序,這里先在public里面新建news文件夾用於存儲其圖片
model
在models文件夾新增news.js文件,為其構建實體,並賦予新增查詢相關操作:

var mongodb = require('./db'); function News(title, content, pic) { this.title = title; this.content = content; this.pic = pic;//保存存儲路徑 }; module.exports = News; //存儲數據 News.prototype = { save: function (callback) { var date = new Date(); var time = { date: date, year: date.getFullYear(), month: date.getFullYear() + "-" + (date.getMonth() + 1), day: date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate(), minute: date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate() + " " + date.getHours() + ":" + (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) } //數據存儲對象 var news = { title: this.title, content: this.content, pic: this.pic, //圖片處理最后來說,現在先亂存 time: time }; //打開數據連接,打開就是一個回調...... mongodb.open(function (err, db) { //錯誤就退出 if (err) { return callback(err); } //打開news集合 db.collection('news', function (err, collection) { if (err) { mongodb.close(); return callback(err); } //寫入集合(寫入數據庫) collection.insert(news, { safe: true }, function (err) { return callback(err); }); callback(null);//err為null }); }); } };
於是,寫入數據庫的程序就有了,這里我們來試試能不能插入數據庫,當然需要修改路由處的程序
PS:路由處當然不能寫過多邏輯代碼,這個文件以后還得分離
這個時候/addNews里面的邏輯需要改變
app.post('/addNews', function (req, res) { var title = req.body.title; var content = req.body.content; var pic = req.body.pic; var news = new News(title, content, pic) news.save(function (err, data) { res.send(data); }) });
查詢下,問題不大,現在要解決的就是附件問題了
上傳圖片
上傳圖片功能express本身就支持了,express通過bodyParser解析請求體,然后便可通過他上傳文件了,其內部使用了formidable
這里將app.js里面的app.use(express.bodyParser())改為:
app.use(express.bodyParser({ keepExtensions: true, uploadDir: './public/news' }));
打開index.js,在前面加一行代碼:
fs = require('fs'),
修改一下index文件:
app.post('/addNews', function (req, res) { for (var i in req.files) { if (req.files[i] == 0) { //同步方式刪除一個文件 fs.unlinkSync(req.files[i].path); console.log('success removed an empty file'); } else { var path = './public/news/' + req.files[i].name; // 使用同步方式重命名一個文件 fs.renameSync(req.files[i].path, path); console.log('sunccess renamed a file'); } } // var title = req.body.title; // var content = req.body.content; // var pic = req.body.pic; // var news = new News(title, content, pic) // news.save(function (err, data) { // res.send(data); // }) });
這個時候選取文件后點擊添加新聞,我們的文件就上傳上去了
這個時候,我只需要將文件名記錄在數據庫即可,文件目錄里面就有圖片了
app.post('/addNews', function (req, res) { var pic = null; for (var i in req.files) { if (req.files[i] == 0) { //同步方式刪除一個文件 fs.unlinkSync(req.files[i].path); console.log('success removed an empty file'); } else { var path = './public/news/' + req.files[i].name; // 使用同步方式重命名一個文件 fs.renameSync(req.files[i].path, path); console.log('sunccess renamed a file'); } pic = req.files[i].name; } var title = req.body.title; var content = req.body.content; var news = new News(title, content, pic) news.save(function (err, data) { res.send(data); }) res.send('<a href="./">請求成功,返回首頁</a>'); });
數據庫中有數據了,我們目錄也有文件了,現在只需要將數據讀出來了
PS:放假兄弟們催的凶,要出去喝酒了
讀取數據
第二步當然是讀取數據,首先是首頁的數據讀取:

1 var mongodb = require('./db'); 2 3 4 function News(title, content, pic) { 5 this.title = title; 6 this.content = content; 7 this.pic = pic;//保存存儲路徑 8 }; 9 10 module.exports = News; 11 12 //存儲數據 13 News.prototype = { 14 save: function (callback) { 15 var date = new Date(); 16 17 //數據存儲對象 18 var news = { 19 title: this.title, 20 content: this.content, 21 pic: this.pic, //圖片處理最后來說,現在先亂存 22 date: date 23 }; 24 25 //打開數據連接,打開就是一個回調...... 26 mongodb.open(function (err, db) { 27 //錯誤就退出 28 if (err) { 29 return callback(err); 30 } 31 32 //打開news集合 33 db.collection('news', function (err, collection) { 34 if (err) { 35 mongodb.close(); 36 return callback(err); 37 } 38 39 //寫入集合(寫入數據庫) 40 collection.insert(news, { safe: true }, function (err) { 41 return callback(err); 42 }); 43 callback(null); //err為null 44 }); 45 }); 46 } 47 48 }; 49 50 51 //讀取文章及其相關信息 52 News.get = function (id, callback) { 53 //打開數據庫 54 mongodb.open(function (err, db) { 55 if (err) { 56 return callback(err); 57 } 58 db.collection('news', function (err, collection) { 59 if (err) { 60 mongodb.close(); 61 return callback(err); 62 } 63 var query = {}; 64 if (id) { 65 query.id = id; 66 } 67 //根據 query 對象查詢文章 68 collection.find(query).sort({ 69 date: -1 70 }).toArray(function (err, data) { 71 mongodb.close(); 72 if (err) { 73 return callback(err); //失敗!返回 err 74 } 75 callback(null, data); //成功!以數組形式返回查詢的結果 76 }); 77 }); 78 }); 79 };
<!DOCTYPE html> <html> <head> <title> <%= title %></title> <link rel='stylesheet' href='/stylesheets/style.css' /> </head> <body> <h1> <%= title %></h1> <ul> <%for(var k in data) { %> <li> <div> 標題: <%=data[k].title %></div> <div> 內容: <%=data[k].content%></div> <div> 附件:<img src="news/<%= data[k].pic%>" /></div> </div> <div> <a href="/delete?id=<%=data[k] %>">刪除</a> </div> <hr/> </li> <%} %> </ul> </body> </html>
結語
今天,暫時 這樣,晚上有約要出去了,有點倉促