基於express+mongodb+pug的博客系統——後臺篇

来源:http://www.cnblogs.com/mcbai/archive/2017/05/21/6885306.html
-Advertisement-
Play Games

上一篇介紹了模板引擎pug.js的用法,這一篇就主要寫後臺邏輯了。 後臺的大部分的功能都有了,只是在已經登錄的狀態下,前臺和後臺的邏輯處理還不是很完善。 先上幾張圖吧,仿舊版的簡書,改了下UI,因為沒有簡書那麼多內容,所以沒必要完全做成一樣的。 1.項目結構 app.js 是整個工程的入口 mode ...


上一篇介紹了模板引擎pug.js的用法,這一篇就主要寫後臺邏輯了。

後臺的大部分的功能都有了,只是在已經登錄的狀態下,前臺和後臺的邏輯處理還不是很完善。

先上幾張圖吧,仿舊版的簡書,改了下UI,因為沒有簡書那麼多內容,所以沒必要完全做成一樣的。

 

 

1.項目結構

app.js 是整個工程的入口

model 文件夾放連接資料庫的邏輯

public 文件夾里全是靜態資源

router 文件夾是各個模塊的路由文件,route.js是總入口

upload 里是上傳的圖像文件

views 里全是模板,layout.pug是最外層的框架模板,componentspages里則分別是公共組件和各個頁面的模板。

2.app.js

app.js代碼:

 app.js是整個工程的入口,這裡沒什麼問題,裡面的模板引擎配置和靜態文件項配置在文檔里都有說明。需要註意的是靜態文件設置這裡,最好使用path.join,因為我按照上面設置模板引擎的寫法去寫,始終會報錯,找不到對應的文件。

 3.router

 在這個文件夾里全是路由的相關配置

route.js

 

articleList.js

router部分被我根據業務相關,劃分成了登錄、文章、管理三個部分。每個部分都會把他們相關的請求邏輯寫在一個js文件里,然後在最下麵暴露出router介面,最後在route.js中統一分發處理。

在router.js里,會把所有的路由都掛在app這個對象上,然後暴露app,以便在入口文件app.js中使用。

另外在這裡還用到了session來進行登錄狀態的保存處理,可以使用req.session.xxx來獲取或者新建並保存一個屬性。

這裡唯一存在的問題就是在設置了maxAge之後,不管中途有沒有操作頁面,只要時間到了,都會清除掉cookie,不能做到只要頁面活躍時,cookie就不會過期。不知道是不是我哪設置的有問題。

 

login.js

登錄邏輯做的比較簡單,僅僅是獲取前臺傳過來的值,然後與資料庫里的值做對比,並沒有做有效性校驗和加密處理等,在實際的項目中都應該加上的。

這裡還用到了POST請求,對於POST請求,還需要單獨引入body-parser這個中間件,才能對POST傳入的值進行獲取處理。

4.model

model部分主要是負責連接資料庫,獲取並返回值。

connect.js

connect.js文件主要負責連接資料庫,並且將db對象暴露出去,這樣在其他需要的地方可以直接引用,而不用再次進行連接操作。

 

article_list.js文件代碼比較多,直接複製過來。

var mongoose = require('mongoose');

// 定義Schema
var articleSchema = new mongoose.Schema({
  author: String,
  createtime: String,
  updatetime: String,
  type: String,
  label: String,
  title: String,
  description: String,
  content: String,
  text: String,
  delta: Object,
  pv: Number,
  likes: Number,
  image: String
})
// 存入資料庫之前的操作
articleSchema.pre('save', function (next) {
  var date = new Date();
  if (this.isNew) {
    this.updatetime = this.createtime = date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate();
  } else {
    this.updatetime = date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate();
  }
  next()
});
// 定義model,關聯相關的表
var articleModel = mongoose.model('article_list', articleSchema);

function findArticle(option, callback) {
  articleModel.find(option, function (err, result) {
    if (err) console.log(err);
    // 渲染模板
    var data = {
      articleLists: result
    };

    callback(data)
  })
}

// 渲染文章列表
var renderArticleList = function (articleType, callback) {
  switch (articleType) {
    case 'all': findArticle({}, callback)
      break;
    case 'novel': findArticle({ type: '小說' }, callback)
      break;
    case 'it': findArticle({ type: '編程' }, callback)
      break;
    default: res.send('暫時沒有!')
  }
};

// 渲染文章詳情
var renderArticle = function (articleId, callback) {
  var articleId = mongoose.mongo.ObjectId(articleId)
  articleModel.find({ _id: articleId }, function (err, result) {
    if (err) console.log(err);

    callback(result[0])
  })
}

// 喜歡數增加
var addLike = function (req, res) {

}

// 文章管理列表分頁獲取數據
var renderManage = function (opt, callback) {
  var currentSize = (opt.currentPage - 1) * opt.pageSize;
  articleModel.find({}, function (err, result) {
    var data = {
      articleLists: result
    };
    callback(result)
  }).skip(currentSize).limit(opt.pageSize)
}
// 文章管理列表獲取總數
var getLength = function (callback) {
  articleModel.find({}, function (err, result) {
    callback(result.length)
  })
}

// 文章編輯保存
var saveArticle = function (article_opt, callback) {
  var newArticle = new articleModel(article_opt);
  if (article_opt.params_id) {
    var _id = article_opt.params_id
    articleModel.findOneAndUpdate({ _id: _id }, article_opt, function (err, result) {
      callback(result._id)
    })
  } else {
    newArticle.save(function (err, result) {
      callback(result._id)
    })
  }
}

// 文章刪除
var deleteArticle = function (articleId, callback) {
  articleModel.remove({_id: articleId}, function (err, result) {
    console.log(result)
    callback()
  })
}

var modelHome = {
  renderArticleList: renderArticleList,
  renderArticle: renderArticle,
  renderManage: renderManage,
  getLength: getLength,
  saveArticle: saveArticle,
  deleteArticle: deleteArticle
};

module.exports = modelHome;

凡是涉及到article_lists這個表的邏輯,都會寫在article_list.js里,不過這裡應該是可以優化的,因為這裡應該只處理model部分,而不應該有邏輯操作部分。

在使用mongoose這個庫連接mongoDB的時候需要註意,在定義model,關聯相關的表的時候, var articleModel = mongoose.model('article_list', articleSchema); 這裡的article_list對應的是你資料庫里的表article_lists,資料庫里的表要多一個s。


在編輯文章的時候,除了新建文章之外,還可以直接修改已有的文章,所以這就涉及到數據的插值和更新,如果使用原生的mongoDB方法,可以很簡單的通過save()方法來實現,但是在mongoose中卻不行,mongoose中的save()方法和原生的insert()基本相同。

所以使用mongoose的時候需要分兩步,更新值使用findOneAndUpdate(),新建使用save()方法。

 

結語:

在這個版本里,還有一些功能沒有做,比如點贊之類,但大的功能都有了,不過剩下的我並不打算再寫了,再寫的時候肯定是重構了。

原因是寫到這裡,自己能發現很多地方可以優化,還有最重要的一點是,express是一個輕量級的框架,他很靈活,但是很多東西需要藉助第三方插件或者庫,這就給人帶來了很多麻煩。

第三方庫良莠不齊,在最初的選擇上面,你需要花很多功夫,選好了之後,你還得挨個去瞭解學習,挨個去踩坑,這都是很麻煩的事,所以並不建議大家直接在公司的重要項目里直接使用express這個框架。

當然如果只是一些比較簡單的頁面,比如活動頁或者一些不設計太多前後臺邏輯交互的頁面,還是可以使用express的,因為它真的很簡單,你不需要會先去把es6搞明白,也不需要把node完全弄清楚。

只需要簡單的看看express官網嗎,就能很快上手做出一個具有前後臺交互的東西出來。

代碼地址:https://github.com/Mcbai/blog

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 上節談了談類工廠/對象查找服務,本節談談AOP的實現。 AOP為Aspect Oriented Programming的縮寫,意為:面向切麵編程,通過預編譯方式和運行期動態代理實現程式功能的統一維護的一種技術。 Netop.Core的AOP採用代理的實現方式。採用代理方式,您的類就必須繼承一個基類( ...
  • 截止目前,筆者在博客園上面已經發表了3篇關於網路下載的文章,這三篇博客實現了基於socket的http多線程遠程斷點下載實用程式。筆者打算在此基礎上開發出一款分散式文件管理實用程式,截止目前,已經實現了 服務端/客戶端 的上傳、下載部分的功能邏輯。涉及到的知識點包括線程池技術、linux epoll... ...
  • 組合模式:將對象組合成樹形結構以表示“部分-整體”的層次結構。 組合模式使得用戶對單個對象和組合對象的使用具有一致性。 是一種結構型模式 使用場景: 1、用於對象的部分-整體層次結構,如樹形菜單、文件夾菜單、部門組織架構圖等; 2、對用戶隱藏組合對象與單個對象的不同,使得用戶統一地使用組合結構中的所 ...
  • 原文參考http://mp.weixin.qq.com/s?__biz=MzU3MDA0NTMzMA==&mid=2247485490&idx=1&sn=15197b4b53e0669e4a017e54a31fb39c&source=41#wechat_redirect 使用原生js ...
  • 本文介紹了windows系統下安裝`nvm nodejs`版本管理包。並且配置了阿裡巴巴的`nodejs`的鏡像和`npm`鏡像。並且,結合webstorm創建出了`nodejs express`項目,成功安裝依賴並運行起來。 ...
  • 微信小程式demo "github地址" 去年小程式剛發佈時特別火,趕潮流做了個demo。感覺小程式開發還是比較簡單的,主要是官方文檔寫得比較好,遺憾的是很多API需要微信認證才能使用。 由於小程式包大小限制在1M以內,所以商品圖片等資源放在了雲上,另外用Nodejs+Express寫了個簡單的AP ...
  • 1.元素浮動: 1)使用 float:left; 這樣的格式設置元素的浮動方式,屬性值可以是left,right; 2)元素設置為左浮動時,元素將從原區域浮動到瀏覽器的左側頁面;右浮動時,就會附在右側的區域,而且元素是按照第一個元素在右側的第一個位置,依次往左排列; 3)設置了浮動後,該元素相當於直 ...
  • HTML中有很多的標簽(元素),可以按照這些元素在網頁中所占的空間情況進行分類。具體可以這樣簡單的分類: 1.塊級元素:指的是在網頁中該元素獨自占據網頁的一行顯示區域,即當使用了該元素後,該元素會使下一個元素在下一行展示,也就是產生換行;根據資料的定義是:標簽的display屬性值為block; 2 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...