# koa2-sql 增删改查
**Repository Path**: zhanhongzhu/koa2-sql
## Basic Information
- **Project Name**: koa2-sql 增删改查
- **Description**: koa2-sql 增删改查 示例
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 6
- **Forks**: 1
- **Created**: 2022-03-15
- **Last Updated**: 2024-06-23
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
## 一、nodejs【Koa2+mysql 】搭建用户信息注册和登录接口服务
## koa2 官网
[https://koa.bootcss.com/](https://koa.bootcss.com/)
## 什么是koa?
Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。 通过利用 async 函数,Koa 帮你丢弃回调函数,并有力地增强错误处理。 Koa 并没有捆绑任何中间件, 而是提供了一套优雅的方法,帮助您快速而愉快地编写服务端应用程序。
## 初始化koa项目
```javascript
npm init
```
## 安装koa
```javascript
npm i koa
```
## 新建一个app.js
```javascript
// 导入koa
const Koa = require('koa')
// 创建一个koa对象
const app = new Koa()
//监听端口
const port = 3000
app.listen(port);
console.log(`启动成功,服务端口为:${port}`)
```
## 运行app.js
```javascript
node app.js
// console.log(`启动成功,服务端口为:${port}`)
```
## 添加启动脚本命令
```js
//package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev":"node app.js"
}
```
可以运行 `npm run dev`启动我们的服务。
## 使用 www 启动服务
在根目录建立 bin文件夹,然后新建 www文件
```js
// bin/www
var app = require('../app');
var http = require('http');
var server = http.createServer(app);
//服务监听端口
server.listen('3001');
```
## 配置www启动脚本
```js
//package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev":"node bin/www"
}
```
然后 `npm run dev`就能启动了。
## 加点服务的返回内容
```js
// 导入koa
const Koa = require('koa')
// 创建一个koa对象
const app = new Koa()
//返回的内容
app.use(async ctx => {
ctx.body = 'Hello World';
});
//监听端口
const port = 3000
app.listen(port);
console.log(`启动成功,服务端口为:${port}`)
```

## 安装中间件 koa-bodyparser
这个中间件可以将post请求的参数转为json格式返回;
```js
npm install --save koa-bodyparser
```
## bodyparser 使用
```js
// 导入koa
const Koa = require('koa')
const bodyParser = require('koa-bodyparser');
// 创建一个koa对象
const app = new Koa()
app.use(bodyParser());
// request.method可以获取请求方法。
// get,post或者其他类型(request对象被封在ctx内,所以也可以ctx.method获取)
app.use(async (ctx) => {
if (ctx.url === '/' && ctx.method === 'POST') {
ctx.body = ctx.request.body
} else {
// 其他请求显示404
ctx.body = '
404!
'
}
})
//监听端口
const port = 3000
app.listen(port);
console.log(`启动成功,服务端口为:${port}`)
```
开始写接口之前,我们安装一下路由 Koa-router
Koa-router是 koa 的一个路由中间件,它可以将请求的URL和方法(如:`GET` 、 `POST` 、 `PUT` 、 `DELETE` 等) 匹配到对应的响应程序或页面。
```js
npm install koa-router --save
```
## 使用koa-router
```js
const Router = require('koa-router'); // 引入koa-router
const router = new Router(); // 创建路由,支持传递参数
// 指定一个url匹配
router.get('/', async (ctx) => {
ctx.type = 'html';
ctx.body = 'hello world!
';
})
// 调用router.routes()来组装匹配好的路由,返回一个合并好的中间件
// 调用router.allowedMethods()获得一个中间件,当发送了不符合的请求时,会返回 `405 Method Not Allowed` 或 `501 Not Implemented`
app.use(router.routes());
app.use(router.allowedMethods({
// throw: true, // 抛出错误,代替设置响应头状态
// notImplemented: () => '不支持当前请求所需要的功能',
// methodNotAllowed: () => '不支持的请求方式'
}));
```
## koa-router 不同请求方式
Koa-router 请求方式: get 、 put 、 post 、 patch 、 delete 、 del ,而使用方法就是 router.方式() ,比如 router.get() 和 router.post() 。而 router.all() 会匹配所有的请求方法。
```js
// 指定一个url匹配
router.get('/test', async (ctx) => {
ctx.type = 'html';
ctx.body = 'hello world!
';
})
router.get("/user", async (ctx) => {
ctx.body = '叫我詹躲躲';
})
```

## 新建router/index.js 路由文件夹
```js
// router/index.js
const Router = require('koa-router')
const router = new Router()
//接口函数
class UserController {
// 新增一条数据
async getUserName(ctx) {
ctx.body = {
code: 200,
message: '叫我詹躲躲',
type: 'warning'
}
}
}
//实例
const userController = new UserController()
// 测试
router.get('/test', userController.getUserName)
module.exports = router
```
测试一下

## 安装中间件 koa2-cors
cors跨域资源共享是一种机制,用来允许不同源服务器上的指定资源可以被特定的Web应用访问。
## cors 安装
```js
npm install koa-cors --save
```
## cors 使用
```js
//app.js
const Cors = require('koa2-cors')
app.use(Cors())
```
## koa连接数据库(mysql)
需要安装sql依赖;
```js
npm install mysql --save
```
## SQL配置
新建一个 sql文件夹,主要用于存放sql的各种操作;
`sql/config.js`
```js
const mysqlConfig = {
user: "Koa", //账号
password: "Koa", //密码
database: "Koa", //数据库
host: "122.112.172.87", //服务器地址
port: 3306, //数据库端口
timezone: '08:00'
};
module.exports = mysqlConfig;
```
## koa封装sql数据库query函数
```js
//sql/query.js
const mysql = require("mysql");
const config = require("./config");
//创建连接池
const pool = mysql.createPool(config);
const query = (sql, val) => {
return new Promise((resolve, reject) => {
pool.getConnection(function (err, connection) {
if (err) {
reject(err);
} else {
connection.query(sql, val, (err, fields) => {
if (err) {
reject(err);
} else {
resolve(fields);
}
connection.release();
});
}
});
});
};
module.exports = { query };
```
## 新增接口 - 用户信息注册 和 登录
新建两个文件夹 controller 和 model
controller主要存放操作和数据处理的一些逻辑
```js
// controller/userController.js
// 用户注册
const User = require('../model/userModel')
class UserController {
// 用户注册
async register(ctx) {
let { name, tel, password } = ctx.request.body
const names = await User.getUser(name) //用户名是否重复
const tels = await User.getTel(tel) //手机号是否重复
if (tels.length > 0) {
ctx.body = { type: 'warning', message: '该手机号已注册' }
} else {
if (names.length > 0) {
ctx.body = { type: 'error', message: '用户名已存在' }
} else {
await User.insert(name, tel, password)
ctx.body = { type: 'success', code: 0, message: '注册成功' }
}
}
}
// 登录
async login(ctx) {
let tel = ctx.request.body.tel
let password = ctx.request.body.password
const res = (await User.getTel(tel))[0]
if (res) {
if (res.password == password) {
ctx.body = {
code: 0,
data: {
name: res.name,
tel: res.tel
},
message: '登录成功',
type: 'success'
}
} else {
ctx.body = { type: 'error', message: '用户名或密码不正确' }
}
} else {
ctx.body = { type: 'error', message: '用户名不存在' }
}
}
}
module.exports = new UserController()
```
## model中操作数据库的函数(包含数据库语句)
```js
// model/userModel.js
const query = require('../sql/query')
class UserModel {
//获取用户
async getUser(name) {
return await query(`SELECT * FROM user WHERE name = '${name}'`)
}
//获取用户手机号
async getTel(tel) {
return await query(`SELECT * FROM user WHERE tel = '${tel}'`)
}
//用户注册
async insert(name, tel, password) {
return await query(`INSERT INTO user(name, tel, password) VALUES('${name}', '${tel}', '${password}')`)
}
}
module.exports = new UserModel()
```
## 在router路由文件里面注册
```js
//router/index.js
const Router = require('koa-router')
const router = new Router()
//用户
const UserController = require('../controller/UserController')
//用户注册
router.post('/register', UserController.register)
//用户信息登录
router.post('/login', UserController.login)
module.exports = router
```
## 接口调用
使用post请求就可以调用 /register 和 /login两个接口啦;当然也可以再封装其他更多的接口。
## 结尾
到此 用户的注册和登录接口就写完了。后续继续其他功能添加。有兴趣的可以查看源码 [源码地址](https://gitee.com/zhanhongzhu/koa2-sql),一起学习,一起加油。我是叫我詹躲躲,很高兴认识你。
## 二、【nodejs进阶之旅(2)】:使用koa2+mysql 实现列表数据分页
## 1.展示效果(分页)

## 2.分页主要字段
分页主要字段包括 pageSize 每页条数、pageNum 第几页、startRow 当前开始页编号、endRow 当前结束页编号、total 总数量。主要是根据前端分页的参数,进行处理后,返回前端正确的数据,其实是一个很常见且简单的功能。但是是非常也是非常重要的。
```js
pageSize 每页条数
pageNum 第几页
startRow 当前开始页编号
endRow 当前结束页编号
total 总数量
```
## 计算 3.startRow 和 endRow
封装成一个函数
```js
/* 分页公共函数*/
module.exports = handlePages = (pageNum, pageSize, total) => {
let startRow = total > 0 ? ((pageNum - 1) * pageSize + 1) : 0;
let endRow = pageNum * pageSize <= total ? pageNum * pageSize : total;
return {
pageNum,
pageSize,
recordCounts:total,
startRow,
endRow
}
}
```
## 4.接口函数中使用该函数
从前端传参中获取,分页所需要的数据。
```js
let { nickname, name, role, pageSize, pageNum } = ctx.request.body;
//此处进行处理
let pageNum1 = (pageNum - 1) * pageSize
```
```js
//获取用户信息列表
async getAllUserList(ctx) {
let { nickname, name, role, pageSize, pageNum } = ctx.request.body
let res = []
let pageNum1 = (pageNum - 1) * pageSize
let total = (await User.getAllUserListTotal())[0].recordCounts
if (!nickname && !name && !role) {
res = (await User.getAllUserListNotCond(pageSize, pageNum1))
} else {
res = (await User.getAllUserList(nickname, name, role, pageSize, pageNum1))
}
ctx.body = {
code: 0,
data: res.map(v => {
if (v.password) {
delete v.password
}
return v
}),
//分页所有的参数
...handlePages(pageNum, pageSize, total)
}
}
```
## 5.分页中的MySql语句
### 根据分页查询数据库的数据
```js
//根据分页查询用户列表
async getAllUserListNotCond(pageSize, pageNum) {
return await query(`SELECT * FROM user LIMIT ${pageNum},${pageSize}`)
}
```
## mySql获取数据库数据总条数
```js
//获取用户信息列表的总条数
async getAllUserListTotal() {
return await query(`SELECT COUNT(*) as recordCounts FROM user`)
}
```
## 关于mySql的COUNT()函数
作用:COUNT() 函数返回匹配指定条件的行数。
### SQL COUNT(column_name) 语法
COUNT(column_name) 函数返回指定列的值的数目(NULL 不计入):
```js
SELECT COUNT(column_name) FROM table_name
```
### SQL COUNT(*) 语法
COUNT(*) 函数返回表中的记录数:
```js
SELECT COUNT(*) FROM table_name
```
### SQL COUNT(DISTINCT column_name) 语法
COUNT(DISTINCT column_name) 函数返回指定列的不同值的数目:
```js
SELECT COUNT(DISTINCT column_name) FROM table_name
```
## 6.切换分页的效果
切换分页后的效果 还是很正常的。

## 7.总结
主要是包含mysql的基本使用。目前还在学习当中,有不当的地方,欢迎指正和一起交流学习。目前正在处理权限管理模块。下一篇文章将讲解如何进行权限控制,有兴趣的可以继续关注。