摘要:所以呢解決這個(gè)問(wèn)題也很簡(jiǎn)單,就是對(duì)提交的內(nèi)容進(jìn)行或者其他形式的編碼,在服務(wù)器端進(jìn)行解碼,即可解決。項(xiàng)目地址完結(jié)撒花
NodeJs開(kāi)發(fā)個(gè)人博客項(xiàng)目
預(yù)覽地址:http://baijiawei.top
GitHub地址:https://github.com/bjw1234/blog
需要安裝的模塊body-parser 解析post請(qǐng)求
cookies 讀寫(xiě)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:模板引擎的名稱(chēng),同時(shí)也是模板文件的后綴 參數(shù)2:表示用于解析處理模板內(nèi)容的方法
設(shè)置模板文件存放的目錄 app.set("views","./views")
注冊(cè)所使用的模板引擎 app.set("view engine","html")
3.用模板引擎去解析文件
/** * 讀取views目錄下的指定文件,解析并返回給客戶(hù)端 * 參數(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)用戶(hù)訪(fǎ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(); // 比如訪(fǎng)問(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 用戶(hù)注冊(cè)
/login 用戶(hù)登錄
/comment 評(píng)論獲取
/comment/post 評(píng)論提交
首頁(yè)
/ 后臺(tái)首頁(yè)
用戶(hù)管理
/user 用戶(hù)列表
分類(lèi)管理
/category 分類(lèi)列表
/category/add 分類(lèi)添加
/category/edit 分類(lèi)修改
/caterory/delete 分類(lèi)刪除
文章內(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ā)順序
用戶(hù)
欄目
內(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:datadb --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ì)于用戶(hù)數(shù)據(jù)表(users.js)在schema文件夾下:
var mongoose = require("mongoose"); module.exports = new mongoose.Schema({ // 用戶(hù)名 username:String, // 密碼 password:String });
在models目錄下創(chuàng)建user.js模型類(lèi)
var mongoose = require("mongoose"); var userSchema = require("../schemas/users"); module.exports = mongoose.model("User",userSchema);處理用戶(hù)注冊(cè)
前端通過(guò)ajax提交用戶(hù)名和密碼
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)訪(fǎng)問(wèn)該目錄時(shí)這個(gè)中間件被調(diào)用 responseData = { code:0, message:"" }; next(); }); router.post("/register",(req,res,next) => { console.log(req.body); // 去判斷用戶(hù)名、密碼是否合法 // 判斷是否用戶(hù)名已經(jīng)被注冊(cè) // 通過(guò) res.json(responseData) 給客戶(hù)端返回json數(shù)據(jù) // 查詢(xún)數(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 // 只要客戶(hù)端發(fā)送請(qǐng)求就會(huì)通過(guò)這個(gè)中間件 app.use((req, res, next) => { req.cookies = new cookies(req, res); /** * 解析用戶(hù)的cookies信息 * 查詢(xún)數(shù)據(jù)庫(kù)判斷是否為管理員 isAdmin * 注意:查詢(xún)數(shù)據(jù)庫(kù)是異步操作,next應(yīng)該放在回調(diào)里邊 */ req.userInfo = {}; if (req.cookies.get("userInfo")) { try { req.userInfo = JSON.parse(req.cookies.get("userInfo")); // 查詢(xún)數(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)用戶(hù)登錄或注冊(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) { { key } } -- { { val } }
// arr = [1, 2, 3]
{ % for key, val in arr % }
{ % 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 %} //重寫(xiě)某一區(qū)塊
6.autoescape 自動(dòng)編碼
當(dāng)想在某個(gè)div中顯示后端生成的HTML代碼,模板渲染時(shí)會(huì)自動(dòng)編碼,
以字符串的形式顯示。通過(guò)以下方式,可以避免這個(gè)情況:
用戶(hù)管理和分頁(yè){% autoescape false %} {{ data.article_content_html }} {% endautoescape %}
CRUD用戶(hù)數(shù)據(jù)
const User = require("../models/user"); // 查詢(xún)所有的用戶(hù)數(shù)據(jù) User.find().then(function(users){ }); // 根據(jù)某一字段查詢(xún)數(shù)據(jù) User.findOne({ username:username }).then(function(result){ }); // 根據(jù)用戶(hù)ID查詢(xún)數(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)字段 - 分類(lèi)的id category:{ // 類(lèi)型 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:"" } }); // 文章查詢(xún)時(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ī)用戶(hù)頭像生成
// 引入對(duì)應(yīng)的庫(kù) const crypto = require("crypto"); const identicon = require("identicon.js"); // 當(dāng)用戶(hù)注冊(cè)時(shí),根據(jù)用戶(hù)的用戶(hù)名生成隨機(jī)頭像 let hash = crypto.createHash("md5"); hash.update(username); let imgData = new identicon(hash.digest("hex").toString()); let imgUrl = "data:/image/png;base64,"+imgData;form表單提交的小問(wèn)題
當(dāng)使用form表單提交一些代碼的時(shí)候,會(huì)出現(xiàn)瀏覽器攔截的現(xiàn)象,原因是:瀏覽器誤以為客戶(hù)進(jìn)行xss攻擊。所以呢解決這個(gè)問(wèn)題也很簡(jiǎn)單,就是對(duì)提交的內(nèi)容進(jìn)行base64或者其他形式的編碼,在服務(wù)器端進(jìn)行解碼,即可解決。
項(xiàng)目地址:https://github.com/bjw1234/blog
完結(jié) 撒花 ^_^ ~
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/19201.html
摘要:所以呢解決這個(gè)問(wèn)題也很簡(jiǎn)單,就是對(duì)提交的內(nèi)容進(jìn)行或者其他形式的編碼,在服務(wù)器端進(jìn)行解碼,即可解決。項(xiàng)目地址完結(jié)撒花 NodeJs開(kāi)發(fā)個(gè)人博客項(xiàng)目 預(yù)覽地址:http://baijiawei.top GitHub地址:https://github.com/bjw1234/blog 需要安裝的模塊 body-parser 解析post請(qǐng)求 cookies 讀寫(xiě)cookie express...
摘要:最近在看,打算跟著書(shū)中的代碼敲一遍,加深對(duì)的理解。在這里記錄過(guò)程中的問(wèn)題與心得。根據(jù)排查內(nèi)存耗盡應(yīng)該是這個(gè)版本的問(wèn)題,換成后問(wèn)題消失。因此認(rèn)為這種寫(xiě)法是有風(fēng)險(xiǎn)的,必須用頂上那一行注釋表明我確實(shí)要全局都的才行。不得不感嘆的嚴(yán)謹(jǐn)。 最近在看 build your own angularjs ,打算跟著書(shū)中的代碼敲一遍,加深對(duì)AngularJS的理解。在這里記錄過(guò)程中的問(wèn)題與心得。 Int...
摘要:本地和服務(wù)器環(huán)境本地位服務(wù)器阿里云輕量應(yīng)用服務(wù)器使用的連接工具當(dāng)然還有這幾個(gè)中任選一個(gè)就好啦。連接工具使用方法創(chuàng)建填入服務(wù)器地址和用戶(hù)名,點(diǎn)擊確認(rèn)然后輸入密碼即可。執(zhí)行測(cè)試項(xiàng)目新建項(xiàng)目文件。使用編輯器打開(kāi)項(xiàng)目文件。 本地和服務(wù)器環(huán)境 本地:Windows10 64位 服務(wù)器:阿里云輕量應(yīng)用服務(wù)器CentOS 7.3 使用的連接工具:puttymobaxterm當(dāng)然還有Xshell這幾個(gè)...
摘要:經(jīng)過(guò)在網(wǎng)上的查找,找到了和兩個(gè)事件進(jìn)行一個(gè)開(kāi)關(guān)判斷。關(guān)于事件是的標(biāo)準(zhǔn)事件,對(duì)于檢測(cè)和這幾個(gè)元素通過(guò)用戶(hù)界面發(fā)生的內(nèi)容變化非常有用,在內(nèi)容修改后立即被觸發(fā),不像事件需要失去焦點(diǎn)才觸發(fā)。補(bǔ)充最近測(cè)試了下發(fā)現(xiàn)在事件之后才觸發(fā)。。。 事件背景 工作過(guò)程中涉及到了移動(dòng)端輸入內(nèi)容長(zhǎng)度的限定,這就要求需要對(duì)輸入過(guò)程中內(nèi)容的變化進(jìn)行監(jiān)控和判定,以決定是否可以繼續(xù)輸入,所以就想著是否可以在相關(guān)輸入處監(jiān)聽(tīng)...
閱讀 1482·2021-11-24 09:39
閱讀 3663·2021-09-29 09:47
閱讀 1598·2021-09-29 09:34
閱讀 3108·2021-09-10 10:51
閱讀 2574·2019-08-30 15:54
閱讀 3250·2019-08-30 15:54
閱讀 898·2019-08-30 11:07
閱讀 1039·2019-08-29 18:36