MongoDB(博客后台接口)

MongoDB

参考地址http://47.94.210.129/malulesson/network/node/08.html

MongoDB

什么是MongoDB?

MongoDB和MySQL一样都是数据库, 都是存储数据的仓库, 不同的是MySQL是关系型数据库, 而MongoDB是非关系型数据库,MongoDB中的存储的数据是类JSON。

什么是非关系型数据库?
  • 在’关系型数据库’中, 数据都是存储在表中的, 对存储的内容有严格的要求, 因为在创建表的时候我们就

    • 已经规定了表中有多少个字段,
    • 已经规定了每个字段将来要存储什么类型数据,
    • 已经规定了每个字段将来是否可以为空, 是否必须唯一等等
  • 在’非关系型数据库’中, 没有表概念, 所以存储数据更加灵活因为不需要创建表, 所以

    • 也没有规定有哪些字段,
    • 也没有规定每个字段数据类型,
    • 也没有规定每个字段将来是否可以为空,是否必须唯一等等
  • '关系型数据库’由于操作的都是结构化的数据, 所以我们需要使用结构化语言SQL来操作

  • '非关系型数据库’由于数据没有严格的结构要求, 所以无需使用SQL来操作

什么是MongoDB?
1.存储文档(BSON)的非关系型数据库
    1)例如在MySQL中:
    |--------------------------------------------------------|
    |   name(varchar(255) not null)   |    age(int unique)   |
    |--------------------------------------------------------|
    我们可以把            'zs', 33        保存到表中
    但是我们不能将         33, 'zs'       保存到表中
    但我们不能能将         null, 33       保存到表中
    但是我们不能将         'zs', 33,  '男' 保存到表中
    但是我们不能再次将     'zs', 33        保存到表中
2)例如在MongoDB中:
    我们可以把         {name: 'zs', age: 33};              保存到集合中
    我们也可以把       {name: 33, age: 'zs'};              保存到集合中
    我们也可以把       {name: null, age: 33};              保存到集合中
    我们也可以把       {name: 'zs', age: 33, gender:'男'}; 保存到集合中
    但是我们可以再次将 {name: 'zs', age: 33};              保存到集合中
2.'非关系型数据库'可以看做是'关系型数据库'的功能阉割版本,
  通过减少用不到或很少用的功能,从而提升数据库的性能    
MongoDB是如何存储文档的?
1.MySQL中所有的数据都是存储在表中的, 而MongoDB中所有的数据都是存储在集合中的
	1)MySQL
                         |--1
                |--1-- |--2
        数据库--|         |--3
                |--2
                |--... ...
    2)MongoDB
                          |--文档1
                |--集合1--|--文档2
        数据库--|          |--文档3
                |--集合2
                |--... ...

企业开发如何选择?
  1. 关系型数据库和非关系型数据库之间并不是替代关系, 而是互补关系 所以在企业开发中大部分情况是结合在一起使用

  2. 对于数据模型比较简单、数据性能要求较高、数据灵活性较强的数据, 我们存储到非关系型数据库中 相反则存储到关系型数据库中

比较重要的数据,存储在mysql中,不是那么重要的数据,存储在MongoDB中。

MongoDB安装

安装MongoDB

https://blog.csdn.net/weixin_40119412/article/details/123781139

  1. 下载地址: https://www.mongodb.org/dl/win32
  2. MongoDB版本号: 偶数为稳定版(推荐), 基数为开发版
  3. MongoDB对32位操作系统支持不佳, 不推荐在32位系统上使用, 并且官方已经停更32位安装包
MongoDB安装步骤
  1. 全程下一步,修改安装路径
  2. 配置环境变量, 将MongoDB的bin目录配置到系统变量Path中
  3. 可以去服务列表中打开服务,相当于开始服务器。
安装可视化工具

下载地址: https://www.mongodbmanager.com/

monogodb原⽣驱动

所需依赖
通过npm i直接安装上面的依赖。

"dependencies": {
    "express": "^4.17.3",
    "mongodb": "^4.4.0",
    "mongoose": "^6.2.4",
    "sequelize": "^6.17.0"
}
连接数据库
const MongoClient = require('mongodb').MongoClient

;
(async function() {
    const client = new MongoClient('mongodb://127.0.0.1:27017') //本地数据库,没装
    //const client = new MongoClient("mongodb://106.75.16.42:27017");//别人的数据库
    // 链接服务端
    await client.connect()
    console.log('链接成功')

    // 获取数据库 
    const db = client.db('school')
    console.log("db:", db);
    // 获取集合
    const grade1 = db.collection('grade1')
	// 给集合中插入一个文档 
    await grade1.insertOne({
        name: "张三3",
        age: 20,
        hobby: ['吃饭', '睡觉', '打豆豆'],
        score: 90
    })

    // 关闭客户端的链接
    client.close()
})()
插入多条数据
const MongoClient = require('mongodb').MongoClient

;
(async function() {
    const client = new MongoClient('mongodb://127.0.0.1:27017')
    // 链接服务端
    await client.connect()
    console.log('链接成功')

    // 获取数据库 
    const db = client.db('school')
    // 获取集合
    const grade1 = db.collection('grade1')

    let r = await grade1.insertMany([{
            name: '张三',
            age: 20,
            hobby: ['吃饭', '睡觉', '打豆豆'],
            score: 90
        },
        {
            name: '李四',
            age: 40,
            hobby: ['妹子', '篮球'],
            score: 93
        },
        {
            name: '王五',
            age: 20,
            hobby: ['妹子', '睡觉'],
            score: 70
        },
        {
            name: '赵六',
            age: 16,
            hobby: ['妹子'],
            score: 50
        },
        {
            name: '张丽',
            age: 38,
            hobby: ['妹子'],
            score: 56
        },
        {
            name: '小红',
            age: 40,
            hobby: ['妹子'],
            score: 87
        },
        {
            name: '小马',
            age: 20,
            hobby: ['妹子'],
            score: 79
        },
        {
            name: '小王',
            age: 59,
            hobby: ['妹子'],
            score: 102
        },
        {
            name: '小黑',
            age: 16,
            hobby: ['妹子'],
            score: 60
        },
        {
            name: '小哥',
            age: 18,
            hobby: ['篮球'],
            score: 49
        },
    ])

    // 关闭客户端的链接
    client.close()
})()
查找某一条数据
const MongoClient = require('mongodb').MongoClient

;
(async function() {
    const client = new MongoClient('mongodb://127.0.0.1:27017')
    // 链接服务端
    await client.connect()
    console.log('链接成功')

    // 获取数据库 
    const db = client.db('school')
    // 获取集合
    const grade1 = db.collection('grade1')
	// fondOne 需要指定一个条件
    r = await grade1.findOne({
        name: '张三'
    })
    console.log("r:", r);

    // 关闭客户端的链接
    client.close()
})()
查找多条数据
const MongoClient = require('mongodb').MongoClient

;
(async function() {
    const client = new MongoClient('mongodb://127.0.0.1:27017')
    // 链接服务端
    await client.connect()
    console.log('链接成功')

    // 获取数据库 
    const db = client.db('school')
    // 获取集合
    const grade1 = db.collection('grade1')

    // 查找所有的数据
    // r = await grade1.find().toArray()
    // console.log("r:", r);
    // find 找集合中所有的文档  .toArray()找到后,数据转成数组
    r = await grade1.find({
        name: '张三'
    }).toArray()
    console.log("r:", r);

    // 关闭客户端的链接
    client.close()
})()
比较运算符
const MongoClient = require('mongodb').MongoClient

;
(async function() {
    const client = new MongoClient('mongodb://127.0.0.1:27017')
    // 链接服务端
    await client.connect()
    console.log('链接成功')

    // 获取数据库 
    const db = client.db('school')
    // 获取集合
    const grade1 = db.collection('grade1')

    // 比较运算符
    r = await grade1.find({
        age: {
            // gt大于 lt小于  gte 大于等于  lte小于等于
            $gte: 20,
        },
    }).toArray()
    console.log("r:", r);

    // 关闭客户端的链接
    client.close()
})()
逻辑运算符
const MongoClient = require('mongodb').MongoClient

;
(async function() {
    const client = new MongoClient('mongodb://127.0.0.1:27017')
    // 链接服务端
    await client.connect()
    console.log('链接成功')

    // 获取数据库 
    const db = client.db('school')
    // 获取集合
    const grade1 = db.collection('grade1')

    // 逻辑运算符  $and  $or $ne  $nor 不等于
    // 查询姓名叫王五并且年龄为20岁的人
    // r = await grade1.find({
    //     name: '王五',
    //     age: 20,
    // }).toArray()
    // console.log("r:", r);

    // -----------------------------

    // 查询姓名叫张三或者年龄为20岁的人
    // r = await grade1.find({
    //     $or: [
    //         {
    //             name: '张三',
    //         },
    //         {
    //             age: 20,
    //         },
    //     ],
    // }).toArray()
    // console.log("r:", r);

    // -----------------------------

    // // 查询年龄不大于20岁并且age不小于16的人员
    // gt 大于    lt 小于    gte 大于等于     lte  不于等于
    r = await grade1.find({
        $nor: [{
                age: {
                    $gt: 20,
                },
            },
            {
                age: {
                    $lt: 16,
                },
            },
        ],
    }).toArray()

    console.log("r:", r);

    // 关闭客户端的链接
    client.close()
})()
指定正则
const MongoClient = require('mongodb').MongoClient

;
(async function() {
    const client = new MongoClient('mongodb://127.0.0.1:27017')
    // 链接服务端
    await client.connect()
    console.log('链接成功')

    // 获取数据库 
    const db = client.db('school')
    // 获取集合
    const grade1 = db.collection('grade1')

    // 正则表达式
    r = await grade1.find({
        name: {
            $regex: /^张/,
        },
    }).toArray()

    console.log("r:", r);

    // 关闭客户端的链接
    client.close()
})()
$all $in $size
const MongoClient = require('mongodb').MongoClient

;
(async function() {
    const client = new MongoClient('mongodb://127.0.0.1:27017')
    // 链接服务端
    await client.connect()
    console.log('链接成功')

    // 获取数据库 
    const db = client.db('school')
    // 获取集合
    const grade1 = db.collection('grade1')

    // $all $in $size

    // 查找指定字段包含所有指定内容的数据
    // r = await grade1.find({
    //     hobby: {
    //         $all: ['妹子'],
    //     },
    // }).toArray()
    // console.log("r:", r);

    // ----------------------------------

    // 查找指定字段只有指定内容其一的数据
    // r = await grade1.find({
    //     hobby: {
    //         $in: ['妹子', '睡觉'],
    //     },
    // }).toArray()

    // console.log("r:", r);

    // ----------------------------------

    // 查找指定字段的数据有三条的
    r = await grade1.find({
        hobby: {
            $size: 3,
        },
    }).toArray()
    console.log("r:", r);

    // 关闭客户端的链接
    client.close()
})()
分页
const MongoClient = require('mongodb').MongoClient

;
(async function() {
    const client = new MongoClient('mongodb://127.0.0.1:27017')
    // 链接服务端
    await client.connect()
    console.log('链接成功')

    // 获取数据库 
    const db = client.db('school')
    // 获取集合
    const grade1 = db.collection('grade1')

    // 分页查询  limit()
    // 查询前两条数据
    // r = await grade1.find().limit(2).toArray()
    // console.log("r:", r);

    // --------------------------------

    // skip(2)跳过前2条数据,limit(4)获取后4条数据
    // r = await grade1.find().skip(2).limit(4).toArray()
    // console.log("r:", r);

    // --------------------------------

    // 根据age字段进行排序 1表示正序  -1 表示倒序
    // r = await grade1.find().sort({
    //     age: -1,
    // }).toArray()
    // console.log("r:", r);

    // --------------------------------

    // 分页
    const pageIndex = 1 //当前的索引
    const pageSize = 3 //当前一页显示的数据
    r = await grade1
        .find()
        .skip((pageIndex - 1) * pageSize)
        .limit(pageSize)
        .toArray()
    console.log("r:", r);

    // 关闭客户端的链接
    client.close()
})()
聚合函数
const MongoClient = require('mongodb').MongoClient

;
(async function() {
    const client = new MongoClient('mongodb://127.0.0.1:27017')
    // 链接服务端
    await client.connect()
    console.log('链接成功')

    // 获取数据库 
    const db = client.db('school')
    // 获取集合
    const grade1 = db.collection('grade1')

    // 聚合函数 $sum $min $max $avg

    // 相同年龄的人数
    // r = await grade1.aggregate([
    //     {
    //         $group: {
    //             _id: '$age',
    //             count: {
    //                 $sum: 1,
    //             },
    //         },
    //     },
    // ]).toArray()
    // console.log("r:", r);

    // --------------------------------

    // r = await grade1.aggregate([
    //     {
    //         $group: {
    //             _id: '$age',
    //             avgScore: {
    //                 $avg: '$score',
    //             },
    //         },
    //     },
    // ]).toArray()
    // console.log("r:", r);

    // --------------------------------

    r = await grade1.aggregate([{
        $group: {
            _id: '$age',
            avgScore: {
                $max: '$score',
            },
        },
    }, ]).toArray()

    console.log("r:", r);

    // 关闭客户端的链接
    client.close()
})()
更新文档
const MongoClient = require('mongodb').MongoClient

;
(async function() {
    const client = new MongoClient('mongodb://127.0.0.1:27017')
    // 链接服务端
    await client.connect()
    console.log('链接成功')

    // 获取数据库 
    const db = client.db('school')
    // 获取集合
    const grade1 = db.collection('grade1')

    r = await grade1.updateOne({
        name: "张三",
    }, {
        $set: {
            name: "小张三"
        }
    })
    console.log('更新成功', r)

    // 关闭客户端的链接
    client.close()
})()
删除文档
const MongoClient = require('mongodb').MongoClient

;
(async function() {
    const client = new MongoClient('mongodb://127.0.0.1:27017')
    // 链接服务端
    await client.connect()
    console.log('链接成功')

    // 获取数据库 
    const db = client.db('school')
    // 获取集合
    const grade1 = db.collection('grade1')

    // 当你做删除的时候 一定要问一下自己 是否要删除
    r = await grade1.deleteOne({
        name: '张三'
    })
    console.log(r.result);

    // 关闭客户端的链接
    client.close()
})()

班级学生管理

对应的依赖:

"dependencies": {
    "@koa/router": "^10.1.1",
    "express": "^4.17.3",
    "koa": "^2.13.4",
    "koa-bodyparser": "^4.3.0",
    "koa-static": "^5.0.0",
    "mongodb": "^4.4.0",
    "mongoose": "^6.2.4",
    "sequelize": "^6.17.0"
}

如下内容直接copy使用:
请添加图片描述

// dbConfig.js
module.exports = {
    url: 'mongodb://127.0.0.1:27017',
    dbName: 'classes',
}
// testData.js
const mongodb = require('./index.js');
mongodb.once('connect', async () => {
    const students = mongodb.col('students');
    try {
        // 插入测试数据
        await students.deleteMany();
        await students.insertMany([{
                "name": '张三',
                "age": 20,
                "score": 90,
                "class": 1
            },
            {
                "name": '李四',
                "age": 24,
                "score": 90,
                "class": 4
            },
            {
                "name": '王五',
                "age": 28,
                "score": 95,
                "class": 2
            },
            {
                "name": '张三',
                "age": 20,
                "score": 93,
                "class": 1
            },
            {
                "name": '张三2',
                "age": 40,
                "score": 40,
                "class": 1
            },
            {
                "name": '张三3',
                "age": 20,
                "score": 90,
                "class": 1
            },
            {
                "name": '张三4',
                "age": 20,
                "score": 90,
                "class": 1
            },
            {
                "name": '张三6',
                "age": 20,
                "score": 90,
                "class": 1
            },
            {
                "name": '张三7',
                "age": 20,
                "score": 90,
                "class": 1
            },
            {
                "name": '张三',
                "age": 20,
                "score": 90,
                "class": 1
            }
        ])
        console.log('测试数据插入成功');

    } catch (error) {
        console.log(error.stack);

    }
})
// index.js
const dbConfig = require('./dbConfig')
const MongoClient = require('mongodb').MongoClient
const EventEmitter = require('events')
class Mongo {
    constructor(dbConfig) {
        this.dbConfig = dbConfig
        this.emitter = new EventEmitter()
        // 创建客户端
        this.client = new MongoClient(this.dbConfig.url)
        // 建立连接
        this.client.connect((err) => {
            if (err) throw err
            console.log('连接数据库成功')
            this.emitter.emit('connect')
        })
    }
    once(eventName, cb) {
        //   只会连接一次
        this.emitter.once(eventName, cb)
    }
    //   获取集合的方法
    col(colName, dbName = this.dbConfig.dbName) {
        return this.client.db(dbName).collection(colName)
    }
}
module.exports = new Mongo(dbConfig)
// 班级学生管理.js

const Koa = require("koa");
const bodyParser = require('koa-bodyparser')
const Router = require("@koa/router")
const static = require('koa-static');
const mongod = require("./db/index.js")
const ObjectId = require("mongodb").ObjectId;

const app = new Koa();
const router = new Router();

app.use(bodyParser());

// 托管静态资源(静态网页)
app.use(static(__dirname + '/public'))

router.get("/", ctx => {
    ctx.body = "首页面"
})

// 获取所有的学生
router.get("/api/classList", async ctx => {
    let {
        pageSize,
        pageIndex
    } = ctx.query;
    pageSize = Number(pageSize)
    pageIndex = Number(pageIndex)

    console.log("pageSize:", pageSize);
    console.log("pageIndex:", pageIndex);

    // 得到students集合
    let students = mongod.col("students");

    // 得到所有的学生
    let classList = await students.find().skip((pageIndex - 1) * pageSize).limit(pageSize).toArray();
    console.log("classList:", classList);
    let total = await students.countDocuments();

    ctx.body = {
        ok: 1,
        data: classList,
        total
    }
})

// 删除某个学生
router.post("/api/deleteUser", async ctx => {
    let _id = ctx.request.body._id;
    // console.log("_id:", _id);
    let students = mongod.col("students");
    let res = await students.deleteOne({
        _id: ObjectId(_id)
    })
    console.log("res:", res);
    if (res.deletedCount === 1) {
        ctx.body = {
            ok: 1,
            msg: "删除成功"
        }
    }
})

app.use(router.routes())
router.allowedMethods();

app.listen(3000, () => {
    console.log("server is running on 3000");
})

浏览器中测试如下:
请添加图片描述

Mongoose

对于原生node操作mongodb的使用,直接百度,用的时候,直接查,不需要记:但是一般情况下,我们写项目时,会直接使用mongoose

mongoose使用

什么是Mongoose?
Mongoose和MongoDB映射关系
  • 在Mongoose中JS中的一个模型就对应数据库中的一个集合
  • 在Mongoose中JS中的一个对象就对应集合中的一个文档
  • 在Mongoose中JS中的一个对象的属性就对应文档的一个字段

对应核心代码如下:

// 1. 定义集合规则
cosnt 规则名称 = new Schema({

    name: String,
    age: Number

});

// 2. 利用规则创建一个集合
let User = mongoose.model('User', userSchema);

// 3. 创建一个文档
let u = new User({

    name: 'zs',
    age: 18

});

// 4. 操作集合和文档
// 只要是通过Mongoose定义的模型, 那么Mongoose就会自动给这个模型添加很多操作集合和文档的方法以后我们就可以直接通过模型操作集合, 通过模型创建出来的对象操作数据

实现代码如下:

// 1.导入mongoose
const mongoose = require('mongoose');

/*
mongodb://MongoDB服务器IP地址:MongoDB服务器端口号/需要打开的数据库名称
* */
// 2.利用mongoose链接MongoDB服务器
mongoose.connect('mongodb://127.0.0.1:27017/demo');

// 3.监听链接成功还是失败
let db = mongoose.connection;
db.on('error', (err) => {
    console.log(err, '连接失败');
});
db.once('open', function() {
    console.log('连接成功');
});
db.once('close', function() {
    console.log('断开连接');
});
// eat是一个自定义事件
// 需要写代码去触发自定义事件
// emit("eat","123")  发布
// db.on("eat",(data)=>{lg("xxx")})  订阅

// 1.定义集合中存储数据规则
let userSchema = new mongoose.Schema({
    name: String,
    age: Number
});
// 需要根据Schema创建model
// model 模型
// MVC   Model数据模型,主要是给数据库打交道   View视图,前端写的页面   Controller控制器
// User 说白了,就是对应数据库中的集合
// 数据中,可以有N个集合,一个集合中可以有N个文档   

// 2.利用规则创建集合
// 注意点: 只要创建好了模型, 那么以后就可以使用模型来操作这个集合
// 注意点: mongoose会自动将我们指定的集合名称变成复数
let User = mongoose.model('User', userSchema);

// 3.利用集合创建文档
// 注意点: 只要创建好了对象, 那么以后就可以使用对象来操作文档
let u = new User({
    name: 'zs',
    age: 18
});

// 4.操作文档
u.save((err, product) => {
    if (!err) {
        console.log('文档保存成功');
        console.log(product);
    }
});

CRUD操作

// 1.导入mongoose
const mongoose = require('mongoose');

// 2.利用mongoose链接MongoDB服务器
mongoose.connect('mongodb://127.0.0.1:27017/blog');

// 3.监听链接成功还是失败
let db = mongoose.connection;
db.on('error', (err) => {
    console.log(err, '连接失败');
});
db.once('open', function() {
    console.log('连接成功');
});
db.once('close', function() {
    console.log('断开连接');
});

// 1.定义集合中存储数据规则
let userSchema = new mongoose.Schema({
    name: String,
    age: Number
});

// 2.利用规则创建集合
let User = mongoose.model('User', userSchema);

// 增加
/*
User.create({name:'zs', age:666}, (err, result)=>{
    if(!err){
        console.log('插入成功');
        console.log(result);
    }
});
*/
/*
User.create([
        {name:'ls', age:18},
        {name:'ls', age:22},
        {name:'ww', age:21},
        {name:'zl', age:23},
        {name:'xq', age:33},
    ],
    (err, result)=>{
    if(!err){
        console.log('插入成功');
        console.log(result);
    }
});
 */
/*
(async ()=>{
    let result = await User.create([
            {name:'ls', age:18},
            {name:'ls', age:22},
            {name:'ww', age:21},
            {name:'zl', age:23},
            {name:'xq', age:33},
        ]);
    console.log(result);
})();
 */

// 查询
/*
User.find({},{},(err, docs)=>{
    if(!err){
        console.log(docs);
    }
});
 */
/*
User.find({},{_id:0, name:1, age:1},(err, docs)=>{
    if(!err){
        console.log(docs);
    }
});
 */
/*
User.find({name:'ls'},{_id:0, name:1, age:1},(err, docs)=>{
    if(!err){
        console.log(docs);
    }
});
 */
/*
User.find({},{_id:0, name:1, age:1},{ skip: 5, limit: 5},(err, docs)=>{
    if(!err){
        console.log(docs);
    }
});
 */
/*
(async ()=>{
    let result = await User.find({},{_id:0, name:1, age:1},{ skip: 5, limit: 5});
    console.log(result);
})();
*/

// 修改
/*
User.update({name:'ls'},{$set:{age:888}},(err, docs)=>{
    if(!err){
        console.log('更新成功');
        console.log(docs);
    }
});
 */
/*
User.update({name:'ls'},{$set:{age:888}}, {multi: true},(err, docs)=>{
    if(!err){
        console.log('更新成功');
        console.log(docs);
    }
});
 */
/*
(async ()=>{
   let result = await User.update({name:'ls'},{$set:{age:123}}, {multi: true});
   console.log(result);
})();
 */

// 删除
/*
User.remove({name:'ww'}, {}, (err, docs)=>{
    if(!err){
        console.log('删除成功');
        console.log(docs);
    }
});
 */
/*
User.deleteOne({name:'xq'}, (err, docs)=>{
    if(!err){
        console.log('删除成功');
        console.log(docs);
    }
});
 */
(async () => {
    let result = await User.deleteOne({
        name: 'xq'
    });
    console.log(result);
})();

博客后台接口

博客《管理员模块》

项目介绍

基于Vue+Node.js koa2+mongoose实战开发的⼀套完整的博客项目网站,使用koa2二次开发⼀套适合多端的Restful API, 同时配合完整的后台管理系统。

功能列表
  • 管理员与权限控制接口
  • 分类接口
  • ⽂章管理接口
  • 评论/回复功能接口
  • ⼴告接口
技术栈
  • Node.js
  • koa2
  • mongodb
  • mongoose
依赖说明
  • bcrypt 对数据进⾏加盐
    • 下载 bcrypt 包时,请先全局下载 node-gyp 包,npm i node-gyp -g
  • jsonwebtoken JSON WEB令牌实现
  • koa-jwt Koa JWT身份验证中间件
  • koa-bouncer Koa路由的参数验证库
  • basic-auth Nodejs基本身份验证解析器
  • mongoose MongoDB DOM框架
  • redis ⾼性能Redis客户端。
  • moment 解析,验证,操作和显示⽇期时间库

模型(model)创建

根据在上面的介绍,我们本项目中的接口需要有如下:

  • 管理员与权限控制接口
  • 分类接口
  • ⽂章管理接口
  • 评论/回复功能接口
  • ⼴告接口

根据接⼝,我们可以反映射模型

  • 管理员模型
  • 分类模型
  • ⽂章模型
  • 评论模型
  • 回复模型
  • ⼴告模型

整体项目目录结果如下:
请添加图片描述
请添加图片描述

管理员注册开发

  1. router⽂件夹下新建admin.js,代码如下:
// router/admin.js

const Router = require("@koa/router");

const router = new Router();

router.prefix("/admin")

// 注册管理员
router.post("/register", (ctx, next) => {
    ctx.body = "册管理员"
})

module.exports = router;
  1. app.js 注册路由
// app.js  
// 注意:代码的书写位置

// ...
const admin = require("./router/admin.js")

// ...

// 注册管理员模块路由
app.use(admin.routes())
admin.allowedMethods();

// ...
  1. postman测试如下:
    请添加图片描述
    路由模块接收到请求后,交由controller模块处理,这一层,叫业务逻辑层
    在controller文件夹下,创建AdminController.js,代码如下:
// controller/AdminController.js

const { registerValidator, loginValidator } = require("../validators/admin.js");
const AdminModel = require("../models/AdminModel")
const LoginManager = require("../services/login")
const res = require("../core/helper.js")

class AdminController {
    // 注册
    static async register(ctx, next) {
        console.log("我是控制器中的register方法,此方法是用来实现注册");

        // 第一件事:先进行数据校验,通过后,再向下走
        registerValidator(ctx)

        // 第二件事:获取用户名和密码
        let { nickname, password2 } = ctx.request.body;
        // console.log(nickname, password2);

        // 第三件事:判断数据库中否有同名的用户名
        let currentUser = await AdminModel.findOne({
            nickname
        });
        // console.log("currentUser:", currentUser);
        if (currentUser) {
            throw new global.errs.Existing("用户已存在", 900)
        }

        // 第四件事:需要把用户入库
        let user = await AdminModel.create({
            nickname, password: password2
        });
        // 之前的写法
        // ctx.body = {
        //     code: 200,
        //     msg: "success",
        //     data: user,
        //     errorCode: 0
        // }
        // 现在的写法
        ctx.body = res.json(user)
    }

    // 登录
    static async login(ctx, next) {
        // 校验
        loginValidator(ctx)

        // 得到前端传递的用户名和密码
        let { nickname, password } = ctx.request.body;
        // console.log(nickname, password);

        let user = await LoginManager.adminLogin({ nickname, password })
        // console.log("user", user);

        ctx.body = res.json(user)
    }

    // 获取用户信息
    static async getUserInfo(ctx, next) {
        let _id = ctx.state.user.data;
        let userInfo = await AdminModel.findById({ _id });
        if (!userInfo) {
            throw new global.errs.AuthFailed("用户不存在")
        }
        ctx.body = res.json({ _id, nickname: userInfo.nickname })
    }
}

// 导出去一个类
module.exports = AdminController;

// 由注册管理员的逻辑看,我们从前台传来的 nickname、password1、password2 字段需要在后端进⾏校验。

在路由模块中,使用上面定义好的controller,如下:

// router/admin.js
const Router = require("@koa/router");
const jwtAuth = require("koa-jwt")
const AdminController = require("../controller/AdminController")
const config = require("../config/index.js")

const router = new Router();

router.prefix("/admin")

// router.post("/register", (ctx, next) => {
//     // 按理说,我们需要在这里,得到前端传递过来数据
//     // 连接数据库,插入数据到数据库
//     // ....
//     ctx.body = "注册管理员"
// })

// 注册
router.post("/register", AdminController.register)

// 登录 
router.post("/login", AdminController.login)

// 获取用户
router.get("/user/info", jwtAuth({ secret: config.security.secretKey }), AdminController.getUserInfo)

module.exports = router;

在postman中测试如下:

请添加图片描述

请添加图片描述
到此,用户注册,就实现了。但是上面响应数据,响应的代码如下:

ctx.body = {
    code: 200,
    msg: "success",
    data: user,
    errorCode: 0,
};

那就意味着,后面我们每次响应数据,都要按如上的方式响应,可能比较麻烦,我们可以封装一个返回结果的模块,这个模块已经封装好了,就是core下面的helper.js模块,大家直接使用就OK。修改代码如下:

// controller/AdminController.js

const AdminModel = require("../models/AdminModel");
const {
    registerValidator
} = require("../validators/admin");
const res = require("../core/helper");
class AdminController {
    // 注册
    static async register(ctx, next) {
        // 参数校验
        registerValidator(ctx);
        // 处理业务
        const {
            nickname,
            password2
        } = ctx.request.body;
        const currentUser = await AdminModel.findOne({
            nickname
        });
        if (currentUser) {
            throw new global.errs.Existing("用户已存在", 900);
        }
        const user = await AdminModel.create({
            nickname,
            password: password2,
        });
        // ctx.body = {
        //   code: 200,
        //   msg: "success",
        //   data: user,
        //   errorCode: 0,
        // };
        ctx.body = res.json(user);
    }
}
module.exports = AdminController;

管理员登录开发

在router下面的admin.js配置对应的路由,如下:

// router/admin.js

// 管理员登录
router.post('/login', AdminController.login)

在AdminController模块中,准备开发对应的业务逻辑,如下:

// controller/AdminController.js

const AdminModel = require("../models/AdminModel");
const {
    registerValidator,
    loginValidator
} = require("../validators/admin");
const res = require("../core/helper");
class AdminController {
    // 注册
    // ... 

    // 登录
    static async login(ctx, next) {
        loginValidator(ctx);
        const {
            nickname,
            password
        } = ctx.request.body;
        console.log(nickname, password);
    }
}
module.exports = AdminController;

在控制台中,可以得到用户名和密码。由于控制器中得到用户名和密码后,剩下的业务逻辑处理,可能会复杂一点,所以,我们可以理抽取一层,在项目根目录下,创建services文件夹,在这里创建login.js,用来操作管理员登录的业务,目录结构如下:
请添加图片描述对应的代码如下:

// services/login.js

const AdminModel = require("../models/AdminModel")
const bcrypt = require("bcrypt")
const { generateToken } = require("../core/util.js")

class LoginManager {
    static async adminLogin({ nickname, password }) {

        // 查找数据库中是否有此用户名和密码
        const user = await AdminModel.findOne({ nickname });
        if (!user) {
            throw new global.errs.AuthFailed("用户名不存在")
        }

        // 验证两次密码是否一致
        const correct = bcrypt.compareSync(password, user.password);
        if (!correct) {
            throw new global.errs.AuthFailed("密码不正确")
        }
        // 用户名和密码是正确的
        // 颁发令牌  生成token
        // 说明用户名存在,密码正确
        // 不要放敏感令牌
        let token = generateToken(user._id);

        return {
            nickname: user.nickname,
            token
        }
    }
}

module.exports = LoginManager;

在controler层使用services层中的login.js,代码如下:

// controller/AdminController.js

const AdminModel = require("../models/AdminModel");
const {
    registerValidator,
    loginValidator
} = require("../validators/admin");
const res = require("../core/helper");
const LoginManager = require("../services/login");
class AdminController {
    // 注册
    static async register(ctx, next) {
        // 参数校验
        registerValidator(ctx);
        // 处理业务
        const {
            nickname,
            password2
        } = ctx.request.body;
        const currentUser = await AdminModel.findOne({
            nickname
        });
        if (currentUser) {
            throw new global.errs.Existing("用户已存在", 900);
        }
        const user = await AdminModel.create({
            nickname,
            password: password2,
        });
        // ctx.body = {
        //   code: 200,
        //   msg: "success",
        //   data: user,
        //   errorCode: 0,
        // };
        ctx.body = res.json(user);
    }
    // 登录
    static async login(ctx, next) {
        loginValidator(ctx);
        const {
            nickname,
            password
        } = ctx.request.body;
        const user = await LoginManager.adminLogin({
            nickname,
            password
        });
        if (!user) {
            throw new global.errs.NotFound("用户不存在");
        }
        ctx.body = res.json(user, "登录成功");
    }
}
module.exports = AdminController;

postman测试如下:
请添加图片描述
请添加图片描述

获取⽤户信息

在router目录下的admin.js文件夹下,创建获取用户信息路由,如下:

// router/admin.js

const AdminController = require("../controller/AdminController")
// 获取用户信息
const config = require("../config/index.js");

// ...

router.get(
    "/user/info",
    jwtAuth({
        secret: config.security.secretKey
    }),
    AdminController.getUserInfo
);

在AdminController中,创建getUserInfo方法,如下:

// controller/AdminController.js

const AdminModel = require("../models/AdminModel");
const {
    registerValidator,
    loginValidator
} = require("../validators/admin");
const res = require("../core/helper");
const LoginManager = require("../services/login");
class AdminController {
    // 注册
    static async register(ctx, next) {
        // 参数校验
        registerValidator(ctx);
        // 处理业务
        const {
            nickname,
            password2
        } = ctx.request.body;
        const currentUser = await AdminModel.findOne({
            nickname
        });
        if (currentUser) {
            throw new global.errs.Existing("用户已存在", 900);
        }
        const user = await AdminModel.create({
            nickname,
            password: password2,
        });
        // ctx.body = {
        //   code: 200,
        //   msg: "success",
        //   data: user,
        //   errorCode: 0,
        // };
        ctx.body = res.json(user);
    }
    // 登录
    static async login(ctx, next) {
        loginValidator(ctx);
        const {
            nickname,
            password
        } = ctx.request.body;
        const user = await LoginManager.adminLogin({
            nickname,
            password
        });
        if (!user) {
            throw new global.errs.NotFound("用户不存在");
        }
        ctx.body = res.json(user, "登录成功");
    }
    // 获取用户登录信息  token
    static async getUserInfo(ctx, next) {
        const _id = ctx.state.user.data;
        // 查询用户信息
        const userInfo = await AdminModel.findById({
            _id
        });
        if (!userInfo) throw new global.errs.AuthFailed("认证失败,请检查请求头");
        ctx.body = res.json({
            _id,
            nickname: userInfo.nickname
        });
    }
}
module.exports = AdminController;

在postman中测试,如下:
请添加图片描述

博客《分类模块》

创建分类

新建router/category.js,代码如下:

// router/category.js

const Router = require("@koa/router");
const jwtAuth = require("koa-jwt")
const CategoryController = require("../controller/CategoryController")
const config = require("../config/index.js")

const router = new Router();


// 创建分类
router.post("/category", jwtAuth({ secret: config.security.secretKey }), CategoryController.create)

// 获取所有分类  jwtAuth({ secret: config.security.secretKey }),
router.get("/category", CategoryController.getCategoryList)

// 根据ID获取某个分类  jwtAuth({ secret: config.security.secretKey }), 
router.get("/category/:_id", CategoryController.getCategoryDetailById)

// 更新分类  jwtAuth({ secret: config.security.secretKey }),
router.put("/category/:_id", CategoryController.updateCategoryById)

// 删除分类  jwtAuth({ secret: config.security.secretKey }),
router.delete("/category/:_id", CategoryController.deleteCategoryById)

module.exports = router;

在app.js中,注册对应的路由,如下:

// app.js
const Koa = require("koa");
const app = new Koa();

// 美化json
const json = require("koa-json");
// 接收post参数
const bodyparser = require("koa-bodyparser");
// 控制台美化日志
const logger = require("koa-logger");
// 前端表单校验
const bouncer = require("koa-bouncer");
// 托管静态资源
const static = require("koa-static")
// 解决跨域
const cors = require('koa2-cors');

// 引用项目的配置文件
const config = require("./config");
// 导入连接数据库文件
const db = require("./db");
// 检查出对应的参数错误、404错误、权限错误、xxx已存在的错误可以这样使用
// 如:throw new global.errs.Existing('管理员已存在')
// errors是一个对象,这个对象中包含了6个类,其中有一个是Existing类
const errors = require("./core/http-exception");
// 当出现任何的错误时,我们需要错误处理中间件来处理  exception是错误处理中间件
const catchError = require("./middlewares/exception");

// 路由的引入
const user = require("./router/user.js")
const admin = require("./router/admin.js")
const category = require("./router/category.js")
const article = require("./router/article.js")
const comment = require("./router/comment.js")
const reply = require("./router/reply.js")
const advertise = require("./router/advertise.js")

// 把errors挂载到GO的errs这个属性上
// GO的属性上有一个errs属性,值是一个对象,对象中有6个类
global.errs = errors;
// 把config挂载到GO,用的时候,直接global.config,到时候就不用导入
global.config = config;
// node app.js PORT=5000
// node app.js 没有传参  process.env.PORT是und  整体的值是config.port
// config.port就是3000
const port = process.env.PORT || config.port;

// 错误处理中间件
app.use(catchError);

// 使用中间件
app
  .use(bodyparser())
  .use(bouncer.middleware())
  .use(json())
  .use(logger())
  .use(cors())
  .use(static(__dirname + '/public'))

// 日志打印中间件
app.use(async (ctx, next) => {
  const start = new Date();
  await next();
  const ms = new Date() - start;
  console.log(`${ctx.method} ${ctx.url} - $ms`);
});

// 路由注册
app.use(user.routes())
user.allowedMethods();

// 注册管理员模块的路由
app.use(admin.routes())
admin.allowedMethods();

// 注册分类模块的路由
app.use(category.routes())
category.allowedMethods();

// 注册文章模块的路由
app.use(article.routes())
article.allowedMethods();

// 注册评论模块的路由
app.use(comment.routes())
comment.allowedMethods();

// 注册回复模块的路由
app.use(reply.routes())
reply.allowedMethods();

// 注册广告模块路由
app.use(advertise.routes());
advertise.allowedMethods();

// 绑定error事件
app.on("error", function (err, ctx) {
  console.log(err)
  // logger.error('server error', err, ctx)
});

module.exports = app.listen(config.port, () => {
  console.log(`Server is running on ${config.port}`);
});

创建对应的控制器,如下:

// controller/CategoryController.js
const AdvertiseModel = require("../models/AdvertiseModel");
const {
    advertiseValidator
} = require("../validators/advertise");
const res = require("../core/helper");
class ReplyController {
    // 创建广告
    static async createAdvertise(ctx, next) {
        advertiseValidator(ctx);
        const {
            title
        } = ctx.request.body;
        let hasAdvertise = await AdvertiseModel.findOne({
            title
        });
        if (hasAdvertise) {
            throw new global.errs.Existing("广告已存在");
        }
        let advertise = await AdvertiseModel.create(ctx.request.body);
        ctx.body = res.json(advertise);
    }

    // 获取广告列表
    static async getAdvertiseList(ctx, next) {
        let advertiseList = await AdvertiseModel.find();
        ctx.status = 200;
        ctx.body = res.json(advertiseList);
    }

    // 获取广告详情
    static async getAdvertiseDetailById(ctx, next) {
        const _id = ctx.params._id;
        const advertiseDetail = await AdvertiseModel.findById({
            _id
        });
        if (!advertiseDetail) {
            throw new global.errs.NotFound("此广告不存在");
        }
        ctx.status = 200;
        ctx.body = res.json(advertiseDetail);
    }

    // 更新广告
    static async updateAdvertiseById(ctx, next) {
        const _id = ctx.params._id;
        const advertiseDetail = await AdvertiseModel.findByIdAndUpdate({
            _id
        },
            ctx.request.body
        );
        if (!advertiseDetail) {
            throw new global.errs.NotFound("此广告不存在");
        }
        ctx.status = 200;
        ctx.body = res.success("更新广告成功");
    }

    // 删除广告
    static async deleteAdvertiseById(ctx, next) {
        const _id = ctx.params._id;
        const advertiseDetail = await AdvertiseModel.findByIdAndDelete({
            _id
        });
        if (!advertiseDetail) {
            throw new global.errs.NotFound("此广告不存在");
        }
        ctx.status = 200;
        ctx.body = res.success("删除广告成功");
    }
}
module.exports = ReplyController;

博客《文章模块》

创建文章

新建router/article.js,代码如下:

// router/article.js

const Router = require("@koa/router");
const jwtAuth = require("koa-jwt")
const ArticleController = require("../controller/ArticleController")
const config = require("../config/index.js")
const upload = require("../middlewares/upload")

const router = new Router();

// 创建文章  jwtAuth({ secret: config.security.secretKey }),
router.post("/article", ArticleController.create)


// 获取文章 jwtAuth({ secret: config.security.secretKey }),
router.get("/article", ArticleController.getArticleList)


// 更新文章 jwtAuth({ secret: config.security.secretKey }),
router.put("/article/:_id", ArticleController.updateArticleById)

// 根据文章ID得到文章的详情 jwtAuth({ secret: config.security.secretKey }),
router.get("/article/:_id", ArticleController.getArticleDetailById)

// 根据文章ID删除文章 jwtAuth({ secret: config.security.secretKey }),
router.delete("/article/:_id", ArticleController.deleteArticleById)

// 文章封面上传 jwtAuth({ secret: config.security.secretKey }),
// upload.single("avatar"), 此中间件已经实现上传了,
// ArticleController.uploadCoverImg 此中间件只需要给出提示
router.post("/upload", upload.single("avatar"), ArticleController.uploadCoverImg)

module.exports = router;

在app.js中,注册对应的路由,如下:

// app.js

创建对应的控制器,如下:

// controller/ArticleController.js

const { articleValidator } = require("../validators/article");
const ArticleModel = require("../models/ArticleModel")
const CommentController = require("./CommentController");
const res = require("../core/helper.js")
const config = require("../config/index.js")

class ArticleController {
    // 创建文章
    static async create(ctx, next) {
        articleValidator(ctx)

        const { title } = ctx.request.body;

        const hasArticle = await ArticleModel.findOne({ title })
        if (hasArticle) {
            throw new global.errs.Existing("文章标题已存在,换个吧~")
        }

        await ArticleModel.create(ctx.request.body)
        ctx.body = res.success("创建成功")
    }

    // 获取文章列表
    //   1)获取所有文章
    //   2)根据某个分类,获取某个分类下的所有的文章
    //   3)根据关键字,获取含有此关键字的文章
    static async getArticleList(ctx, next) {
        const {
            category_id = null,
            pageIndex = 1,
            pageSize = 10,
            keyword
        } = ctx.query
        let filter = {};
        if (category_id) {
            filter = {
                category_id,
            };
        }
        // 得到数据库中总的文章数
        const totalSize = await ArticleModel.find().countDocuments();

        const articleList = await ArticleModel
            .find(filter)
            .skip(parseInt(pageIndex - 1) * parseInt(pageSize))
            .limit(+pageSize)
            .or([
                //   模糊搜索查询    正则  RegExp是正则类   node   new EegExp("node", "i")
                {
                    // 匹配匹配
                    keyword: {
                        $regex: new RegExp(keyword, "i"),
                    },
                },
            ])
            .sort({ _id: -1 })
            .populate("category_id");  // //连表查询

        ctx.body = res.json({
            content: articleList,
            pageIndex: parseInt(pageIndex),
            pageSize: parseInt(pageSize),
            totalSize,
        });
    }

    // 更新文章
    static async updateArticleById(ctx, next) {
        const _id = ctx.params._id;

        const article = await ArticleModel.findByIdAndUpdate({ _id }, ctx.request.body);

        if (!article) {
            throw new global.errs.NotFound("没有找到相关文章")
        }
        ctx.body = res.json("文章更新成功")
    }

    // 根据ID获取文章详情
    // static async getArticleDetailById(ctx, next) {
    //     const _id = ctx.params._id;
    //     const articleDetail = await ArticleModel.findById({ _id }).populate("category_id");  //连表查询
    //     if (!articleDetail) {
    //         throw new global.errs.NotFound("没有找到相关文章")
    //     }
    //     await ArticleModel.findByIdAndUpdate({ _id }, { browse: ++articleDetail.browse })
    //     // ==============> todo:
    //     //   获取文章下的所有的评论
    //     const commentList = []; // 现在评论内容是空
    //     ctx.body = res.json({
    //         articleDetail,
    //         commentList
    //     })
    // }

    // 根据ID删除文章
    static async deleteArticleById(ctx, next) {
        const _id = ctx.params._id;

        const article = await ArticleModel.findByIdAndDelete({ _id })

        if (!article) {
            throw new global.errs.NotFound("没有找到相关文章")
        }
        ctx.body = res.json("文章删除成功")
    }

    // 上传文章封面
    static async uploadCoverImg(ctx, next) {
        let imgPath = config.host + ":" + config.port + "/" + "images/" + ctx.req.file.filename;
        // ctx.body = res.json(imgPath)
        ctx.body = res.json(ctx.req.file.filename)
    }

    // 根据ID获取文章详情 
    static async getArticleDetailById(ctx, next) {
        const _id = ctx.params._id;
        //   文章详情的内容
        const articleDetail = await ArticleModel.findById({
            _id
        }).populate(
            "category_id"
        );
        if (!articleDetail) throw new global.errs.NotFound("没有找到相关分类");
        // 更新文章浏览器数 browse
        await ArticleModel.findByIdAndUpdate({
            _id
        }, {
            browse: ++articleDetail.browse
        });
        const {
            data,
            pageIndex,
            pageSize,
            totalSize
        } =
            await CommentController.targetComment({
                target_id: articleDetail._id
            });

        ctx.body = res.json({
            articleDetail,
            commentList: data,
            pageIndex,
            pageSize,
            commentCount: totalSize,
            totalSize,
        });
    }
}

// 导出去一个类
module.exports = ArticleController;

博客《评论模块》

添加评论

新建router/comment.js,代码如下:

// router/comment.js

const Router = require("@koa/router");
const jwtAuth = require("koa-jwt")
const CommentController = require("../controller/CommentController")
const config = require("../config/index.js")

const router = new Router();


// 添加评论  jwtAuth({ secret: config.security.secretKey }), 
router.post("/comment", CommentController.createComment)

// 获取所有评论  jwtAuth({ secret: config.security.secretKey }), 
router.get("/comment", CommentController.getCommentList)

// 获取评论详情  jwtAuth({ secret: config.security.secretKey }), 
router.get("/comment/:_id", CommentController.getCommentDetailById)

// 更新评论  jwtAuth({ secret: config.security.secretKey }), 
router.put("/comment/:_id", CommentController.updateCommentById)

// 删除评论  jwtAuth({ secret: config.security.secretKey }), 
router.delete("/comment/:_id", CommentController.deleteCommentById)

// 获取文章目标的评论接口(带回复和分页)
router.get("/comment/target/list", CommentController.getTargetComment);

module.exports = router;

在app.js中,注册对应的路由,如下:

// app.js

创建对应的控制器,如下:

// controller/CommentController.js

const { commentValidator } = require("../validators/comment");
const CommentModel = require("../models/CommentModel")
const ReplyModel = require("../models/ReplyModel")
const res = require("../core/helper.js")

class CommentController {
    // 创建评论
    static async createComment(ctx, next) {
        commentValidator(ctx)

        // const { target_id } = ctx.request.body;

        const data = await CommentModel.create(ctx.request.body);
        ctx.body = res.json(data)
    }

    // 获取评论列表
    static async getCommentList(ctx, next) {
        const { pageIndex = 1, pageSize = 10 } = ctx.query
        const totalSize = await CommentModel.find().countDocuments();
        const commentList = await CommentModel
            .find()
            .skip(parseInt(pageIndex - 1) * parseInt(pageSize))
            .limit(+pageSize)
            .sort({ _id: -1 });

        ctx.body = res.json({
            data: commentList,
            totalSize,
            pageIndex: parseInt(pageIndex),
            pageSize: parseInt(pageSize)
        })
    }

    // 获取评论的详情
    static async getCommentDetailById(ctx, next) {
        const _id = ctx.params._id;

        const commentDetail = await CommentModel.findById({ _id });

        if (!commentDetail) {
            throw new global.errs.NotFound("没有找到相关的评论信息")
        }

        // =============> todo: 获取改评论下面的回复
        const replyList = [];

        ctx.body = res.json({
            commentDetail,
            replyList
        })
    }

    // 更新评论
    static async updateCommentById(ctx, next) {
        const _id = ctx.params._id;

        const comment = await CommentModel.findByIdAndUpdate({ _id }, ctx.request.body);

        if (!comment) {
            throw new global.errs.NotFound("没有找到相关评论")
        }

        ctx.body = res.json("更新评论成功")
    }

    // 删除评论
    static async deleteCommentById(ctx, next) {
        const _id = ctx.params._id;

        // category是删除前的category
        const comment = await CommentModel.findByIdAndDelete({ _id });

        if (!comment) {
            throw new global.errs.NotFound("没有找到相关评论")
        }

        ctx.body = res.json("删除评论成功")
    }

    // 下面两个方法用于一个文章下的所有评论
    static async getTargetComment(ctx, next) {
        const commentList = await CommentController.targetComment(ctx.query);
        ctx.status = 200;
        ctx.body = res.json(commentList);
    }
    static async targetComment(params = {}) {
        // target_id: 文章id
        const {
            target_id,
            pageIndex = 1,
            pageSize = 4
        } = params;
        // 评论总数量
        const totalSize = await CommentModel.find({
            target_id,
        }).countDocuments();
        // 获取所有的评论
        const commentList = await CommentModel.find({
            target_id,
        })
            .skip(parseInt(pageIndex - 1) * parseInt(pageSize))
            .limit(parseInt(pageSize))
            .sort({
                _id: -1,
            })
            .lean();
        //  2.获取评论下回复列表
        // Promise.all()
        let newCommentList = await Promise.all(
            commentList.map(async (comment) => {
                let replyList = await ReplyModel.find({
                    comment_id: comment._id,
                });
                comment.replyList = replyList;
                return comment;
            })
        );

        return {
            data: newCommentList,
            pageIndex: parseInt(pageIndex),
            pageSize: parseInt(pageSize),
            totalSize,
        };
    }
}

// 导出去一个类
module.exports = CommentController;

博客《回复模块》

创建回复

新建router/reply.js,代码如下:

// router/reply.js

const Router = require("@koa/router");
const jwtAuth = require("koa-jwt")
const ReplyController = require("../controller/ReplyController")
const config = require("../config/index.js")

const router = new Router();


// 添加回复  jwtAuth({ secret: config.security.secretKey }), 
router.post("/reply", ReplyController.createReply)

// 获取所有回复  jwtAuth({ secret: config.security.secretKey }), 
router.get("/reply", ReplyController.getReplyList)

// 获取回复详情  jwtAuth({ secret: config.security.secretKey }), 
router.get("/reply/:_id", ReplyController.getReplyDetailById)

// 获取回复详情  jwtAuth({ secret: config.security.secretKey }), 
router.put("/reply/:_id", ReplyController.updateReplyById)

// 获取回复详情  jwtAuth({ secret: config.security.secretKey }), 
router.delete("/reply/:_id", ReplyController.deleteReplyById)


module.exports = router;

在app.js中,注册对应的路由,如下:

// app.js

创建对应的控制器,如下:

// controller/ReplyController.js

const { replyValidator } = require("../validators/reply");
const ReplyModel = require("../models/ReplyModel")
const CommentModel = require("../models/CommentModel")
const res = require("../core/helper.js")

class ReplyController {
    // 创建评论
    static async createReply(ctx, next) {
        replyValidator(ctx)

        const { comment_id } = ctx.request.body;

        let comment = await CommentModel.findById({ _id: comment_id })

        if (!comment) {
            throw new global.errs.NotFound("没有找相关评论")
        }

        let reply = await ReplyModel.create(ctx.request.body)


        ctx.body = res.json(reply)
    }

    // 获取所有回复
    static async getReplyList(ctx, next) {
        const comment_id = ctx.query.comment_id;
        let replyList = null;
        if (comment_id) {
            replyList = await ReplyModel.find({
                comment_id
            })
        } else {
            replyList = await ReplyModel.find().sort({ _id: -1 })
        }

        ctx.body = res.json(replyList)
    }

    // 获取某条回复的详情
    static async getReplyDetailById(ctx, next) {
        const _id = ctx.params._id;
        let replyDetail = await ReplyModel.findById(_id);
        if (!replyDetail) {
            throw new global.errs.NotFound("没有相关的回复")
        }
        ctx.body = res.json(replyDetail)
    }

    // 修改,编辑,更新回复
    static async updateReplyById(ctx, next) {
        const _id = ctx.params._id;
        let reply = await ReplyModel.findByIdAndUpdate(_id, ctx.request.body);
        if (!reply) {
            throw new global.errs.NotFound("没有相关的回复")
        }
        ctx.body = res.success("修改回复成功")
    }

    // 删除评论
    static async deleteReplyById(ctx, next) {
        const _id = ctx.params._id;
        let reply = await ReplyModel.findByIdAndDelete(_id);
        if (!reply) {
            throw new global.errs.NotFound("没有相关的回复")
        }
        ctx.body = res.success("删除回复成功")
    }
}
// 导出去一个类
module.exports = ReplyController;

博客《广告模块》

创建⼴告

新建router/advertise.js,代码如下:

// router/advertise.js

const Router = require("@koa/router");
const AdvertiseController = require("../controller/AdvertiseController.js");
const jwtAuth = require("koa-jwt");
const config = require("../config/index.js");

const router = new Router();

// 创建广告
router.post("/advertise", jwtAuth({
    secret: config.security.secretKey
}), AdvertiseController.createAdvertise);

// 获取广告列表
router.get("/advertise", AdvertiseController.getAdvertiseList);

// 获取广告详情
router.get("/advertise/:_id", AdvertiseController.getAdvertiseDetailById);

// 更新广告
router.put("/advertise/:_id", AdvertiseController.updateAdvertiseById);

// 删除
router.delete("/advertise/:_id", AdvertiseController.deleteAdvertiseById);

module.exports = router;

在app.js中,注册对应的路由,如下:

// app.js

创建对应的控制器,如下:

// controller/AdvertiseController.js

const AdvertiseModel = require("../models/AdvertiseModel");
const {
    advertiseValidator
} = require("../validators/advertise");
const res = require("../core/helper");
class ReplyController {
    // 创建广告
    static async createAdvertise(ctx, next) {
        advertiseValidator(ctx);
        const {
            title
        } = ctx.request.body;
        let hasAdvertise = await AdvertiseModel.findOne({
            title
        });
        if (hasAdvertise) {
            throw new global.errs.Existing("广告已存在");
        }
        let advertise = await AdvertiseModel.create(ctx.request.body);
        ctx.body = res.json(advertise);
    }

    // 获取广告列表
    static async getAdvertiseList(ctx, next) {
        let advertiseList = await AdvertiseModel.find();
        ctx.status = 200;
        ctx.body = res.json(advertiseList);
    }

    // 获取广告详情
    static async getAdvertiseDetailById(ctx, next) {
        const _id = ctx.params._id;
        const advertiseDetail = await AdvertiseModel.findById({
            _id
        });
        if (!advertiseDetail) {
            throw new global.errs.NotFound("此广告不存在");
        }
        ctx.status = 200;
        ctx.body = res.json(advertiseDetail);
    }

    // 更新广告
    static async updateAdvertiseById(ctx, next) {
        const _id = ctx.params._id;
        const advertiseDetail = await AdvertiseModel.findByIdAndUpdate({
            _id
        },
            ctx.request.body
        );
        if (!advertiseDetail) {
            throw new global.errs.NotFound("此广告不存在");
        }
        ctx.status = 200;
        ctx.body = res.success("更新广告成功");
    }

    // 删除广告
    static async deleteAdvertiseById(ctx, next) {
        const _id = ctx.params._id;
        const advertiseDetail = await AdvertiseModel.findByIdAndDelete({
            _id
        });
        if (!advertiseDetail) {
            throw new global.errs.NotFound("此广告不存在");
        }
        ctx.status = 200;
        ctx.body = res.success("删除广告成功");
    }
}
module.exports = ReplyController;

博客《其它补充》

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Express和MongoDB是一对非常强大的组合,可以用来构建管理后台。Express是一种基于Node.js的Web框架,提供了许多强大的功能,如路由、中间件、模板引擎等。而MongoDB则是一种流行的NoSQL数据库,可以轻松地存储大量数据,并且具有高可用性和可扩展性。 要实现一个管理后台,首先需要用Express来搭建应用程序。可以使用npm包管理器来安装所需的依赖,并使用模板引擎来渲染页面。同时,也可以使用Express提供的中间件来处理身份验证、文件上传、错误处理等问题。 在管理后台中,数据是至关重要的。这就是MongoDB的用武之地了。可以使用官方的MongoDB Node.js驱动程序或第三方ORM,如Mongoose等来连接数据库并执行CRUD操作。通过使用MongoDB,可以轻松地管理用户、文章、评论、订单等数据,并将其存储在一个集合中。 除了使用Express和MongoDB以外,管理后台还可以通过使用其他有用的工具和技术来增强。例如: - 使用Bootstrap或其他CSS框架来创建漂亮的用户界面。 - 使用Webpack或Gulp等工具来优化前端资源。 - 使用Socket.IO来实时通信。 - 使用Passport.js或其他身份验证库来实现用户认证。 - 使用JWT或其他令牌库来实现安全的API访问。 总的来说,使用Express和MongoDB可以轻松地创建一个功能强大的管理后台,它不仅可以管理数据,还可以提供良好的用户界面和安全的认证和授权。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值