koa + mysql做一个后端系统

做毕设学了点东西系列

之前已经用antdpro做了前端,就直接把后端部分在前端目录下加了一个server文件夹,npm包也直接安装在了目录下,省去了很多步骤(偷懒了

koa中间件

先来学习一下koa的一些理论
koa的一个中间件是这样定义的

1
2
3
4
5
async function middleware(ctx, next) {
// xxx
await next();
// xxx
}

第一个参数是Koa Context,是所有的中间件和请求处理函数传递的内容,封装了requestresponse,可以通过ctx.requestctx.response获取,常用属性如下:

1
2
3
ctx.url // 相当于ctx.request.url
ctx.body // ctx.response.body
ctx.status // ctx.response.status

第二个参数是next函数,用来把控制权交给下一个中间件。与Express不同的是,这里的next函数返回的是一个Promise,这个Promise完成后,就会去执行next函数后面的内容,也就是将中间件的执行拆分为两个阶段(next前面和next后面)

文件结构

├── server
│ ├── config // 配置
│ ├── routes // 定义路由
│ ├── controllers // 逻辑处理
│ ├── service // 数据库接口方法
│ ├──models // 数据库表结构
│ ├──utils // 公用方法
│ └── app.js // 入口文件

安装依赖和初始化

  • koa
  • koa-router
  • koa-json
  • koa-bodyparser
  • sequelize
  • sequelize-auto
  • mysql2

在app.js中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const Koa = require('koa');
const Router = require('koa-router');
const Json = require('koa-json');
const Parser = require('koa-bodyparser');
const app = new Koa();
const router = new Router();
app.use(new Parser());
app.use(new Json());
app.on('error', function(err, ctx){
console.log('server error', err);
});
app.listen(8889,() => {
console.log('Koa is listening in 8889');
});
module.exports = app;

此时运行node app.js可以看到server在listen了

数据库配置

本地配置

使用本地mysql数据库,建库,建表

和数据库交互

使用了sequelize来实现ORM,安装相关的依赖后

1 首先在server目录下运行自动生成数据库表对应的对象

1
sequelize-auto -o "./models" -d gas -h 127.0.0.1 -u root -p 3306 -x XXXXX -e mysql // xxxxx是密码

运行后会在models下生成所有数据库表对应的js文件和一个init-models.js

2 在config下新建数据库相关的配置

1
2
3
4
5
6
7
8
9
10
11
12
const Sequelize = require('sequelize'); // 引入sequelize
const Gas = new Sequelize('mysql://root:123456@localhost/gas',{
define: {
timestamps: true // 自动给数据表加入时间戳
}
})
module.exports = {
Gas
}

之后Gas就可以暴露出来在service层中调用数据库方法

3 在service层中对数据库表进行增删改查的操作

以一个user作为例子,在service下新增user.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// models/user.js
const db = require('../config/db.js');
const GasDb = db.Gas; // 引入数据库
const initModels = require("../models/init-models"); // 初始化models
const models = initModels(GasDb);
const User = models.user; // 使用user对象
const getUserById = async (id) => {
const userInfo = await User.findOne({
where: {
id: id
}
});
return userInfo // 返回数据
}
module.exports = {
getUserById, // 导出getUserById的方法,将会在controller里调用
}

来写完一个接口吧

以上步骤实现了和数据库user表的交互并且定义了一个方法来根据id查询user,完成这个接口的话,首先在routes中分发这个接口,然后在指定的controller层的方法中处理并且调用service层的方法,返回需要的信息。下面倒着来实现这个过程。

controller

1
2
3
4
5
6
7
8
9
10
11
12
// controllers/user.js
const user = require('../service/user.js');
const getUserInfo = async (ctx) => {
const id = ctx.params.id; // 获取url里传过来的参数里的id
const result = await user.getUserById(id); // 调用service方法
ctx.body = result; // 设置响应
}
module.exports = {
getUserInfo, // 把获取用户信息的方法暴露出去
}

routes

1
2
3
4
5
6
const user = require('../controllers/user.js');
const Router = require('koa-router');
const router = new Router();
router.get('/user/:id', user.getUserInfo); // 定义了一个get方法
module.exports = router; // 暴露router规则

在app.js中引入这个路径

1
2
3
router.use('/user', user.routes()); // 挂载路由信息,所有用户相关请求路径前面加上'/user'的请求路径。
app.use(koa.routes()); // 将所有的路由规则挂载到Koa上

验证这个接口

使用postman,get http://localhost:8889/user/user/1
查看返回的数据如下:

1
2
3
4
5
6
{
"id": 1,
"name": "admin",
"username": "admin",
"password": "admin"
}

用户认证使用jwt

https://qqcr.github.io/2021/01/29/jwt%E8%AE%A4%E8%AF%81%E5%AE%9E%E8%B7%B5/

参考两篇很棒的博客文章