需要安裝的模塊
目錄結構
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.配置應用模板
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'));
劃分模塊
// 根據不同的功能劃分模塊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/userrouter.get('/user',function(req,res,next) { res.send('User');});module.exports = router;
前臺路由 + 模板
main 模塊
/ 首頁
/view 內容頁
api模塊
/首頁
/register 用戶注冊
/login 用戶登錄
/comment 評論獲取
/comment/post 評論提交
后臺(admin)路由+模板
首頁
/ 后臺首頁
用戶管理
/user 用戶列表
分類管理
/category 分類列表
/category/add 分類添加
/category/edit 分類修改
/caterory/delete 分類刪除
文章內容管理
/article nei內容列表
/article/add 內容添加
/article/edit 內容修改
/article/delete 內容刪除
評論內容管理
/comment 評論列表
/comment/delete 評論刪除
功能開發順序
功能模塊開發順序
編碼順序
連接數據庫(mongoDB)
啟動MongoDB服務端:
mongod --dbpath=G:/data/db --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(); }});// 當用戶登錄或注冊成功之后,可以為其設置cookiesreq.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循環
// arr = [1, 2, 3]
{ % for key, val in arr % }
<p>{ { key } } -- { { val } }</p>
{ % 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代碼,模板渲染時會自動編碼,
以字符串的形式顯示。通過以下方式,可以避免這個情況:
<div id="article-content" class="content"> {% autoescape false %} {{ data.article_content_html }} {% endautoescape %}</div>
用戶管理和分頁
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) * 每頁顯示的條數
// 接收傳過來的pagelet query_page = Number(req.query.page) || 1;query_page = Math.max(query_page, 1); // 限制最小為1query_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.jsvar mongoose = require('mongoose');var contentSch = require('../schemas/contentSch');module.exports = mongoose.model('Content',contentSch);// contentSch.jsmodule.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中直接使用
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/default.min.css"><script src="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script><script src="https://cdn.bootcss.com/marked/0.3.17/marked.min.js"></script>// 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環境中使用
// 在模板頁面引入默認樣式<!--語法高亮--><link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/default.min.css">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;
orm表單提交的小問題
當使用form表單提交一些代碼的時候,會出現瀏覽器攔截的現象,原因是:瀏覽器誤以為客戶進行xss攻擊。所以呢解決這個問題也很簡單,就是對提交的內容進行base64或者其他形式的編碼,在服務器端進行解碼,即可解決。
源碼地址:https://github.com/bjw1234/blog
新聞熱點
疑難解答