技术栈: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: 未找到
* */