摘要:所以呢解決這個問題也很簡單,就是對提交的內(nèi)容進(jìn)行或者其他形式的編碼,在服務(wù)器端進(jìn)行解碼,即可解決。項目地址完結(jié)撒花
NodeJs開發(fā)個人博客項目
預(yù)覽地址:http://baijiawei.top
GitHub地址:https://github.com/bjw1234/blog
需要安裝的模塊body-parser 解析post請求
cookies 讀寫cookie
express 搭建服務(wù)器
markdown Markdown語法解析生成器
mongoose 操作Mongodb數(shù)據(jù)庫
swig 模板解析引擎
目錄結(jié)構(gòu)db 數(shù)據(jù)庫存儲目錄
models 數(shù)據(jù)庫模型文件目錄
public 公共文件目錄(css,js,img)
routers 路由文件目錄
schemas 數(shù)據(jù)庫結(jié)構(gòu)文件
views 模板視圖文件目錄
app.js 啟動文件
package.json
app.js 文件1.創(chuàng)建應(yīng)用、監(jiān)聽端口
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ù)2:表示用于解析處理模板內(nèi)容的方法
設(shè)置模板文件存放的目錄 app.set("views","./views")
注冊所使用的模板引擎 app.set("view engine","html")
3.用模板引擎去解析文件
/** * 讀取views目錄下的指定文件,解析并返回給客戶端 * 參數(shù)1:模板文件 * 參數(shù)2:給模板傳遞的參數(shù) */ res.render("index",{ title:"首頁 ", content: "hello swig" });
4.開發(fā)過程中需要取消模板緩存的限制
swig.setDefaults({ cache: false }); app.set("view cache", false);
5.設(shè)置靜態(tài)文件托管
// 當(dāng)用戶訪問的是/public路徑下的文件,那么直接返回 app.use("/public",express.static(__dirname + "/public"));劃分模塊
前臺模塊
后臺模塊
API模塊
// 根據(jù)不同的功能劃分模塊 app.use("/",require("./routers/main")); app.use("/admin",require("./routers/admin")); app.use("/api",require("./routers/api"));
對于管理員模塊 admin.js
var express = require("express"); var router = express.Router(); // 比如訪問 /admin/user router.get("/user",function(req,res,next) { res.send("User"); }); module.exports = router;前臺路由 + 模板
main 模塊
/ 首頁
/view 內(nèi)容頁
api模塊
/ 首頁
/register 用戶注冊
/login 用戶登錄
/comment 評論獲取
/comment/post 評論提交
首頁
/ 后臺首頁
用戶管理
/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)容刪除
評論內(nèi)容管理
/comment 評論列表
/comment/delete 評論刪除
功能模塊開發(fā)順序
用戶
欄目
內(nèi)容
評論
編碼順序
通過Schema定義設(shè)計數(shù)據(jù)存儲結(jié)構(gòu)
功能邏輯
頁面展示
連接數(shù)據(jù)庫(mongoDB) 啟動MongoDB服務(wù)端:
mongod --dbpath=G:datadb --port=27017
啟動服務(wù)設(shè)置數(shù)據(jù)庫的存儲地址以及端口
var mongoose = require("mongoose"); // 數(shù)據(jù)庫鏈接 mongoose.connect("mongodb://localhost:27017/blog",(err) => { if(err){ console.log("數(shù)據(jù)庫連接失敗"); }else{ console.log("數(shù)據(jù)庫連接成功"); // 啟動服務(wù)器,監(jiān)聽端口 app.listen(3000,(req,res,next) => { console.log("app is running at port 3000"); }); } });定義數(shù)據(jù)表結(jié)構(gòu)和模型
對于用戶數(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);處理用戶注冊
前端通過ajax提交用戶名和密碼
url: /api/register
后端對前端提交(POST)的數(shù)據(jù)解析
var bodyParser = require("body-parser"); // bodyParser 配置 // 通過使用這一方法,可以為req對象添加一個body屬性 app.use( bodyParser.urlencoded({extended:true})); // 在api模塊中: // 1.可以定義一個中間件,來統(tǒng)一返回格式 var responseData; router.use( function(req,res,next){ // path默認(rèn)為"/",當(dāng)訪問該目錄時這個中間件被調(diào)用 responseData = { code:0, message:"" }; next(); }); router.post("/register",(req,res,next) => { console.log(req.body); // 去判斷用戶名、密碼是否合法 // 判斷是否用戶名已經(jīng)被注冊 // 通過 res.json(responseData) 給客戶端返回json數(shù)據(jù) // 查詢數(shù)據(jù)庫 User.findOne({ // 返回一個promise對象 username: username }).then(function( userInfo ) { if( userInfo ){ // 數(shù)據(jù)庫中有該條記錄 ... res.json(responseData); return; } // 給數(shù)據(jù)庫中添加該條信息 var user = new User({ username:username,password:password }); return user.save(); // 返回promise對象 }).then(function( newUserInfo ){ console.log(newUserInfo); res.json(responseData); // 數(shù)據(jù)保存成功 }); });cookies 模塊的使用
全局(app.js)注冊使用
// 設(shè)置cookie // 只要客戶端發(fā)送請求就會通過這個中間件 app.use((req, res, next) => { req.cookies = new cookies(req, res); /** * 解析用戶的cookies信息 * 查詢數(shù)據(jù)庫判斷是否為管理員 isAdmin * 注意:查詢數(shù)據(jù)庫是異步操作,next應(yīng)該放在回調(diào)里邊 */ req.userInfo = {}; if (req.cookies.get("userInfo")) { try { req.userInfo = JSON.parse(req.cookies.get("userInfo")); // 查詢數(shù)據(jù)庫判斷是否為管理員 User.findById(req.userInfo._id).then(function (result) { req.userInfo.isAdmin = Boolean(result.isAdmin); next(); }); } catch (e) { next(); } } else { next(); } }); // 當(dāng)用戶登錄或注冊成功之后,可以為其設(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命令
用來設(shè)置一個變量,在當(dāng)前上下文中復(fù)用
{% set foo = [0, 1, 2, 3, 4, 5] %}
{% extends "layout.html" %} // 繼承某一個HTML模板
{% include "page.html" %} // 包含一個模板到當(dāng)前位置
{% block main %} xxx {% endblock %} //重寫某一區(qū)塊
6.autoescape 自動編碼
當(dāng)想在某個div中顯示后端生成的HTML代碼,模板渲染時會自動編碼,
以字符串的形式顯示。通過以下方式,可以避免這個情況:
用戶管理和分頁{% autoescape false %} {{ data.article_content_html }} {% endautoescape %}
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ù)分頁管理
兩個重要方法
limit(Number): 限制獲取的數(shù)據(jù)條數(shù)
skip(Number): 忽略數(shù)據(jù)的條數(shù) 前number條
忽略條數(shù):(當(dāng)前頁 - 1) * 每頁顯示的條數(shù)
// 接收傳過來的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)前頁 var limit = 10; // 每頁顯示的條數(shù) var skip = (cur_page - 1) * limit; //忽略的條數(shù) User.find().limit(limit).skip(skip).then(function(users){ ... // 將當(dāng)前頁 page 傳給頁面 // 將最大頁碼 maxPage 傳給頁面 });文章的表結(jié)構(gòu)
// 對于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, // 簡介 description:{ type: String, default: "" }, // 內(nèi)容 content:{ type:String, default:"" } }); // 文章查詢時關(guān)聯(lián)category字段 Content.find().populate("category").then(contents => { // 那么通過這樣的方式,我們就可以找到Content表中的 // 關(guān)聯(lián)信息 content.category.category_name });MarkDown語法高亮
在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語法解析內(nèi)容預(yù)覽 $("#bjw-content").on("keyup blur", function () { $("#bjw-previous").html(marked($("#bjw-content").val())); });
node環(huán)境中使用
// 在模板頁面引入默認(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; } }); // 對內(nèi)容進(jìn)行markdown語法轉(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ī)用戶頭像生成
// 引入對應(yīng)的庫 const crypto = require("crypto"); const identicon = require("identicon.js"); // 當(dāng)用戶注冊時,根據(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;form表單提交的小問題
當(dāng)使用form表單提交一些代碼的時候,會出現(xiàn)瀏覽器攔截的現(xiàn)象,原因是:瀏覽器誤以為客戶進(jìn)行xss攻擊。所以呢解決這個問題也很簡單,就是對提交的內(nèi)容進(jìn)行base64或者其他形式的編碼,在服務(wù)器端進(jìn)行解碼,即可解決。
項目地址:https://github.com/bjw1234/blog
完結(jié) 撒花 ^_^ ~
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/19201.html
摘要:所以呢解決這個問題也很簡單,就是對提交的內(nèi)容進(jìn)行或者其他形式的編碼,在服務(wù)器端進(jìn)行解碼,即可解決。項目地址完結(jié)撒花 NodeJs開發(fā)個人博客項目 預(yù)覽地址:http://baijiawei.top GitHub地址:https://github.com/bjw1234/blog 需要安裝的模塊 body-parser 解析post請求 cookies 讀寫cookie express...
摘要:最近在看,打算跟著書中的代碼敲一遍,加深對的理解。在這里記錄過程中的問題與心得。根據(jù)排查內(nèi)存耗盡應(yīng)該是這個版本的問題,換成后問題消失。因此認(rèn)為這種寫法是有風(fēng)險的,必須用頂上那一行注釋表明我確實要全局都的才行。不得不感嘆的嚴(yán)謹(jǐn)。 最近在看 build your own angularjs ,打算跟著書中的代碼敲一遍,加深對AngularJS的理解。在這里記錄過程中的問題與心得。 Int...
摘要:本地和服務(wù)器環(huán)境本地位服務(wù)器阿里云輕量應(yīng)用服務(wù)器使用的連接工具當(dāng)然還有這幾個中任選一個就好啦。連接工具使用方法創(chuàng)建填入服務(wù)器地址和用戶名,點(diǎn)擊確認(rèn)然后輸入密碼即可。執(zhí)行測試項目新建項目文件。使用編輯器打開項目文件。 本地和服務(wù)器環(huán)境 本地:Windows10 64位 服務(wù)器:阿里云輕量應(yīng)用服務(wù)器CentOS 7.3 使用的連接工具:puttymobaxterm當(dāng)然還有Xshell這幾個...
摘要:經(jīng)過在網(wǎng)上的查找,找到了和兩個事件進(jìn)行一個開關(guān)判斷。關(guān)于事件是的標(biāo)準(zhǔn)事件,對于檢測和這幾個元素通過用戶界面發(fā)生的內(nèi)容變化非常有用,在內(nèi)容修改后立即被觸發(fā),不像事件需要失去焦點(diǎn)才觸發(fā)。補(bǔ)充最近測試了下發(fā)現(xiàn)在事件之后才觸發(fā)。。。 事件背景 工作過程中涉及到了移動端輸入內(nèi)容長度的限定,這就要求需要對輸入過程中內(nèi)容的變化進(jìn)行監(jiān)控和判定,以決定是否可以繼續(xù)輸入,所以就想著是否可以在相關(guān)輸入處監(jiān)聽...
閱讀 1446·2021-11-24 09:39
閱讀 3626·2021-09-29 09:47
閱讀 1571·2021-09-29 09:34
閱讀 3067·2021-09-10 10:51
閱讀 2536·2019-08-30 15:54
閱讀 3216·2019-08-30 15:54
閱讀 869·2019-08-30 11:07
閱讀 1004·2019-08-29 18:36