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