加载中...
ERP后端
发表于:2022-12-15 | 更新于:2023-01-13 | 分类: 项目

技术栈:node + koa2 + mysql + swagger

搭建框架

创建项目

项目
// 新建node.js文件,生成package.json文件
npm init -y
// 下载koa2框架
npm i koa --save
// node.js挂载
const Koa = require('koa');
const app = new Koa;
// 3000 端口号
app.listen(3000)
console.log('http://localhost:3000');
// 自启项目
npm i nodemon --save
// node.js 文件名
nodemon node.js
npm run test

所有依赖

下载依赖
// 生成package.json文件
npm init -y
// 下载koa2框架
npm i koa --save
// 自动启动项目
npm i nodemon --save
// 路由下载
npm i koa-router --save
// 返回前端格式
npm i koa-json --save
npm i koa-bodyparser --save
// 生成token
npm i jsonwebtoken --save
// mysql
npm i mysql --save
// 接口文档
npm i koa2-swagger-ui swagger-jsdoc --save

node.js 挂载

挂载
// 挂载
const Koa = require('koa')
const app = new Koa()

// 挂载
const router = require('koa-router')()
app.use(router.routes())
app.use(router.allowedMethods())

// 挂载
const json = require('koa-json')
const bodyparser = require('koa-bodyparser')
app.use(json())
app.use(bodyparser())

//引入路由文件
const banner = require('./router/index')

//注册路由中间件
app.use(banner.routes(), banner.allowedMethods())

// 3000 端口号
app.listen(3000)
console.log('http://localhost:3000/')

连接 mysql 数据库

修改:node.js
// 挂载
const Koa = require('koa')
const app = new Koa()

// 挂载
const router = require('koa-router')()
app.use(router.routes())
app.use(router.allowedMethods())

// 挂载
const json = require('koa-json')
const bodyparser = require('koa-bodyparser')
app.use(json())
app.use(bodyparser())

//引入路由文件
const banner = require('./router/index')

//注册路由中间件
app.use(banner.routes(), banner.allowedMethods())

// 挂载
const mysql = require('mysql')
// 连接mysql数据库
var coonnection = mysql.createConnection({
  host: 'localhost', // 端口号
  user: 'root', // 账户
  password: '253547', // 密码
  database: 'node' // 表名
})
coonnection.connect(function (err) {
  if (err) {
    console.log('连接失败' + err.stack)
    return
  }
  console.log('连接成功' + coonnection.threadId)
})

// 3000 端口号
app.listen(3000)
console.log('http://localhost:3000/')

封装连接池

新建:models/mysql.js
// 挂载
const mysql = require('mysql')

// 创建数据库连接池
const pool = mysql.createPool({
  host: 'localhost', // 端口号
  user: 'root', // 账户
  password: '253547', // 密码
  database: 'node' // 表名
})

// 封装异步操作
let query = function (sql, values) {
  return new Promise((resolve, reject) => {
    pool.getConnection(function (err, connection) {
      if (err) {
        reject(err)
      } else {
        connection.query(sql, values, (err, rows) => {
          if (err) {
            reject(err)
          } else {
            resolve(rows)
          }
          connection.release()
        })
      }
    })
  })
}

module.exports = { query }

生成 token

新建:utils/token.js
// 生成token
npm i jsonwebtoken --save
// 挂载
const jwt = require('jsonwebtoken')
// token生成的密匙,根据自己需求定义
const jwtKey = 'didicar'
// token生成函数(jwtSign),有效时间为一个小时
const jwtSign = (data) => {
  const token = jwt.sign(data, jwtKey, { expiresIn: 60 * 60 })
  return token
}
// token验证函数---解析token是否有效----其他请求方法
const jwtCheck = (req, res, next) => {
  //前端headers传来的token值:
  const token = req.headers.authorization
  jwt.verify(token, jwtKey, (err, data) => {
    if (err) {
      console.log('token失效了')
      res.send({
        message: '登录过期,请重新登录!',
        code: 201
      })
      return
    } else {
      req.jwtInfo = data
      next()
    }
  })
}
/*
    后台登录验证 : token
    token : token值
    jwtKey : 密钥
 */
const verifyToken = (token, jwtKey) => {
  return new Promise((resolve, reject) => {
    try {
      const info = jwt.verify(token, jwtKey)
      resolve(info)
    } catch (error) {
      console.log('后台报错了')
    }
  })
}
module.exports = {
  jwtSign,
  jwtCheck,
  verifyToken
}

处理响应

新建:utils/init.js
class initdata {
  constructor(ctx, message = 'success', data = [], code = 200) {
    this.ctx = ctx
    this.message = message
    this.data = data
    this.code = code
  }

  //200
  listing() {
    this.ctx.body = {
      code: this.code,
      message: this.message,
      data: this.data
    }
    this.ctx.status = this.code
  }

  // 参数不对
  tips(tipmessage, codes) {
    this.ctx.body = {
      message: tipmessage
    }
    this.ctx.status = codes
  }
}
module.exports = initdata

增删改查

新建:router/index.js
index.js
//引入mySql
const { query } = require('../models/mySql')
//路由
const router = require('koa-router')()
// 全局异常
const initdata = require('../utils/init')
//引入token生成函数
const { jwtSign } = require('../utils/token')
//打印
const { log } = console

// 增删改查

module.exports = router
// 增 INSERT into 表名 (字段名列表(逗号隔开)) values(值列表(逗号隔开));
router.post('/increase', async (ctx, next) => {
  let { username, password } = ctx.request.body
  // 校验
  if ((username === '') | (password === '')) {
    new initdata(ctx).tips('用户名和密码不能为空', 202)
    return false
  }
  if ((username === undefined) | (password === undefined)) {
    new initdata(ctx).tips('参数填写不正确', 400)
    return false
  }
  // 用户名校验
  let phone = /^1[3456789]\d{9}$/
  if (!phone.test(username)) {
    new initdata(ctx).tips('手机号码不正确', 202)
    return false
  }
  // 密码校验
  let reg = /^(?![\d]+$)(?![a-zA-Z]+$)(?![^\da-zA-Z]+$).{6,20}$/
  if (!reg.test(password)) {
    new initdata(ctx).tips('密码必须由6~20位数字和字母的组合', 202)
    return false
  }
  // 新增sql
  let sql = 'INSERT into `user` (id,username,password) value(null,?,?);'
  let params = [username, password]
  let listdata = await query(sql, params)
  // 返回
  if (listdata.length === 0) {
    new initdata(ctx).tips('账号或密码错误', 202)
  } else {
    ctx.body = {
      code: 200,
      message: 'success'
    }
  }
})
// 删 DELETE FROM 表名 WHERE 删除条件;
router.post('/delete', async (ctx, next) => {
  let { username, password } = ctx.request.body
  // 校验
  if ((username === '') | (password === '')) {
    new initdata(ctx).tips('用户名和密码不能为空', 202)
    return false
  }
  // 删除sql
  let sql = 'DELETE FROM user WHERE username=?'
  let params = [username]
  let listdata = await query(sql, params)
  // 返回
  if (listdata.length === 0) {
    new initdata(ctx).tips('删除失败', 202)
  } else {
    ctx.body = {
      code: 200,
      message: 'success'
    }
  }
})
// 改 UPDATE 表名 SET 字段1=表达式1,字段2=表达式2 WHERE 修改条件;
router.post('/change', async (ctx, next) => {
  let { username, password, id } = ctx.request.body
  // 校验
  if ((username === '') | (password === '')) {
    new initdata(ctx).tips('用户名和密码不能为空', 202)
    return false
  }
  // 删除sql
  let sql = 'UPDATE user SET username = ?,password = ? WHERE id = ?'
  let params = [username, password, id]
  let listdata = await query(sql, params)
  // 返回
  if (listdata.length === 0) {
    new initdata(ctx).tips('更新用户失败', 400)
  } else {
    ctx.body = {
      code: 200,
      message: 'success'
    }
  }
})
// 查 `SELECT * FROM 表名 WHERE 字段 = '${参数}'`
router.post('/login', async (ctx, next) => {
  let { username, password } = ctx.request.body
  // 校验
  if ((username === '') | (password === '')) {
    new initdata(ctx).tips('用户名和密码不能为空', 202)
    return false
  }
  if ((username === undefined) | (password === undefined)) {
    new initdata(ctx).tips('参数填写不正确', 400)
    return false
  }
  if (username !== 'admin' || password !== 'admin') {
    // 用户名校验
    let phone = /^1[3456789]\d{9}$/
    if (!phone.test(username)) {
      new initdata(ctx).tips('手机号码不正确', 202)
      return false
    }
    // 密码校验
    let reg = /^(?![\d]+$)(?![a-zA-Z]+$)(?![^\da-zA-Z]+$).{6,20}$/
    if (!reg.test(password)) {
      new initdata(ctx).tips('密码必须由6~20位数字和字母的组合', 202)
      return false
    }
  }
  // 查询集合
  let sql = `SELECT * FROM user WHERE username = '${username}'`
  let listdata = await query(sql)
  // 用引入的jwtSign方法生成token并返回
  const token = jwtSign({})
  // 返回
  if (listdata.length === 0) {
    new initdata(ctx).tips('账号或密码错误', 202)
  } else {
    ctx.body = {
      code: 200,
      data: {
        pageItems: token,
        total: 1
      },
      message: 'success'
    }
  }
})
无规则新增
// 无规则新增
router.post('/register', async (ctx, next) => {
  let { username, password } = ctx.request.body
  // 存储到数据库
  let sql = 'INSERT into `user` (id,username,password) value(null,?,?);'
  let params = [username, password]
  let listdata = await query(sql, params)
  // 返回
  if (listdata.length === 0) {
    new initdata(ctx).tips('账号或密码错误', 202)
  } else {
    ctx.body = {
      code: 200,
      message: '新增成功'
    }
  }
})

编写接口文档

新建:swagger.js
下载依赖:npm i koa2-swagger-ui swagger-jsdoc --save
// node.js同级
const router = require('koa-router')() //引入路由函数
const swaggerJSDoc = require('swagger-jsdoc')
const path = require('path')
const swaggerDefinition = {
  info: {
    title: 'ERP后台管理接口文档',
    version: '1.0.0',
    description: 'API'
  },
  host: 'localhost:3000', // 想着改这里,如果不修改,那么接口文档访问地址为:localhost:3000/swagger
  basePath: '/' // Base path (optional)
}
const options = {
  swaggerDefinition,
  apis: [path.join(__dirname, './router/*.js')] // 写有注解的router的存放地址, 最好path.join()
}
const swaggerSpec = swaggerJSDoc(options)
// 通过路由获取生成的注解文件
router.get('/swagger.json', async function (ctx) {
  ctx.set('Content-Type', 'application/json')
  ctx.body = swaggerSpec
})
module.exports = router
node.js挂载
// 挂载
const swagger = require('./swagger') // 存放swagger.js的位置,可以自行配置,我放在了根目录
const { koaSwagger } = require('koa2-swagger-ui')

// 接口文档配置
app.use(swagger.routes(), swagger.allowedMethods())
app.use(
  koaSwagger({
    routePrefix: '/swagger', // 接口文档访问地址
    swaggerOptions: {
      url: '/swagger.json' // example path to json 其实就是之后swagger-jsdoc生成的文档地址
    }
  })
)
新建:router/swagger.js
/**
 * @swagger
 * definitions:
 *  loginparam:
 *    properties:
 *      username:
 *        type: "string"
 *        default: "admin"
 *        description: 用户名
 *      password:
 *        type: "string"
 *        default: "admin"
 *        description: 密码
 */

/**
 * @swagger
 * /login:
 *   post:
 *     summary: 登录
 *     description: 登录
 *     tags:
 *       - user
 *     consumes:
 *      - application/json
 *      - application/xml
 *     produces:
 *      - application/json
 *      - application/xml
 *     parameters:
 *       - name: body
 *         in: body
 *         schema:
 *          $ref: '#/definitions/loginparam'
 *     responses:
 *       200:
 *         description: 发布成功
 *       402:
 *          description: 信息填写不全
 *       403:
 *          description: 参数类型错误
 */

/**
 * @swagger
 * /treemodules:
 *   get:
 *     description: 所有权限
 *     tags: [authority] #分类
 *     summary: "所有权限" #这个接口的提示
 *     produces: #返回类型
 *       - application/json
 *       - application/xml
 *       - application/x-www-form-urlencoded
 *     responses:
 *       200:
 *         description: 成功
 *       400:
 *          description: 失败
 *       404:
 *          description: 未找到
 * */
/**
 * @swagger
 * /securityuser:
 *   get:
 *     description: 用户权限
 *     tags: [authority] #分类
 *     summary: "用户权限" #这个接口的提示
 *     produces: #返回类型
 *       - application/json
 *       - application/xml
 *       - application/x-www-form-urlencoded
 *     responses:
 *       200:
 *         description: 成功
 *       400:
 *          description: 失败
 *       404:
 *          description: 未找到
 * */
上一篇:
后台管理
下一篇:
跨域
本文目录
本文目录