nodejs教程之制作一個(gè)簡(jiǎn)單的文章發(fā)布系統(tǒng)
前言
我們今天就來(lái)做一個(gè)簡(jiǎn)單的新聞發(fā)布系統(tǒng),系統(tǒng)第一階段不需要太難,主要有以下功能
① 新聞?lì)愋凸芾?/p>
② 新聞管理(具有圖片上傳功能)
③ 新聞瀏覽
功能雖然不多,但是也涵蓋很多基本操作了,程序不過(guò)增刪查改嘛,外加上傳附件,夠了。于是開(kāi)始我們今天的學(xué)習(xí)吧
準(zhǔn)備工作
根據(jù)昨天的折騰后,我們已經(jīng)有了nodeJS與mongoDB環(huán)境了,現(xiàn)在直接新建工程文件與數(shù)據(jù)庫(kù)文件即可
第一步,打開(kāi)命令符切換到D盤后輸入
于是系統(tǒng)會(huì)自動(dòng)開(kāi)開(kāi)心心構(gòu)建基本環(huán)境
很明顯,里面很多模塊依賴沒(méi)有,這個(gè)時(shí)候?qū)⒆蛱斓膒ackage.json直接考過(guò)來(lái):
{
"name": "application-name",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node app.js"
},
"dependencies": {
"express": "3.4.8",
"ejs": "*",
"mongodb": "*"
}
}
然后切換到項(xiàng)目目錄下:
依賴文件全部搞下來(lái)了,然后我們輸入
D:\news>node app
Express server listening on port 3000
于是,我們的程序高高興興的運(yùn)行起來(lái)了,打開(kāi)網(wǎng)址一看,確實(shí)沒(méi)問(wèn)題
PS:這里有個(gè)問(wèn)題需要注意,我們下載下來(lái)的文件不是UTF-8編碼,所以中文可能有亂碼,文件編碼需要各位自己統(tǒng)一
程序跑起來(lái)了就需要數(shù)據(jù)庫(kù)相關(guān)的配置了
① 首先在mongoDB目錄中新建news文件夾
② 為項(xiàng)目新增配置文件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òng)數(shù)據(jù)庫(kù),只需要運(yùn)行他即可,如此,我們初步的準(zhǔn)備工作基本結(jié)束
但是這里有兩個(gè)比較煩的事情,一個(gè)是每次要啟動(dòng)news程序很煩,二個(gè)是修改任何東西都需要重啟,于是我們這里先解決這兩個(gè)問(wèn)題
① 在桌面新建news_app.bat,以后運(yùn)行他就可以啟動(dòng)程序了
② supervisor為一進(jìn)程保護(hù)程序,我們可以使用他幫我們重啟程序,首先按照,然后調(diào)整我們的node_app.bat
當(dāng)然之前需要安裝:
這個(gè)樣子后,修改了文件就不需要手動(dòng)重啟了(需要將news_app放到項(xiàng)目目錄下),于是準(zhǔn)備工作到此為止
項(xiàng)目結(jié)構(gòu)
第一步結(jié)束后,我們就需要思考下項(xiàng)目結(jié)構(gòu)了
① 首頁(yè)為index這里將列出所有新聞?lì)愋鸵约皩?duì)于新聞條目
② 各個(gè)新聞條目擁有編輯/刪除/查看 三個(gè)按鈕
③ 首頁(yè)具有增加新聞按鈕(增加時(shí)候可上傳圖片)
基本功能如上
于是,我們?nèi)サ鬭pp里面的路由功能,將路由全部放到index里面
//將路由功能放入index
//app.get('/', routes.index);
//app.get('/users', user.list);
routes(app);
module.exports = function (app) {
//主頁(yè),現(xiàn)在也是首頁(yè)
app.get('/', function (req, res) {
res.render('index', { title: 'Express' });
});
app.get('/add', function (req, res) {
res.send('增加新聞?wù)埱?);
});
app.get('/delete', function (req, res) {
res.send('刪除新聞?wù)埱?);
});
app.get('/view', function (req, res) {
res.send('查看新聞?wù)埱?);
});
app.get('/update', function (req, res) {
res.send('修改新聞?wù)埱?);
});
};
第一步簡(jiǎn)單如此,因?yàn)樵黾有侣剳?yīng)該有單獨(dú)的頁(yè)面,而具體點(diǎn)擊增加按鈕又會(huì)有其他處理,所以內(nèi)部還得細(xì)分各個(gè)請(qǐng)求,現(xiàn)在規(guī)定如下:
/ 默認(rèn)頁(yè)面,該頁(yè)面顯示所有類型以及新聞,并帶有刪除按鈕
/add 進(jìn)入添加新聞頁(yè)面
/addNews 添加新聞具體post請(qǐng)求地址(點(diǎn)擊按鈕時(shí)候的響應(yīng))
/delete 刪除新聞?wù)埱?/p>
/view 具體新聞查詢
于是稍微修改下上述路由:
module.exports = function (app) {
//主頁(yè),現(xiàn)在也是首頁(yè)
app.get('/', function (req, res) {
res.render('index', { title: 'Express' });
});
app.get('/add', function (req, res) {
res.send('添加新聞頁(yè)面');
});
app.post('/addNews', function (req, res) {
res.send('處理添加新聞?wù)埱?);
});
app.get('/delete', function (req, res) {
res.send('刪除新聞?wù)埱?);
});
app.get('/view', function (req, res) {
res.send('查看新聞?wù)埱?);
});
};
于是我們需要新建幾個(gè)模板組織我們的網(wǎng)頁(yè),這里我們先不分離頭尾只要最簡(jiǎn)單的頁(yè)面即可
新增add與view兩個(gè)模板文件,暫時(shí)表現(xiàn)與index.ejs一致,并且修改導(dǎo)航相關(guān)
module.exports = function (app) {
//主頁(yè),現(xiàn)在也是首頁(yè)
app.get('/', function (req, res) {
res.render('index', { title: 'Express' });
});
app.get('/add', function (req, res) {
res.render('add', { title: '添加新聞頁(yè)面' });
});
app.post('/addNews', function (req, res) {
res.send('處理添加新聞?wù)埱?);
});
app.get('/delete', function (req, res) {
res.send('刪除新聞?wù)埱?);
});
app.get('/view', function (req, res) {
res.render('view', { title: '查看新聞?wù)埱? });
});
};
至此項(xiàng)目結(jié)構(gòu)結(jié)束
數(shù)據(jù)操作
整體結(jié)構(gòu)出來(lái)后,我們就需要進(jìn)行數(shù)據(jù)操作了:
① 增加數(shù)據(jù)(增加新聞)
② 展示數(shù)據(jù)(展示新聞)
③ 刪除數(shù)據(jù)(刪除新聞)
本來(lái)還涉及到類型操作的,但是做著做著給搞沒(méi)了,暫時(shí)不管他吧,因?yàn)槭状巫鋈菀酌院?/p>
增加新聞
這里,我們就不使用表單提交了,我們用ajax......這里順便引入zepto庫(kù),于是我們的頁(yè)面成了這樣
<!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>
標(biāo)題:<input type="text" id="title" />
</div>
<div>
內(nèi)容:<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>
雖然現(xiàn)在還沒(méi)有請(qǐng)求響應(yīng)程序,所以數(shù)據(jù)并不會(huì)被處理,另外我們這里的附件也沒(méi)有(現(xiàn)在附件只允許一個(gè)好了),于是再修改下代碼,加入圖片:
PS:比較麻煩的是圖片經(jīng)過(guò)ajax處理有點(diǎn)麻煩,所以我們這里乖乖的換回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>
標(biāo)題:<input type="text" id="title" name="title" />
</div>
<div>
圖片:<input type="file" id="pic" name="pic" />
</div>
<div>
內(nèi)容:<textarea id="content" name="content"></textarea>
</div>
<div>
<input type="submit" id="ok" value="添加新聞" />
</div>
</form>
</body>
</html>
這個(gè)樣子就不需要過(guò)多的考慮附件問(wèn)題,先暫時(shí)如此吧,現(xiàn)在先處理請(qǐng)求程序,這里先在public里面新建news文件夾用于存儲(chǔ)其圖片
model
在models文件夾新增news.js文件,為其構(gòu)建實(shí)體,并賦予新增查詢相關(guān)操作:
var mongodb = require('./db');
function News(title, content, pic) {
this.title = title;
this.content = content;
this.pic = pic;//保存存儲(chǔ)路徑
};
module.exports = News;
//存儲(chǔ)數(shù)據(jù)
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())
}
//數(shù)據(jù)存儲(chǔ)對(duì)象
var news = {
title: this.title,
content: this.content,
pic: this.pic, //圖片處理最后來(lái)說(shuō),現(xiàn)在先亂存
time: time
};
//打開(kāi)數(shù)據(jù)連接,打開(kāi)就是一個(gè)回調(diào)......
mongodb.open(function (err, db) {
//錯(cuò)誤就退出
if (err) {
return callback(err);
}
//打開(kāi)news集合
db.collection('news', function (err, collection) {
if (err) {
mongodb.close();
return callback(err);
}
//寫入集合(寫入數(shù)據(jù)庫(kù))
collection.insert(news, { safe: true }, function (err) {
return callback(err);
});
callback(null);//err為null
});
});
}
};
于是,寫入數(shù)據(jù)庫(kù)的程序就有了,這里我們來(lái)試試能不能插入數(shù)據(jù)庫(kù),當(dāng)然需要修改路由處的程序
PS:路由處當(dāng)然不能寫過(guò)多邏輯代碼,這個(gè)文件以后還得分離
這個(gè)時(shí)候/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);
})
});
查詢下,問(wèn)題不大,現(xiàn)在要解決的就是附件問(wèn)題了
上傳圖片
上傳圖片功能express本身就支持了,express通過(guò)bodyParser解析請(qǐng)求體,然后便可通過(guò)他上傳文件了,其內(nèi)部使用了formidable
這里將app.js里面的app.use(express.bodyParser())改為:
打開(kāi)index.js,在前面加一行代碼:
修改一下index文件:
app.post('/addNews', function (req, res) {
for (var i in req.files) {
if (req.files[i] == 0) {
//同步方式刪除一個(gè)文件
fs.unlinkSync(req.files[i].path);
console.log('success removed an empty file');
} else {
var path = './public/news/' + req.files[i].name;
// 使用同步方式重命名一個(gè)文件
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);
// })
});
這個(gè)時(shí)候選取文件后點(diǎn)擊添加新聞,我們的文件就上傳上去了
這個(gè)時(shí)候,我只需要將文件名記錄在數(shù)據(jù)庫(kù)即可,文件目錄里面就有圖片了
app.post('/addNews', function (req, res) {
var pic = null;
for (var i in req.files) {
if (req.files[i] == 0) {
//同步方式刪除一個(gè)文件
fs.unlinkSync(req.files[i].path);
console.log('success removed an empty file');
} else {
var path = './public/news/' + req.files[i].name;
// 使用同步方式重命名一個(gè)文件
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="./">請(qǐng)求成功,返回首頁(yè)</a>');
});
數(shù)據(jù)庫(kù)中有數(shù)據(jù)了,我們目錄也有文件了,現(xiàn)在只需要將數(shù)據(jù)讀出來(lái)了
PS:放假兄弟們催的兇,要出去喝酒了
讀取數(shù)據(jù)
第二步當(dāng)然是讀取數(shù)據(jù),首先是首頁(yè)的數(shù)據(jù)讀?。?/p>
var mongodb = require('./db');
function News(title, content, pic) {
this.title = title;
this.content = content;
this.pic = pic;//保存存儲(chǔ)路徑
};
module.exports = News;
//存儲(chǔ)數(shù)據(jù)
News.prototype = {
save: function (callback) {
var date = new Date();
//數(shù)據(jù)存儲(chǔ)對(duì)象
var news = {
title: this.title,
content: this.content,
pic: this.pic, //圖片處理最后來(lái)說(shuō),現(xiàn)在先亂存
date: date
};
//打開(kāi)數(shù)據(jù)連接,打開(kāi)就是一個(gè)回調(diào)......
mongodb.open(function (err, db) {
//錯(cuò)誤就退出
if (err) {
return callback(err);
}
//打開(kāi)news集合
db.collection('news', function (err, collection) {
if (err) {
mongodb.close();
return callback(err);
}
//寫入集合(寫入數(shù)據(jù)庫(kù))
collection.insert(news, { safe: true }, function (err) {
return callback(err);
});
callback(null); //err為null
});
});
}
};
//讀取文章及其相關(guān)信息
News.get = function (id, callback) {
//打開(kāi)數(shù)據(jù)庫(kù)
mongodb.open(function (err, db) {
if (err) {
return callback(err);
}
db.collection('news', function (err, collection) {
if (err) {
mongodb.close();
return callback(err);
}
var query = {};
if (id) {
query.id = id;
}
//根據(jù) query 對(duì)象查詢文章
collection.find(query).sort({
date: -1
}).toArray(function (err, data) {
mongodb.close();
if (err) {
return callback(err); //失敗!返回 err
}
callback(null, data); //成功!以數(shù)組形式返回查詢的結(jié)果
});
});
});
};
news.js
<!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>
標(biāo)題: <%=data[k].title %></div>
<div>
內(nèi)容: <%=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>
結(jié)語(yǔ)
好了,文章發(fā)布系統(tǒng)的制作就先到這里了,以后我們?cè)俾黾庸δ?,慢慢做美化?/p>
相關(guān)文章
NodeJS?Express使用ORM模型訪問(wèn)關(guān)系型數(shù)據(jù)庫(kù)流程詳解
這篇文章主要介紹了NodeJS?Express使用ORM模型訪問(wèn)關(guān)系型數(shù)據(jù)庫(kù)流程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2023-01-01使用ExcelJS快速處理Node.js爬蟲(chóng)數(shù)據(jù)
Excel.js是一個(gè)強(qiáng)大的JavaScript庫(kù),它提供了方法處理Excel文件,例如創(chuàng)建和編輯工作簿、讀取和寫入數(shù)據(jù)、處理行和列、設(shè)置樣式、導(dǎo)入和導(dǎo)出數(shù)據(jù)等,本文介紹使用ExcelJS快速處理Node.js爬蟲(chóng)數(shù)據(jù)的方法,一起看看吧2024-01-01node.js實(shí)現(xiàn)學(xué)生檔案管理
這篇文章主要為大家詳細(xì)介紹了node.js實(shí)現(xiàn)學(xué)生檔案管理,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05基于node實(shí)現(xiàn)websocket協(xié)議
這篇文章主要介紹了基于node實(shí)現(xiàn)websocket協(xié)議的相關(guān)資料,需要的朋友可以參考下2016-04-04nodejs 搭建簡(jiǎn)易服務(wù)器的圖文教程(推薦)
下面小編就為大家?guī)?lái)一篇nodejs 搭建簡(jiǎn)易服務(wù)器的圖文教程(推薦)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-07-07使用Node.js實(shí)現(xiàn)ORM的一種思路詳解(圖文)
這篇文章主要介紹了用Node.js實(shí)現(xiàn)ORM的一種思路詳解(圖文),需要的朋友可以參考下2017-10-10