blog-node 是採用了主流的先後端分離思想的,主裏只講 後端。html
blog-node 項目是 node + express + mongodb 的進行開發的,項目已經開源,項目地址在 github 上。前端
效果請看 http://biaochenxuying.cn/main.htmlvue
// modules const createError = require('http-errors'); const express = require('express'); const path = require('path'); const cookieParser = require('cookie-parser'); const logger = require('morgan'); const session = require('express-session'); // import 等語法要用到 babel 支持 require('babel-register'); const app = express(); // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'ejs'); app.use(logger('dev')); app.use(express.json()); app.use(express.urlencoded({ extended: false })); app.use(express.static(path.join(__dirname, 'public'))); app.use(cookieParser('blog_node_cookie')); app.use( session({ secret: 'blog_node_cookie', name: 'session_id', //# 在瀏覽器中生成cookie的名稱key,默認是connect.sid resave: true, saveUninitialized: true, cookie: { maxAge: 60 * 1000 * 30, httpOnly: true }, //過時時間 }), ); const mongodb = require('./core/mongodb'); // data server mongodb.connect(); //將路由文件引入 const route = require('./routes/index'); //初始化全部路由 route(app); // catch 404 and forward to error handler app.use(function(req, res, next) { next(createError(404)); }); // error handler app.use(function(err, req, res, next) { // set locals, only providing error in development res.locals.message = err.message; res.locals.error = req.app.get('env') === 'development' ? err : {}; // render the error page res.status(err.status || 500); res.render('error'); }); module.exports = app;
/** * Mongoose module. * @file 數據庫模塊 * @module core/mongoose * @author biaochenxuying <https://github.com/biaochenxuying> */ const consola = require('consola') const CONFIG = require('../app.config.js') const mongoose = require('mongoose') const autoIncrement = require('mongoose-auto-increment') // remove DeprecationWarning mongoose.set('useFindAndModify', false) // mongoose Promise mongoose.Promise = global.Promise // mongoose exports.mongoose = mongoose // connect exports.connect = () => { // 鏈接數據庫 mongoose.connect(CONFIG.MONGODB.uri, { useCreateIndex: true, useNewUrlParser: true, promiseLibrary: global.Promise }) // 鏈接錯誤 mongoose.connection.on('error', error => { consola.warn('數據庫鏈接失敗!', error) }) // 鏈接成功 mongoose.connection.once('open', () => { consola.ready('數據庫鏈接成功!') }) // 自增 ID 初始化 autoIncrement.initialize(mongoose.connection) // 返回實例 return mongoose }
這裏只介紹 用戶、文章和評論 的模型。java
用戶的字段都有設置類型 type,大多都設置了默認值 default ,郵箱設置了驗證規則 validate,密碼保存用了 crypto 來加密。node
用了中間件自增 ID 插件 mongoose-auto-increment。react
/** * User model module. * @file 權限和用戶數據模型 * @module model/user * @author biaochenxuying <https://github.com/biaochenxuying> */ const crypto = require('crypto'); const { argv } = require('yargs'); const { mongoose } = require('../core/mongodb.js'); const autoIncrement = require('mongoose-auto-increment'); const adminSchema = new mongoose.Schema({ // 名字 name: { type: String, required: true, default: '' }, // 用戶類型 0:博主 1:其餘用戶 type: { type: Number, default: 1 }, // 手機 phone: { type: String, default: '' }, //封面 img_url: { type: String, default: '' }, // 郵箱 email: { type: String, required: true, validate: /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/ }, // 我的介紹 introduce: { type: String, default: '' }, // 頭像 avatar: { type: String, default: 'user' }, // 密碼 password: { type: String, required: true, default: crypto .createHash('md5') .update(argv.auth_default_password || 'root') .digest('hex'), }, // 建立日期 create_time: { type: Date, default: Date.now }, // 最後修改日期 update_time: { type: Date, default: Date.now }, }); // 自增 ID 插件配置 adminSchema.plugin(autoIncrement.plugin, { model: 'User', field: 'id', startAt: 1, incrementBy: 1, }); module.exports = mongoose.model('User', adminSchema);
文章是分類型的:文章類型 => 1: 普通文章,2: 簡歷,3: 管理員介紹
並且簡歷和管理員介紹的文章只能是各自一篇(由於前臺展現那裏有個導航 關於我 ,就是請求管理員介紹這篇文章的,簡歷也是打算這樣子用的),普通文章能夠是無數篇。git
點讚的用戶 like_users 那裏應該只保存用戶 id 的,這個後面修改一下。程序員
/** * Article model module. * @file 文章數據模型 * @module model/article * @author biaochenxuying <https://github.com/biaochenxuying> */ const { mongoose } = require('../core/mongodb.js'); const autoIncrement = require('mongoose-auto-increment'); // 文章模型 const articleSchema = new mongoose.Schema({ // 文章標題 title: { type: String, required: true, validate: /\S+/ }, // 文章關鍵字(SEO) keyword: [{ type: String, default: '' }], // 做者 author: { type: String, required: true, validate: /\S+/ }, // 文章描述 desc: { type: String, default: '' }, // 文章內容 content: { type: String, required: true, validate: /\S+/ }, // 字數 numbers: { type: String, default: 0 }, // 封面圖 img_url: { type: String, default: 'https://upload-images.jianshu.io/upload_images/12890819-80fa7517ab3f2783.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240' }, // 文章類型 => 1: 普通文章,2: 簡歷,3: 管理員介紹 type: { type: Number, default: 1 }, // 文章發佈狀態 => 0 草稿,1 已發佈 state: { type: Number, default: 1 }, // 文章轉載狀態 => 0 原創,1 轉載,2 混合 origin: { type: Number, default: 0 }, // 文章標籤 tags: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Tag', required: true }], comments: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Comment', required: true }], // 文章分類 category: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Category', required: true }], // 點讚的用戶 like_users: [ { // 用戶id id: { type: mongoose.Schema.Types.ObjectId }, // 名字 name: { type: String, required: true, default: '' }, // 用戶類型 0:博主 1:其餘用戶 type: { type: Number, default: 1 }, // 我的介紹 introduce: { type: String, default: '' }, // 頭像 avatar: { type: String, default: 'user' }, // 建立日期 create_time: { type: Date, default: Date.now }, }, ], // 其餘元信息 meta: { views: { type: Number, default: 0 }, likes: { type: Number, default: 0 }, comments: { type: Number, default: 0 }, }, // 建立日期 create_time: { type: Date, default: Date.now }, // 最後修改日期 update_time: { type: Date, default: Date.now }, }); // 自增 ID 插件配置 articleSchema.plugin(autoIncrement.plugin, { model: 'Article', field: 'id', startAt: 1, incrementBy: 1, }); // 文章模型 module.exports = mongoose.model('Article', articleSchema);
評論功能是實現了簡單的三級評論的,第三者的評論(就是別人對一級評論進行再評論)放在 other_comments 裏面。github
/** * Comment model module. * @file 評論數據模型 * @module model/comment * @author biaochenxuying <https://github.com/biaochenxuying> */ const { mongoose } = require('../core/mongodb.js'); const autoIncrement = require('mongoose-auto-increment'); // 評論模型 const commentSchema = new mongoose.Schema({ // 評論所在的文章 id article_id: { type: mongoose.Schema.Types.ObjectId, required: true }, // content content: { type: String, required: true, validate: /\S+/ }, // 是否置頂 is_top: { type: Boolean, default: false }, // 被贊數 likes: { type: Number, default: 0 }, user_id: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true }, // 父評論的用戶信息 user: { // 用戶id user_id: { type: mongoose.Schema.Types.ObjectId }, // 名字 name: { type: String, required: true, default: '' }, // 用戶類型 0:博主 1:其餘用戶 type: { type: Number, default: 1 }, // 頭像 avatar: { type: String, default: 'user' }, }, // 第三者評論 other_comments: [ { user: { id: { type: mongoose.Schema.Types.ObjectId }, // 名字 name: { type: String, required: true, default: '' }, // 用戶類型 0:博主 1:其餘用戶 type: { type: Number, default: 1 }, }, // content content: { type: String, required: true, validate: /\S+/ }, // 狀態 => 0 待審覈 / 1 經過正常 / -1 已刪除 / -2 垃圾評論 state: { type: Number, default: 1 }, // 建立日期 create_time: { type: Date, default: Date.now }, }, ], // 狀態 => 0 待審覈 / 1 經過正常 / -1 已刪除 / -2 垃圾評論 state: { type: Number, default: 1 }, // 建立日期 create_time: { type: Date, default: Date.now }, // 最後修改日期 update_time: { type: Date, default: Date.now }, }); // 自增 ID 插件配置 commentSchema.plugin(autoIncrement.plugin, { model: 'Comment', field: 'id', startAt: 1, incrementBy: 1, }); // 標籤模型 module.exports = mongoose.model('Comment', commentSchema);
其餘模塊的具體需求,都是些經常使用的邏輯能夠實現的,也很簡單,這裏就不展開講了。mongodb
/* *全部的路由接口 */ const user = require('./user'); const article = require('./article'); const comment = require('./comment'); const message = require('./message'); const tag = require('./tag'); const link = require('./link'); const category = require('./category'); const timeAxis = require('./timeAxis'); module.exports = app => { app.post('/login', user.login); app.post('/logout', user.logout); app.post('/loginAdmin', user.loginAdmin); app.post('/register', user.register); app.post('/delUser', user.delUser); app.get('/currentUser', user.currentUser); app.get('/getUserList', user.getUserList); app.post('/addComment', comment.addComment); app.post('/addThirdComment', comment.addThirdComment); app.post('/changeComment', comment.changeComment); app.post('/changeThirdComment', comment.changeThirdComment); app.get('/getCommentList', comment.getCommentList); app.post('/addArticle', article.addArticle); app.post('/updateArticle', article.updateArticle); app.post('/delArticle', article.delArticle); app.get('/getArticleList', article.getArticleList); app.get('/getArticleListAdmin', article.getArticleListAdmin); app.post('/getArticleDetail', article.getArticleDetail); app.post('/likeArticle', article.likeArticle); app.post('/addTag', tag.addTag); app.post('/delTag', tag.delTag); app.get('/getTagList', tag.getTagList); app.post('/addMessage', message.addMessage); app.post('/addReplyMessage', message.addReplyMessage); app.post('/delMessage', message.delMessage); app.post('/getMessageDetail', message.getMessageDetail); app.get('/getMessageList', message.getMessageList); app.post('/addLink', link.addLink); app.post('/updateLink', link.updateLink); app.post('/delLink', link.delLink); app.get('/getLinkList', link.getLinkList); app.post('/addCategory', category.addCategory); app.post('/delCategory', category.delCategory); app.get('/getCategoryList', category.getCategoryList); app.post('/addTimeAxis', timeAxis.addTimeAxis); app.post('/updateTimeAxis', timeAxis.updateTimeAxis); app.post('/delTimeAxis', timeAxis.delTimeAxis); app.get('/getTimeAxisList', timeAxis.getTimeAxisList); app.post('/getTimeAxisDetail', timeAxis.getTimeAxisDetail); };
各模塊的列表都是用了分頁的形式的。
import Article from '../models/article'; import User from '../models/user'; import { responseClient, timestampToTime } from '../util/util'; exports.addArticle = (req, res) => { // if (!req.session.userInfo) { // responseClient(res, 200, 1, '您還沒登陸,或者登陸信息已過時,請從新登陸!'); // return; // } const { title, author, keyword, content, desc, img_url, tags, category, state, type, origin } = req.body; let tempArticle = null if(img_url){ tempArticle = new Article({ title, author, keyword: keyword ? keyword.split(',') : [], content, numbers: content.length, desc, img_url, tags: tags ? tags.split(',') : [], category: category ? category.split(',') : [], state, type, origin, }); }else{ tempArticle = new Article({ title, author, keyword: keyword ? keyword.split(',') : [], content, numbers: content.length, desc, tags: tags ? tags.split(',') : [], category: category ? category.split(',') : [], state, type, origin, }); } tempArticle .save() .then(data => { responseClient(res, 200, 0, '保存成功', data); }) .catch(err => { console.log(err); responseClient(res); }); }; exports.updateArticle = (req, res) => { // if (!req.session.userInfo) { // responseClient(res, 200, 1, '您還沒登陸,或者登陸信息已過時,請從新登陸!'); // return; // } const { title, author, keyword, content, desc, img_url, tags, category, state, type, origin, id } = req.body; Article.update( { _id: id }, { title, author, keyword: keyword ? keyword.split(','): [], content, desc, img_url, tags: tags ? tags.split(',') : [], category:category ? category.split(',') : [], state, type, origin, }, ) .then(result => { responseClient(res, 200, 0, '操做成功', result); }) .catch(err => { console.error(err); responseClient(res); }); }; exports.delArticle = (req, res) => { let { id } = req.body; Article.deleteMany({ _id: id }) .then(result => { if (result.n === 1) { responseClient(res, 200, 0, '刪除成功!'); } else { responseClient(res, 200, 1, '文章不存在'); } }) .catch(err => { console.error('err :', err); responseClient(res); }); }; // 前臺文章列表 exports.getArticleList = (req, res) => { let keyword = req.query.keyword || null; let state = req.query.state || ''; let likes = req.query.likes || ''; let tag_id = req.query.tag_id || ''; let category_id = req.query.category_id || ''; let pageNum = parseInt(req.query.pageNum) || 1; let pageSize = parseInt(req.query.pageSize) || 10; let conditions = {}; if (!state) { if (keyword) { const reg = new RegExp(keyword, 'i'); //不區分大小寫 conditions = { $or: [{ title: { $regex: reg } }, { desc: { $regex: reg } }], }; } } else if (state) { state = parseInt(state); if (keyword) { const reg = new RegExp(keyword, 'i'); conditions = { $and: [ { $or: [{ state: state }] }, { $or: [{ title: { $regex: reg } }, { desc: { $regex: reg } }, { keyword: { $regex: reg } }] }, ], }; } else { conditions = { state }; } } let skip = pageNum - 1 < 0 ? 0 : (pageNum - 1) * pageSize; let responseData = { count: 0, list: [], }; Article.countDocuments(conditions, (err, count) => { if (err) { console.log('Error:' + err); } else { responseData.count = count; // 待返回的字段 let fields = { title: 1, author: 1, keyword: 1, content: 1, desc: 1, img_url: 1, tags: 1, category: 1, state: 1, type: 1, origin: 1, comments: 1, like_User_id: 1, meta: 1, create_time: 1, update_time: 1, }; let options = { skip: skip, limit: pageSize, sort: { create_time: -1 }, }; Article.find(conditions, fields, options, (error, result) => { if (err) { console.error('Error:' + error); // throw error; } else { let newList = []; if (likes) { // 根據熱度 likes 返回數據 result.sort((a, b) => { return b.meta.likes - a.meta.likes; }); responseData.list = result; } else if (category_id) { // 根據 分類 id 返回數據 result.forEach(item => { if (item.category.indexOf(category_id) > -1) { newList.push(item); } }); let len = newList.length; responseData.count = len; responseData.list = newList; } else if (tag_id) { // 根據標籤 id 返回數據 result.forEach(item => { if (item.tags.indexOf(tag_id) > -1) { newList.push(item); } }); let len = newList.length; responseData.count = len; responseData.list = newList; } else { responseData.list = result; } responseClient(res, 200, 0, '操做成功!', responseData); } }); } }); }; // 後臺文章列表 exports.getArticleListAdmin = (req, res) => { let keyword = req.query.keyword || null; let state = req.query.state || ''; let likes = req.query.likes || ''; let pageNum = parseInt(req.query.pageNum) || 1; let pageSize = parseInt(req.query.pageSize) || 10; let conditions = {}; if (!state) { if (keyword) { const reg = new RegExp(keyword, 'i'); //不區分大小寫 conditions = { $or: [{ title: { $regex: reg } }, { desc: { $regex: reg } }], }; } } else if (state) { state = parseInt(state); if (keyword) { const reg = new RegExp(keyword, 'i'); conditions = { $and: [ { $or: [{ state: state }] }, { $or: [{ title: { $regex: reg } }, { desc: { $regex: reg } }, { keyword: { $regex: reg } }] }, ], }; } else { conditions = { state }; } } let skip = pageNum - 1 < 0 ? 0 : (pageNum - 1) * pageSize; let responseData = { count: 0, list: [], }; Article.countDocuments(conditions, (err, count) => { if (err) { console.log('Error:' + err); } else { responseData.count = count; // 待返回的字段 let fields = { title: 1, author: 1, keyword: 1, content: 1, desc: 1, img_url: 1, tags: 1, category: 1, state: 1, type: 1, origin: 1, comments: 1, like_User_id: 1, meta: 1, create_time: 1, update_time: 1, }; let options = { skip: skip, limit: pageSize, sort: { create_time: -1 }, }; Article.find(conditions, fields, options, (error, result) => { if (err) { console.error('Error:' + error); // throw error; } else { if (likes) { result.sort((a, b) => { return b.meta.likes - a.meta.likes; }); } responseData.list = result; responseClient(res, 200, 0, '操做成功!', responseData); } }) .populate([ { path: 'tags', }, { path: 'comments', }, { path: 'category', }, ]) .exec((err, doc) => {}); } }); }; // 文章點贊 exports.likeArticle = (req, res) => { if (!req.session.userInfo) { responseClient(res, 200, 1, '您還沒登陸,或者登陸信息已過時,請從新登陸!'); return; } let { id, user_id } = req.body; Article.findOne({ _id: id }) .then(data => { let fields = {}; data.meta.likes = data.meta.likes + 1; fields.meta = data.meta; let like_users_arr = data.like_users.length ? data.like_users : []; User.findOne({ _id: user_id }) .then(user => { let new_like_user = {}; new_like_user.id = user._id; new_like_user.name = user.name; new_like_user.avatar = user.avatar; new_like_user.create_time = user.create_time; new_like_user.type = user.type; new_like_user.introduce = user.introduce; like_users_arr.push(new_like_user); fields.like_users = like_users_arr; Article.update({ _id: id }, fields) .then(result => { responseClient(res, 200, 0, '操做成功!', result); }) .catch(err => { console.error('err :', err); throw err; }); }) .catch(err => { responseClient(res); console.error('err 1:', err); }); }) .catch(err => { responseClient(res); console.error('err 2:', err); }); }; // 文章詳情 exports.getArticleDetailByType = (req, res) => { let { type } = req.body; if (!type) { responseClient(res, 200, 1, '文章不存在 !'); return; } Article.findOne({ type: type }, (Error, data) => { if (Error) { console.error('Error:' + Error); // throw error; } else { data.meta.views = data.meta.views + 1; Article.updateOne({ type: type }, { meta: data.meta }) .then(result => { responseClient(res, 200, 0, '操做成功 !', data); }) .catch(err => { console.error('err :', err); throw err; }); } }) .populate([ { path: 'tags', select: '-_id' }, { path: 'category', select: '-_id' }, { path: 'comments', select: '-_id' }, ]) .exec((err, doc) => { // console.log("doc:"); // aikin // console.log("doc.tags:",doc.tags); // aikin // console.log("doc.category:",doc.category); // undefined }); }; // 文章詳情 exports.getArticleDetail = (req, res) => { let { id } = req.body; let type = Number(req.body.type) || 1; //文章類型 => 1: 普通文章,2: 簡歷,3: 管理員介紹 console.log('type:', type); if (type === 1) { if (!id) { responseClient(res, 200, 1, '文章不存在 !'); return; } Article.findOne({ _id: id }, (Error, data) => { if (Error) { console.error('Error:' + Error); // throw error; } else { data.meta.views = data.meta.views + 1; Article.updateOne({ _id: id }, { meta: data.meta }) .then(result => { responseClient(res, 200, 0, '操做成功 !', data); }) .catch(err => { console.error('err :', err); throw err; }); } }) .populate([ { path: 'tags', }, { path: 'category', }, { path: 'comments', }, ]) .exec((err, doc) => { // console.log("doc:"); // aikin // console.log("doc.tags:",doc.tags); // aikin // console.log("doc.category:",doc.category); // undefined }); } else { Article.findOne({ type: type }, (Error, data) => { if (Error) { console.log('Error:' + Error); // throw error; } else { if (data) { data.meta.views = data.meta.views + 1; Article.updateOne({ type: type }, { meta: data.meta }) .then(result => { responseClient(res, 200, 0, '操做成功 !', data); }) .catch(err => { console.error('err :', err); throw err; }); } else { responseClient(res, 200, 1, '文章不存在 !'); return; } } }) .populate([ { path: 'tags', }, { path: 'category', }, { path: 'comments', }, ]) .exec((err, doc) => {}); } };
評論是有狀態的:狀態 => 0 待審覈 / 1 經過正常 / -1 已刪除 / -2 垃圾評論。
管理一級和三級評論是設置前臺能不能展現的,默認是展現,若是管理員看了,是條垃圾評論就 設置爲 -1 或者 -2 ,進行隱藏,前臺就不會展示了。
import { responseClient } from '../util/util'; import Comment from '../models/comment'; import User from '../models/user'; import Article from '../models/article'; //獲取所有評論 exports.getCommentList = (req, res) => { let keyword = req.query.keyword || null; let comment_id = req.query.comment_id || null; let pageNum = parseInt(req.query.pageNum) || 1; let pageSize = parseInt(req.query.pageSize) || 10; let conditions = {}; if (comment_id) { if (keyword) { const reg = new RegExp(keyword, 'i'); //不區分大小寫 conditions = { _id: comment_id, content: { $regex: reg }, }; } else { conditions = { _id: comment_id, }; } } else { if (keyword) { const reg = new RegExp(keyword, 'i'); //不區分大小寫 conditions = { content: { $regex: reg }, }; } } let skip = pageNum - 1 < 0 ? 0 : (pageNum - 1) * pageSize; let responseData = { count: 0, list: [], }; Comment.countDocuments(conditions, (err, count) => { if (err) { console.error('Error:' + err); } else { responseData.count = count; // 待返回的字段 let fields = { article_id: 1, content: 1, is_top: 1, likes: 1, user_id: 1, user: 1, other_comments: 1, state: 1, create_time: 1, update_time: 1, }; let options = { skip: skip, limit: pageSize, sort: { create_time: -1 }, }; Comment.find(conditions, fields, options, (error, result) => { if (err) { console.error('Error:' + error); // throw error; } else { responseData.list = result; responseClient(res, 200, 0, '操做成功!', responseData); } }); } }); }; // 添加一級評論 exports.addComment = (req, res) => { if (!req.session.userInfo) { responseClient(res, 200, 1, '您還沒登陸,或者登陸信息已過時,請從新登陸!'); return; } let { article_id, user_id, content } = req.body; User.findById({ _id: user_id, }) .then(result => { // console.log('result :', result); if (result) { let userInfo = { user_id: result._id, name: result.name, type: result.type, avatar: result.avatar, }; let comment = new Comment({ article_id: article_id, content: content, user_id: user_id, user: userInfo, }); comment .save() .then(commentResult => { Article.findOne({ _id: article_id }, (errors, data) => { if (errors) { console.error('Error:' + errors); // throw errors; } else { data.comments.push(commentResult._id); data.meta.comments = data.meta.comments + 1; Article.updateOne({ _id: article_id }, { comments: data.comments, meta: data.meta }) .then(result => { responseClient(res, 200, 0, '操做成功 !', commentResult); }) .catch(err => { console.error('err :', err); throw err; }); } }); }) .catch(err2 => { console.error('err :', err2); throw err2; }); } else { responseClient(res, 200, 1, '用戶不存在'); } }) .catch(error => { console.error('error :', error); responseClient(res); }); }; // 添加第三者評論 exports.addThirdComment = (req, res) => { if (!req.session.userInfo) { responseClient(res, 200, 1, '您還沒登陸,或者登陸信息已過時,請從新登陸!'); return; } let { article_id, comment_id, user_id, content } = req.body; Comment.findById({ _id: comment_id, }) .then(commentResult => { User.findById({ _id: user_id, }) .then(userResult => { if (userResult) { let userInfo = { user_id: userResult._id, name: userResult.name, type: userResult.type, avatar: userResult.avatar, }; let item = { user: userInfo, content: content, }; commentResult.other_comments.push(item); Comment.updateOne( { _id: comment_id }, { other_comments: commentResult, }, ) .then(result => { responseClient(res, 200, 0, '操做成功', result); Article.findOne({ _id: article_id }, (errors, data) => { if (errors) { console.error('Error:' + errors); // throw errors; } else { data.meta.comments = data.meta.comments + 1; Article.updateOne({ _id: article_id }, { meta: data.meta }) .then(result => { // console.log('result :', result); responseClient(res, 200, 0, '操做成功 !', result); }) .catch(err => { console.log('err :', err); throw err; }); } }); }) .catch(err1 => { console.error('err1:', err1); responseClient(res); }); } else { responseClient(res, 200, 1, '用戶不存在'); } }) .catch(error => { console.error('error :', error); responseClient(res); }); }) .catch(error2 => { console.error('error2 :', error2); responseClient(res); }); }; // 管理一級評論 exports.changeComment = (req, res) => { if (!req.session.userInfo) { responseClient(res, 200, 1, '您還沒登陸,或者登陸信息已過時,請從新登陸!'); return; } let { id, state } = req.body; Comment.updateOne( { _id: id }, { state: Number(state), }, ) .then(result => { responseClient(res, 200, 0, '操做成功', result); }) .catch(err => { console.error('err:', err); responseClient(res); }); }; // 管理第三者評論 exports.changeThirdComment = (req, res) => { if (!req.session.userInfo) { responseClient(res, 200, 1, '您還沒登陸,或者登陸信息已過時,請從新登陸!'); return; } let { comment_id, state, index } = req.body; Comment.findById({ _id: comment_id, }) .then(commentResult => { let i = index ? Number(index) : 0; if (commentResult.other_comments.length) { commentResult.other_comments[i].state = Number(state); Comment.updateOne( { _id: comment_id }, { other_comments: commentResult, }, ) .then(result => { responseClient(res, 200, 0, '操做成功', result); }) .catch(err1 => { console.error('err1:', err1); responseClient(res); }); } else { responseClient(res, 200, 1, '第三方評論不存在!', result); } }) .catch(error2 => { console.log('error2 :', error2); responseClient(res); }); };
其餘模塊的具體需求,都是些經常使用的邏輯能夠實現的,也很簡單,這裏就不展開講了。
# install dependencies npm install # serve with hot reload at localhost: 3000 npm start # build for production with minification 請使用 pm2 ,能夠永久運行在服務器上,且不會一報錯 node 程序就掛了。
若是以爲該項目不錯或者對你有所幫助,歡迎到 github 上給個 star,謝謝。
項目地址:
前臺展現: https://github.com/biaochenxuying/blog-react管理後臺:https://github.com/biaochenxuying/blog-react-admin
本博客系統的系列文章:
小汪也是第一次搭建 node 後端項目,也參考了其餘項目。
參考項目:
1. nodepress
2. React-Express-Blog-Demo
對 全棧開發 有興趣的朋友,能夠掃下方二維碼,關注個人公衆號,我會不按期更新有價值的內容。
微信公衆號: BiaoChenXuYing
分享 前端、後端開發 等相關的技術文章,熱點資源,全棧程序員的成長之路。
關注公衆號並回復 福利 便免費送你視頻資源,絕對乾貨。
福利詳情請點擊: 免費資源分享--Python、Java、Linux、Go、node、vue、react、javaScript