Koa+mongodb实战

koa 脚手架

本人弄了一个koa脚手架,koa和mongodb组合而成, 已上传GitHub. 👏 👏 👏 👏

传送门

目录结构如上,一个控制器(也就是写代码的地方),一个日志,一个数据库模型,一个路由,一个工具,和入口文件。

写代码只要添加路由 填充控制器就好了,如图所示

下面解析下有哪些构成的👇

koa

const Koa = require('koa');
const app = new Koa();
// response
app.use(ctx => {
  ctx.body = 'Hello Koa';
});
app.listen(3000);

更多见阮一峰koa框架

router

官方例子

var Koa = require('koa');
var Router = require('koa-router');
var app = new Koa();
var router = new Router();
router.get('/', (ctx, next) => {
  // ctx.router available
});
app
  .use(router.routes())
  .use(router.allowedMethods());

实战例子

// routers/index.js
const Router = require('koa-router')
const dateNumberController = require('../controllers/date_number')
const router = new Router({
	prefix: '/api'
})
dateNumberController.prefix ='date_number'
router
.post(dateNumberController.getPath('add'), dateNumberController.add)
.get(dateNumberController.getPath(`select`), dateNumberController.find)
.post(dateNumberController.getPath(`remove`), dateNumberController.delect)
.post(dateNumberController.getPath(`update`), dateNumberController.update)
module.exports = router
// main.js
const router = require('./routers')
app.use(router.routes());

更多详情见koa-router github

bodyparser

有了路由,但是我们还需要前端传递过来的参数,所以需要先获取参数

例子

app.use(async ctx => {
  ctx.body = ctx.request.body;
});

这时候post请求就可以解析了,不管是application/json还是application/x-www-form-urlencoded

效果

更新详情见bodyparser GitHub

koa-parameter

拿到参数后我们需要校验它

// main.js
const parameter = require("koa-parameter")
const error = require("koa-json-error")
app.use(parameter(app));
// 这个是json错误处理,可以自动抛出http status 422
app.use(
    error({ postFormat: (e, { stack, ...rest }) => ({ stack, rest }) })
)
// ctx里面,比如路由里面
ctx.verifyParams({
    date: { type: "string", required: true },
    list: { type: "array", required: true },
})

mongodb

拿到参数,我们下一步就是需要操作数据了

初始化

安装mongodb,然后npm安装mongoose, 如下初始化即可

const mongoose = require('mongoose')
// db是数据库名称哦,没有的话会自动创建
const DB_ADDRESS = "mongodb://localhost:27017/db"
mongoose.connect(DB_ADDRESS, {useNewUrlParser: true, useUnifiedTopology: true}, err => {
    if (err) {
        log.fatal({msg: '[Mongoose] database connect failed!', err})
    } else {
        console.log('[Mongoose] database connect success!')
    }
})
module.exports = mongoose

建立模型

使用的时候,我们需要先建立集合(在mysql里面叫表),但是MD更灵活,可以直接在代码里面操作,我们先建立模型。

const mongoose = require('mongoose');  
const { Schema, model } = mongoose;
// 数据模型  
let DateNumberSchema = new Schema({
    date: { type: String, required: true, unique: true },
    list: { type: Array, require: true },
});
module.exports = model('DateNumber', DateNumberSchema);

操作数据库

const data = await DateNumber.find()

新增

// 要和模型对应
const data = await to( new DateNumber({date, list}).save() 

const data = await DateNumber.deleteOne({date: date})

const data = await DateNumber.updateOne({date}, {$set: {list}})

例子

const DateNumber = require('../models/dateNumber')
class DateNumberController {
    prefix = ''
    getPath(name){
        return `/${this.prefix}/${name}`
    }
    async add(ctx, next){
        ctx.verifyParams({
            date: { type: "string", required: true },
            list: { type: "array", required: true },
        })
        const {date, list} = ctx.request.body
        const [err, data] = await to( new DateNumber({date, list}).save() )
        if(err) return ctx.throw(500, err)
        ctx.response.body = data
    }
    async find(ctx, next){
        const data = await DateNumber.find()
        ctx.response.body = data.join('\n')
        log.info('find')
    }
    async delect (ctx, next){
        ctx.verifyParams({
            date: { type: "string", required: true },
        })
        const {date} = ctx.request.body
        const data = await DateNumber.deleteOne({date: date})
        ctx.response.body = data
    }
    async update(ctx, next){
        ctx.verifyParams({
            date: { type: "string", required: true },
            list: { type: "array", required: true },
        })
        const {date, list} = ctx.request.body
        const [err, data] = await to( DateNumber.updateOne({date}, {$set: {list}}) )
        if(err) return ctx.throw(500, err)
        ctx.response.body = data
    }
}
module.exports = new DateNumberController()

对应关系(来自菜鸟教程)

SQL术语/概念MongoDB术语/概念解释/说明
databasedatabase数据库
tablecollection数据库表/集合
rowdocument数据记录行/文档
columnfield数据字段/域
indexindex索引
tablejoins表连接,MongoDB不支持
primarykeyprimary key 主键,MongoDB自动将_id字段设置为主键

MAC的需要先运行mongod,然后再开一个窗口,不然会提醒找不到服务;
Windows有自带的可视化软件,安装的时候install mongoDB compass勾上即可

to function

上面有一个代码用到了to

to是对promise的一个封装,变成[err, data] 这种形式,这样有一个好处是不需要写try catch,又可以平级处理错误。

to是全局的,在main.js引入

mongodb更多见菜鸟教程

日志

使用log4js实现日志

使用方式

var log4js = require('log4js');
var logger = log4js.getLogger();
logger.level = 'debug';
logger.debug("Some debug messages");

Level

等级作用是,输出>=当前级别的日志

输出设置

我设置的是,info正常输出,输出的时候按日期分(这样文件不会太大),如果遇到error这种大问题就发邮件,例子如下,包含测试代码,你配置下email里面的账号密码就可以运行了

const config = {
    // 例子
    email: {
        host: 'smtp.qq.com',
        auth: {
            user: '你的qq号@qq.com',
            pass: '你的密码,',
        },
        recipients: '发送方@126.com'
    }
}
const LOGINFO = {
    appenders: {
        info: {
            type: "DateFile",
            category: 'dateFileLog',
            filename: path.join(__dirname, './log/info/'),
            pattern: "yyyy-MM-dd.log",
            alwaysIncludePattern: true
        },
        email: {
            type: '@log4js-node/smtp',
             //发送邮件的邮箱
            sender: config.email.auth.user,
             //标题
            subject: 'Latest error report',
            SMTP: {
                host: config.email.host, 
                auth: config.email.auth,
            },
            recipients: config.email.recipients
        }
    },
}
const log4js = require('log4js')
log4js.configure(LOGINFO)
const log_info = log4js.getLogger()
const log_error = log4js.getLogger('error')
global.log = {
    debug: log_info.debug.bind(log_info),
    info: log_info.info.bind(log_info),
    warn: log_info.warn.bind(log_info),
    error: log_error.error.bind(log_error),
    fatal: log_error.fatal.bind(log_error),
}
// 这个是测试代码
setTimeout(() => {
    log.fatal({
        msg: '测试',
        err: 'fatal'
    })
}, 400)

邮箱密钥获取方式: 进入qq邮箱,设置—-> 账户 ——->开启服务:POP3/SMTP服务 —–>生成授权码

log.fatal({
        msg: '测试',
        err: 'fatal'
})

效果

log4js更多详情见 log4js github
log4js邮箱更多详情见 log4js-node/smtp github

其他

各位大哥哥小姐姐麻烦点个赞,我要冲3级,谢谢

— 完 —

https://juejin.im/post/5eb9595c5188256d9d598b59

「点点赞赏,手留余香」

    还没有人赞赏,快来当第一个赞赏的人吧!
0 条回复 A 作者 M 管理员
    所有的伟大,都源于一个勇敢的开始!
欢迎您,新朋友,感谢参与互动!欢迎您 {{author}},您在本站有{{commentsCount}}条评论