likes
comments
collection
share

node.js+MongoDB6.0+koa2搭建服务端管理系统基本架构

作者站长头像
站长
· 阅读数 19

初始化server项目

Koa2项目初始化操作通常我们可以借助于脚手架,快速创建一个Koa2项目,当然也可以自己从头搭建;脚手架会帮我们提前搭好基本的架子。

模板地址gitee.com/liu-zi-qi/s…

1.koa-generator快速生成koa服务的脚手架工具全局安装脚手架工具 npm i -g koa-generator --registry=https://registry.npm.taobao.org

2.进入到项目文件夹目录,执行生成命令 koa2 mmyBlog

3.安装依赖 npm i --registry=https://registry.npm.taobao.org

4.启动服务(http://localhost:3000/) npm run dev

node.js+MongoDB6.0+koa2搭建服务端管理系统基本架构

log4js

1.安装命令 npm i log4js -S registry=https://registry.npm.taobao.org

2.新建logs文件夹用来存日志文件

3.新建utils/log4js.js文件

/**
 * 日志存储
 * @author JackBean
 */
const log4js = require('log4js')

const levels = {
    'trace':log4js.levels.TRACE,
    'debug':log4js.levels.DEBUG,
    'info':log4js.levels.INFO,
    'warn':log4js.levels.WARN,
    'error':log4js.levels.ERROR,
    'fatal':log4js.levels.FATAL,
}

log4js.configure({
    appenders:{
        console:{ type:'console' },
        info:{
            type: 'file', 
            filename: 'logs/all-logs.log'
        },
        error:{
            type: 'dateFile',
            filename:'logs/log',
            pattern:'yyyy-MM-dd.log',
            alwaysIncludePattern:true// 设置文件名称为 filename + pattern
        }
    },
    categories:{
        default:{ appenders: [ 'console' ], level: 'debug' },
        info:{
            appenders: [ 'info','console' ],
            level: 'info'
        },
        error:{
            appenders: [ 'error','console' ],
            level: 'error'
        }
    }
})

/**
 * 日志输出,level为debug
 * @param {string} content 
 */
exports.debug = (content)=>{
    let logger = log4js.getLogger();
    logger.level = levels.debug;
    logger.debug(content);
}

/**
 * 日志输出,level为info
 * @param {string} content 
 */
exports.info = (content)=>{
    let logger = log4js.getLogger('info');
    logger.level = levels.info;
    logger.info(content);
}

/**
 * 日志输出,level为error
 * @param {string} content 
 */
exports.error = (content)=>{
    let logger = log4js.getLogger('error');
    logger.level = levels.error;
    logger.error(content);
}

4.app.js引入

const log4js = require('./utils/log4js')

// logger
app.use(async (ctx, next) => {
  log4js.info(`get params:${JSON.stringify(ctx.request.query)}`)
  log4js.info(`post params:${JSON.stringify(ctx.request.body)}`)
})

MongoDB数据库安装使用(6.0.4版本)

MongoDB安装

1.zip安装包下载:https://www.mongodb.com/download-center/community

2.添加系统环境变量

node.js+MongoDB6.0+koa2搭建服务端管理系统基本架构

3.data文件夹下新建db文件夹,在log目录创建名为mongod.log的日志文件(这里安装时自动创建了,我就不新建一个了)

4.在安装目录新建文件mongo.config,内容可复制如下代码,只需要改两个部分:dbpath,logpath

dbpath=D:\MongoDB\data\db #数据库路径logpath=D:\MongoDB\log\mongodb.log #日志输出文件路径logappend=true #错误日志采用追加模式journal=true #启用日志文件,默认启用quiet=true #过滤掉无用的日志信息,若需要调试使用请设置为falseport=27017 #端口号 默认为27017

5.启动服务,在bin目录下打开终端(注意路径,如有如下报错使用该命令:.\mongod --dbpath D:\MongoDB\bin):mongod --dbpath D:\MongoDB\bin

node.js+MongoDB6.0+koa2搭建服务端管理系统基本架构

浏览器访问:http://localhost:27017/ 启动成功!

node.js+MongoDB6.0+koa2搭建服务端管理系统基本架构 6.安装服务(开机自启动),在bin目录下打开终端(注意路径): .\mongod --config "D:\MongoDB\mongo.config" --install --serviceName "MongoDB"

打开任务管理器,可以看到MongoDB服务正在运行

7.安装Mongoshell:MongoDB Shell Download | MongoDB

在MongoDB6之前,我们配置完环境变量后,可以直接通过终端输入"mongo"进入Mongoshell,但MongoDB6没有mong.exe和mongdb.exe,终端输入"mongo"会报错:'mongo' 不是内部或外部命令,也不是可运行的程序或批处理文件。要想通过命令行启动mongoDB需要自己下载一个Mongoshell,下载及使用相当简单。

下载后直接解压到MongoDB的安装目录下(bin同级) ,然后配置系统环境变量(Path):D:\MongoDB\mongosh-1.6.2-win32-x64\bin之后就可以基于”mongosh“指令,通过终端进入Mongoshell了

mongo语法

1.SQL与Mongo对比

SQLMongo
表(table)集合(collection)
行(row)文档(document)
列(col)字段(field)
主键(primary key)对象(objectId)

2.数据库操作

创建数据库(无则创建有则切换):use demo 查看数据库:show dbs 删除数据库: db.dropDatabase

3.集合操作

创建集合:db.creatCollection(name) 查看集合:show collections 删除集合:db.collection.drop()

4.文档操作

创建文档:db.collection.inSertOne({});db.collection.inSertMany([]) 查看文档:db.collection.find({}) 删除文档:db.collection.deleteOne();db.collection.deleteMany() 更新文档:db.collection.update({},{},false,true)

5.条件操作

大于:$gt 小于:$lt 大于等于:$gte 小于等于:$lte

基本框架搭建

1.封装工具函数,utils/util.js

/**
 * 通用工具函数
 */
const log4js = require('./log4js')
const jwt = require('jsonwebtoken')
const CODE = {
  SUCCESS: 200,
  PARAM_ERROR: 10001, // 参数错误
  USER_ACCOUNT_ERROR: 20001, //账号或密码错误
  USER_LOGIN_ERROR: 30001, // 用户未登录
  BUSINESS_ERROR: 40001, //业务请求失败
  AUTH_ERROR: 500001, // 认证失败或TOKEN过期
}
module.exports = {
  /**
   * 分页结构封装
   * @param {number} pageNum 
   * @param {number} pageSize 
   */
  pager({ pageNum = 1, pageSize = 10 }) {
    pageNum *= 1;
    pageSize *= 1;
    const skipIndex = (pageNum - 1) * pageSize;
    return {
      page: {
        pageNum,
        pageSize
      },
      skipIndex
    }
  },
  success(data = '', msg = '', code = CODE.SUCCESS) {
    log4js.debug(data);
    return {
      code, data, msg
    }
  },
  fail(msg = '', code = CODE.BUSINESS_ERROR, data = '') {
    log4js.debug(msg);
    return {
      code, data, msg
    }
  },
  CODE,
  decoded(authorization) {
    if (authorization) {
      let token = authorization.split(' ')[1]
      return jwt.verify(token, 'myBlog')
    }
    return '';
  },
  // 递归拼接树形列表
  getTreeMenu(rootList, id, list) {
    for (let i = 0; i < rootList.length; i++) {
      let item = rootList[i]
      if (String(item.parentId.slice().pop()) == String(id)) {
        list.push(item._doc)
      }
    }
    list.map(item => {
      item.children = []
      this.getTreeMenu(rootList, item._id, item.children)
      if (item.children.length == 0) {
        delete item.children;
      } else if (item.children.length > 0 && item.children[0].menuType == 2) {
        // 快速区分按钮和菜单,用于后期做菜单按钮权限控制
        item.action = item.children;
      }
    })
    return list;
  },
  formateDate(date, rule) {
    let fmt = rule || 'yyyy-MM-dd hh:mm:ss'
    if (/(y+)/.test(fmt)) {
      fmt = fmt.replace(RegExp.$1, date.getFullYear())
    }
    const o = {
      // 'y+': date.getFullYear(),
      'M+': date.getMonth() + 1,
      'd+': date.getDate(),
      'h+': date.getHours(),
      'm+': date.getMinutes(),
      's+': date.getSeconds()
    }
    for (let k in o) {
      if (new RegExp(`(${k})`).test(fmt)) {
        const val = o[k] + '';
        fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? val : ('00' + val).substr(val.length));
      }
    }
    return fmt;
  },
}

2.与数据库建立连接

安装mongoose:npm install mongoose -S --registry=https://registry.npm.taobao.org

// 新建config/index.js
/**
 * 配置文件
 */
module.exports = {
    URL:'mongodb://127.0.0.1:27017/myBlog'
}
// 新建config/db.js
/**
 * 数据库连接
 */
const mongoose = require('mongoose')
const config = require('./index')
const log4js = require('./../utils/log4js')

mongoose.connect(config.URL,{
    useNewUrlParser: true,
    useUnifiedTopology: true
})

const db = mongoose.connection;

db.on('error',()=>{
    log4js.error('***数据库连接失败***')
})

db.on('open',()=>{
    log4js.info('***数据库连接成功***')
})

登录功能

1.jwt,koa-jwt,mongoose,koa-logger安装

npm install koa-jwt -S --registry=https://registry.npm.taobao.org

npm install jsonwebtoken -S --registry=https://registry.npm.taobao.org

npm install koa-logger -S --registry=https://registry.npm.taobao.org

npm install koa-logger jsonwebtoken koa-jwt -S --registry=https://registry.npm.taobao.org

// 引入模块后的app.js文件

const Koa = require('koa')
const app = new Koa()
const views = require('koa-views')
const json = require('koa-json')
const onerror = require('koa-onerror')
const bodyparser = require('koa-bodyparser')
const logger = require('koa-logger')
const log4js = require('./utils/log4js')
const router = require('koa-router')()
const koajwt = require('koa-jwt')
const util = require('./utils/util')
const users = require('./routes/users')

// error handler
onerror(app)

require('./config/db')

// middlewares(中间件)
app.use(bodyparser({
  enableTypes: ['json', 'form', 'text']
}))
app.use(json())
app.use(logger())
app.use(require('koa-static')(__dirname + '/public'))

app.use(views(__dirname + '/views', {
  extension: 'pug'
}))

// logger
app.use(async (ctx, next) => {
  log4js.info(`get params:${JSON.stringify(ctx.request.query)}`)
  log4js.info(`post params:${JSON.stringify(ctx.request.body)}`)
  await next().catch((err) => {
    if (err.status == '401') {
      ctx.status = 200;
      ctx.body = util.fail('Token认证失败', util.CODE.AUTH_ERROR)
    } else {
      throw err;
    }
  })
})

app.use(koajwt({ secret: 'myBlog' }).unless({
  path: [/^\/api\/users\/login/]
}))

router.prefix("/api")

router.use(users.routes(), users.allowedMethods())
app.use(router.routes(), router.allowedMethods())

// error-handling
app.on('error', (err, ctx) => {
  log4js.error(`${err.stack}`)
});

module.exports = app

3.user模型

// models\userSchema.js

const mongoose = require('mongoose')
const userSchema = mongoose.Schema({
    "userId" : Number,//用户ID,自增长
    "userName" : String,//用户名称
    "userPwd" : String,//用户密码,md5加密
    "userEmail" : String,//用户邮箱
    "mobile":String,//手机号
    "sex":Number,//性别 0:男  1:女 
    "deptId":[],//部门
    "job":String,//岗位
    "state" : {
        type:Number,
        default:1
    },// 1: 在职 2: 离职 3: 试用期
    "role": {
        type:Number,
        default:1
    }, // 用户角色 0:系统管理员  1: 普通用户
    "roleList" : [], //系统角色
    "createTime" : {
        type:Date,
        default:Date.now()
    },//创建时间
    "lastLoginTime" : {
        type:Date,
        default:Date.now()
    },//更新时间
    remark:String
})

module.exports = mongoose.model("users",userSchema,"users")

4.routes\users.js文件

/**
 * 用户管理模块
 */
 const router = require('koa-router')()
 const User = require('./../models/userSchema')
 const util = require('./../utils/util')
 const jwt = require('jsonwebtoken')
 const md5 = require('md5')
 router.prefix('/users')
 
 // 用户登录
 router.post('/login', async (ctx) => {
   try {
     const { userName, userPwd } = ctx.request.body;
     /**
      * 返回数据库指定字段,有三种方式
      * 1. 'userId userName userEmail state role deptId roleList'
      * 2. {userId:1,_id:0}
      * 3. select('userId')
      */
     const res = await User.findOne({
       userName,
       userPwd
       // userPwd: md5(userPwd)
     }, 'userId userName userEmail state role deptId roleList')

     if (res) {
       console.log(res, '1111');
       const data = res._doc;
       const token = jwt.sign({
         data
       }, 'myBlog', { expiresIn: '1h' })
       data.token = token;
       ctx.body = util.success(data)
     } else {
       ctx.body = util.fail("账号或密码不正确")
     }
   } catch (error) {
     ctx.body = util.fail(error.msg)
   }
 })

 module.exports = router