国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

后端小白的我,是如何成功搭建 express+mongodb 的簡潔博客網站后端的

Kahn / 3023人閱讀

摘要:前言是采用了主流的前后端分離思想的,主里只講后端。項目是的進行開發的,項目已經開源,項目地址在上。路由接口主文件所有的路由接口文章各模塊的列表都是用了分頁的形式的。

前言

blog-node 是采用了主流的前后端分離思想的,主里只講 后端。

blog-node 項目是 node + express + mongodb 的進行開發的,項目已經開源,項目地址在 github 上。

效果請看 http://biaochenxuying.cn/main.html

1. 后端 1.1 已經實現功能

[x] 登錄

[x] 文章管理

[x] 標簽管理

[x] 評論

[x] 留言管理

[x] 用戶管理

[x] 友情鏈接管理

[x] 時間軸管理

[x] 身份驗證

1.2 待實現功能

[ ] 點贊、留言和評論 的通知管理

[ ] 個人中心(用來設置博主的各種信息)

[ ] 工作臺( 接入百度統計接口,查看網站瀏覽量和用戶訪問等數據 )

2. 技術

node

cookie-parser : "~1.4.3"

crypto : "^1.0.1"

express: "~4.16.0"

express-session : "^1.15.6",

http-errors : "~1.6.2",

mongodb : "^3.1.8",

mongoose : "^5.3.7",

mongoose-auto-increment : "^5.0.1",

yargs : "^12.0.2"

3. 主文件 app.js
// 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;
4. 數據庫 core/mongodb.js
/**
 * Mongoose module.
 * @file 數據庫模塊
 * @module core/mongoose
 * @author  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
}
5. 數據模型 Model

這里只介紹 用戶、文章和評論 的模型。

5.1 用戶

用戶的字段都有設置類型 type,大多都設置了默認值 default ,郵箱設置了驗證規則 validate,密碼保存用了 crypto 來加密。

用了中間件自增 ID 插件 mongoose-auto-increment。

/**
 * User model module.
 * @file 權限和用戶數據模型
 * @module model/user
 * @author 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);
5.2 文章

文章是分類型的:文章類型 => 1: 普通文章,2: 簡歷,3: 管理員介紹
而且簡歷和管理員介紹的文章只能是各自一篇(因為前臺展示那里有個導航 關于我 ,就是請求管理員介紹這篇文章的,簡歷也是打算這樣子用的),普通文章可以是無數篇。

點贊的用戶 like_users 那里應該只保存用戶 id 的,這個后面修改一下。

/**
 * Article model module.
 * @file 文章數據模型
 * @module model/article
 * @author 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);
5.3 評論

評論功能是實現了簡單的三級評論的,第三者的評論(就是別人對一級評論進行再評論)放在 other_comments 里面。

/**
 * Comment model module.
 * @file 評論數據模型
 * @module model/comment
 * @author 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);

其他模塊的具體需求,都是些常用的邏輯可以實現的,也很簡單,這里就不展開講了。

6. 路由接口 routes 6.1 主文件
/*
*所有的路由接口
*/
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);
};
6.2 文章

各模塊的列表都是用了分頁的形式的。

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) => {});
    }
};
6.3 評論

評論是有狀態的:狀態 => 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);
        });
};

其他模塊的具體需求,都是些常用的邏輯可以實現的,也很簡單,這里就不展開講了。

7. Build Setup ( 構建安裝 )
# install dependencies
npm install 

# serve with hot reload at localhost: 3000
npm start 

# build for production with minification
請使用 pm2 ,可以永久運行在服務器上,且不會一報錯 node 程序就掛了。
8. 項目地址

如果覺得該項目不錯或者對你有所幫助,歡迎到 github 上給個 star,謝謝。

項目地址:

前臺展示: https://github.com/biaochenxuying/blog-react

管理后臺:https://github.com/biaochenxuying/blog-react-admin

后端:https://github.com/biaochenxuying/blog-node

blog:https://github.com/biaochenxuying/blog

本博客系統的系列文章:

react + node + express + ant + mongodb 的簡潔兼時尚的博客網站

react + Ant Design + 支持 markdown 的 blog-react 項目文檔說明

基于 node + express + mongodb 的 blog-node 項目文檔說明

服務器小白的我,是如何將node+mongodb項目部署在服務器上并進行性能優化的

9. 最后

小汪也是第一次搭建 node 后端項目,也參考了其他項目。

參考項目:
1. nodepress
2. React-Express-Blog-Demo

全棧開發 有興趣的朋友,可以掃下方二維碼,關注我的公眾號,我會不定期更新有價值的內容。

微信公眾號:BiaoChenXuYing
分享 前端、后端開發 等相關的技術文章,熱點資源,全棧程序員的成長之路。

關注公眾號并回復 福利 便免費送你視頻資源,絕對干貨。

福利詳情請點擊: 免費資源分享--Python、Java、Linux、Go、node、vue、react、javaScript

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/19433.html

相關文章

  • react + node + express + ant + mongodb 簡潔兼時尚博客網站

    摘要:前言此項目是用于構建博客網站的,由三部分組成,包含前臺展示管理后臺和后端。體驗地址網站主頁網站首頁管理后臺計劃這次是一個完整的全棧式開發,只要部署了這三個項目的代碼,是完全可以搭建好博客網站的。 showImg(https://segmentfault.com/img/remote/1460000017095592); 前言 此項目是用于構建博客網站的,由三部分組成,包含前臺展示、管理...

    fish 評論0 收藏0
  • 服務器小白,如何成功將 node+mongodb 項目部署在服務器上并進行性能優化

    摘要:前言本文講解的是做為前端開發人員,對服務器的了解還是小白的我,是如何一步步將項目部署在阿里云的服務器上,并進行性能優化,達到頁面秒內看到,秒內看到首屏內容的。搭建的項目是采用了主流的前后端分離思想的,這里只講服務器環境搭建與性能優化。 showImg(https://segmentfault.com/img/remote/1460000017143281); 前言 本文講解的是:做為前...

    zsy888 評論0 收藏0
  • react + Ant Design blog-react-admin 項目項目文檔說明

    摘要:前言此項目是基于螞蟻金服開源的之上,用全家桶的進行再次開發的,項目已經開源,項目地址在上。項目地址開源不易,如果覺得該項目不錯或者對你有所幫助,歡迎到上給個,謝謝。 showImg(https://segmentfault.com/img/remote/1460000017116745); 前言 此 blog-react-admin 項目是基于 螞蟻金服開源的 ant design p...

    chavesgu 評論0 收藏0
  • 全棧最一公里 - Node.js 項目線上服務器部署與發布

    摘要:沒有耐心閱讀的同學,可以直接前往學習全棧最后一公里。我下面會羅列一些,我自己錄制過的一些項目,或者其他的我覺得可以按照這個路線繼續深入學習的項目資源。 showImg(https://segmentfault.com/img/bVMlke?w=833&h=410); 本文技術軟文,閱讀需謹慎,長約 7000 字,通讀需 5 分鐘 大家好,我是 Scott,本文通過提供給大家學習的方法,...

    Nosee 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<