小編給大家分享一下如何開(kāi)發(fā)node.js博客項(xiàng)目,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供龍泉驛網(wǎng)站建設(shè)、龍泉驛做網(wǎng)站、龍泉驛網(wǎng)站設(shè)計(jì)、龍泉驛網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)與制作、龍泉驛企業(yè)網(wǎng)站模板建站服務(wù),十年龍泉驛做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。
需要安裝的模塊
body-parser 解析post請(qǐng)求
cookies 讀寫cookie
express 搭建服務(wù)器
markdown Markdown語(yǔ)法解析生成器
mongoose 操作MongoDB數(shù)據(jù)庫(kù)
swig 模板解析引擎
目錄結(jié)構(gòu)
db 數(shù)據(jù)庫(kù)存儲(chǔ)目錄
models 數(shù)據(jù)庫(kù)模型文件目錄
public 公共文件目錄(css,js,img)
routers 路由文件目錄
schemas 數(shù)據(jù)庫(kù)結(jié)構(gòu)文件
views 模板視圖文件目錄
app.js 啟動(dòng)文件
package.json
app.js 文件
1.創(chuàng)建應(yīng)用、監(jiān)聽(tīng)端口
const app = express(); app.get('/',(req,res,next) => { res.send("Hello World !"); }); app.listen(3000,(req,res,next) => { console.log("app is running at port 3000"); });
2.配置應(yīng)用模板
定義使用的模板引擎 app.engine('html',swig.renderFile) 參數(shù)1:模板引擎的名稱,同時(shí)也是模板文件的后綴 參數(shù)2:表示用于解析處理模板內(nèi)容的方法
設(shè)置模板文件存放的目錄 app.set('views','./views')
注冊(cè)所使用的模板引擎 app.set('view engine','html')
3.用模板引擎去解析文件
/** * 讀取views目錄下的指定文件,解析并返回給客戶端 * 參數(shù)1:模板文件 * 參數(shù)2:給模板傳遞的參數(shù) */ res.render('index',{ title:'首頁(yè) ', content: 'hello swig' });
4.開(kāi)發(fā)過(guò)程中需要取消模板緩存的限制
swig.setDefaults({ cache: false }); app.set('view cache', false);
5.設(shè)置靜態(tài)文件托管
// 當(dāng)用戶訪問(wèn)的是/public路徑下的文件,那么直接返回 app.use('/public',express.static(__dirname + '/public'));
劃分模塊
前臺(tái)模塊
后臺(tái)模塊
API模塊
// 根據(jù)不同的功能劃分模塊 app.use('/',require('./routers/main')); app.use('/admin',require('./routers/admin')); app.use('/api',require('./routers/api'));
對(duì)于管理員模塊 admin.js
var express = require('express'); var router = express.Router(); // 比如訪問(wèn) /admin/user router.get('/user',function(req,res,next) { res.send('User'); }); module.exports = router;
前臺(tái)路由 + 模板
main 模塊
/ 首頁(yè)
/view 內(nèi)容頁(yè)
api模塊
/首頁(yè)
/register 用戶注冊(cè)
/login 用戶登錄
/comment 評(píng)論獲取
/comment/post 評(píng)論提交
后臺(tái)(admin)路由+模板
首頁(yè)
/ 后臺(tái)首頁(yè)
用戶管理
/user 用戶列表
分類管理
/category 分類列表
/category/add 分類添加
/category/edit 分類修改
/caterory/delete 分類刪除
文章內(nèi)容管理
/article nei內(nèi)容列表
/article/add 內(nèi)容添加
/article/edit 內(nèi)容修改
/article/delete 內(nèi)容刪除
評(píng)論內(nèi)容管理
/comment 評(píng)論列表
/comment/delete 評(píng)論刪除
功能開(kāi)發(fā)順序
功能模塊開(kāi)發(fā)順序
用戶
欄目
內(nèi)容
評(píng)論
編碼順序
通過(guò)Schema定義設(shè)計(jì)數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)
功能邏輯
頁(yè)面展示
連接數(shù)據(jù)庫(kù)(mongoDB)
啟動(dòng)MongoDB服務(wù)端:
mongod --dbpath=G:\data\db --port=27017
啟動(dòng)服務(wù)設(shè)置數(shù)據(jù)庫(kù)的存儲(chǔ)地址以及端口
var mongoose = require('mongoose'); // 數(shù)據(jù)庫(kù)鏈接 mongoose.connect("mongodb://localhost:27017/blog",(err) => { if(err){ console.log("數(shù)據(jù)庫(kù)連接失敗"); }else{ console.log("數(shù)據(jù)庫(kù)連接成功"); // 啟動(dòng)服務(wù)器,監(jiān)聽(tīng)端口 app.listen(3000,(req,res,next) => { console.log("app is running at port 3000"); }); } });
定義數(shù)據(jù)表結(jié)構(gòu)和模型
對(duì)于用戶數(shù)據(jù)表(users.js)在schema文件夾下:
var mongoose = require('mongoose'); module.exports = new mongoose.Schema({ // 用戶名 username:String, // 密碼 password:String });
在models目錄下創(chuàng)建user.js模型類
var mongoose = require('mongoose'); var userSchema = require('../schemas/users'); module.exports = mongoose.model('User',userSchema);
處理用戶注冊(cè)
前端通過(guò)ajax提交用戶名和密碼
url: /api/register
后端對(duì)前端提交(POST)的數(shù)據(jù)解析
var bodyParser = require('body-parser'); // bodyParser 配置 // 通過(guò)使用這一方法,可以為req對(duì)象添加一個(gè)body屬性 app.use( bodyParser.urlencoded({extended:true})); // 在api模塊中: // 1.可以定義一個(gè)中間件,來(lái)統(tǒng)一返回格式 var responseData; router.use( function(req,res,next){ // path默認(rèn)為'/',當(dāng)訪問(wèn)該目錄時(shí)這個(gè)中間件被調(diào)用 responseData = { code:0, message:'' }; next(); }); router.post('/register',(req,res,next) => { console.log(req.body); // 去判斷用戶名、密碼是否合法 // 判斷是否用戶名已經(jīng)被注冊(cè) // 通過(guò) res.json(responseData) 給客戶端返回json數(shù)據(jù) // 查詢數(shù)據(jù)庫(kù) User.findOne({ // 返回一個(gè)promise對(duì)象 username: username }).then(function( userInfo ) { if( userInfo ){ // 數(shù)據(jù)庫(kù)中有該條記錄 ... res.json(responseData); return; } // 給數(shù)據(jù)庫(kù)中添加該條信息 var user = new User({ username:username,password:password }); return user.save(); // 返回promise對(duì)象 }).then(function( newUserInfo ){ console.log(newUserInfo); res.json(responseData); // 數(shù)據(jù)保存成功 }); });
cookies 模塊的使用
全局(app.js)注冊(cè)使用
// 設(shè)置cookie // 只要客戶端發(fā)送請(qǐng)求就會(huì)通過(guò)這個(gè)中間件 app.use((req, res, next) => { req.cookies = new cookies(req, res); /** * 解析用戶的cookies信息 * 查詢數(shù)據(jù)庫(kù)判斷是否為管理員 isAdmin * 注意:查詢數(shù)據(jù)庫(kù)是異步操作,next應(yīng)該放在回調(diào)里邊 */ req.userInfo = {}; if (req.cookies.get("userInfo")) { try { req.userInfo = JSON.parse(req.cookies.get("userInfo")); // 查詢數(shù)據(jù)庫(kù)判斷是否為管理員 User.findById(req.userInfo._id).then(function (result) { req.userInfo.isAdmin = Boolean(result.isAdmin); next(); }); } catch (e) { next(); } } else { next(); } }); // 當(dāng)用戶登錄或注冊(cè)成功之后,可以為其設(shè)置cookies req.cookies.set("userInfo",JSON.stringify({ _id:result._id, username:result.username }));
swig模板引擎
1.變量
{{ name }}
2.屬性
{{ student.name }}
3.if判斷
{ % if name === '郭靖' % }
hello 靖哥哥
{ % endif % }
4.for循環(huán)
// arr = [1, 2, 3]
{ % for key, val in arr % }
{ { key } } -- { { val } }
{ % endfor % }
5.set命令
用來(lái)設(shè)置一個(gè)變量,在當(dāng)前上下文中復(fù)用
{% set foo = [0, 1, 2, 3, 4, 5] %}
{% extends 'layout.html' %} // 繼承某一個(gè)HTML模板
{% include 'page.html' %} // 包含一個(gè)模板到當(dāng)前位置
{% block main %} xxx {% endblock %} //重寫某一區(qū)塊
6.autoescape 自動(dòng)編碼
當(dāng)想在某個(gè)div中顯示后端生成的HTML代碼,模板渲染時(shí)會(huì)自動(dòng)編碼,
以字符串的形式顯示。通過(guò)以下方式,可以避免這個(gè)情況:
{% autoescape false %} {{ data.article_content_html }} {% endautoescape %}
用戶管理和分頁(yè)
CRUD用戶數(shù)據(jù)
const User = require('../models/user'); // 查詢所有的用戶數(shù)據(jù) User.find().then(function(users){ }); // 根據(jù)某一字段查詢數(shù)據(jù) User.findOne({ username:username }).then(function(result){ }); // 根據(jù)用戶ID查詢數(shù)據(jù) User.findById(id).then(function(user){ }); // 根據(jù)ID刪除數(shù)據(jù) User.remove({ _id: id }).then(function(){ }); // 修改數(shù)據(jù) User.update({ _id: id },{ username: name }).then(function(){ });
數(shù)據(jù)分頁(yè)管理
兩個(gè)重要方法
limit(Number): 限制獲取的數(shù)據(jù)條數(shù)
skip(Number): 忽略數(shù)據(jù)的條數(shù) 前number條
忽略條數(shù):(當(dāng)前頁(yè) - 1) * 每頁(yè)顯示的條數(shù)
// 接收傳過(guò)來(lái)的page let query_page = Number(req.query.page) || 1; query_page = Math.max(query_page, 1); // 限制最小為1 query_page = Math.min(Math.ceil(count / limit), query_page); // 限制最大值 count/limit向上取整 var cur_page = query_page; // 當(dāng)前頁(yè) var limit = 10; // 每頁(yè)顯示的條數(shù) var skip = (cur_page - 1) * limit; //忽略的條數(shù) User.find().limit(limit).skip(skip).then(function(users){ ... // 將當(dāng)前頁(yè) page 傳給頁(yè)面 // 將最大頁(yè)碼 maxPage 傳給頁(yè)面 });
文章的表結(jié)構(gòu)
// 對(duì)于content.js var mongoose = require('mongoose'); var contentSch = require('../schemas/contentSch'); module.exports = mongoose.model('Content',contentSch); // contentSch.js module.exports = new mongoose.Schema({ // 關(guān)聯(lián)字段 - 分類的id category:{ // 類型 type:mongoose.Schema.Types.ObjectId, // 引用 ref:'Category' }, // 內(nèi)容標(biāo)題 title: String, // 簡(jiǎn)介 description:{ type: String, default: '' }, // 內(nèi)容 content:{ type:String, default:'' } }); // 文章查詢時(shí)關(guān)聯(lián)category字段 Content.find().populate('category').then(contents => { // 那么通過(guò)這樣的方式,我們就可以找到Content表中的 // 關(guān)聯(lián)信息 content.category.category_name });
MarkDown語(yǔ)法高亮
在HTML中直接使用
// marked相關(guān)配置 marked.setOptions({ renderer: new marked.Renderer(), gfm: true, tables: true, breaks: false, pedantic: false, sanitize: true, smartLists: true, smartypants: false, highlight: function (code) { return hljs.highlightAuto(code).value; } }); // MarkDown語(yǔ)法解析內(nèi)容預(yù)覽 $('#bjw-content').on('keyup blur', function () { $('#bjw-previous').html(marked($('#bjw-content').val())); });
node環(huán)境中使用
// 在模板頁(yè)面引入默認(rèn)樣式 const marked = require('marked'); const hljs = require('highlight.js'); // marked相關(guān)配置 marked.setOptions({ renderer: new marked.Renderer(), gfm: true, tables: true, breaks: false, pedantic: false, sanitize: true, smartLists: true, smartypants: false, highlight: function (code) { return hljs.highlightAuto(code).value; } }); // 對(duì)內(nèi)容進(jìn)行markdown語(yǔ)法轉(zhuǎn)換 data.article_content_html = marked(article.content);
使文本域支持Tab縮進(jìn)
$('#bjw-content').on('keydown',function(e){ if(e.keyCode === 9){ // Tab鍵 var position = this.selectionStart + 2; // Tab === 倆空格 this.value = this.value.substr(0,this.selectionStart) + " " + this.value.substr(this.selectionStart); this.selectionStart = position; this.selectionEnd = position; this.focus(); e.preventDefault(); } });
layer 彈框
// 顯示彈框 function showDialog(text, icon, callback) { layer.open({ time: 1500, anim: 4, offset: 't', icon: icon, content: text, btn: false, title: false, closeBtn: 0, end: function () { callback && callback(); } }); });
隨機(jī)用戶頭像生成
// 引入對(duì)應(yīng)的庫(kù) const crypto = require('crypto'); const identicon = require('identicon.js'); // 當(dāng)用戶注冊(cè)時(shí),根據(jù)用戶的用戶名生成隨機(jī)頭像 let hash = crypto.createHash('md5'); hash.update(username); let imgData = new identicon(hash.digest('hex').toString()); let imgUrl = 'data:/image/png;base64,'+imgData;
orm表單提交的小問(wèn)題
當(dāng)使用form表單提交一些代碼的時(shí)候,會(huì)出現(xiàn)瀏覽器攔截的現(xiàn)象,原因是:瀏覽器誤以為客戶進(jìn)行xss攻擊。所以呢解決這個(gè)問(wèn)題也很簡(jiǎn)單,就是對(duì)提交的內(nèi)容進(jìn)行base64或者其他形式的編碼,在服務(wù)器端進(jìn)行解碼,即可解決。
以上是“如何開(kāi)發(fā)node.js博客項(xiàng)目”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!