一. Express介绍

1 概念

Express 是一个基于nodejs平台的快速,开发,极简的web开发框架
理解: 它和之前内置的http模块一样的,在内置http模块的基础做了封装,使用更加快捷方便

2 核心内容(作用)

Express的核心只有两个部分

  • 路由
  • 中间件

Express提供了基本的路由处理和中间件功能, 几乎所有功能的实现都由一个个独立的中间件完成

路由

  1. 根据不同的url路径,调用后台不同的处理函数

中间件

  1. 指从请求到响应这个业务流程的所有中间处理环节(函数)

二. 安装及使用

express也是一个node的包, 可以npm来安装

1 安装

  1. npm i express

2 使用

步骤

  1. 导入express包
  2. 实例化对象
  3. 编写路由(中间件)
  4. 监听端口

    示例

  1. // 1. 引入express包
  2. const express = require('express')
  3. // 2. 实例化对象
  4. const app = express()
  5. // 3. 编写路由
  6. app.get('/', function(req, res) {
  7. res.send('hello world')
  8. })
  9. // 4. 监听端口
  10. app.listen(3000)

三. 路由

  1. 根据不同的url路径,调用后台不同的处理函数

1 请求方式

请求方式就是HTTP协议的请求方式, 常见的有

  • get: 对应app.get()
  • post: 对应app.post()
  • put: 对应app.put()
  • delete: 对应app.delete()

    2 URL

    格式
    协议://端口/path?queryString#hash #hash:锚链接

解析queryString

对于query参数
使用req.params获得参数
可得到如:id,name,age…
对于/users/:id 类型
使用req.query获得参数
可得到如:id,name,age…

  1. // 第一种, 不带参数
  2. app.get('/users', function(req, res) {
  3. res.send('hello world')
  4. })
  5. // 第二种, 带参数
  6. app.get('/users/:id', function(req, res) {
  7. res.send('hello world')
  8. })
  9. // 第三种, 正则表达式, 以html结尾
  10. app.get(/.html$/, function(req, res) {
  11. res.send('hello world')
  12. })

3 处理函数

1) 请求对象

请求对象包含了一次请求中的所有数据(http请求头, 请求参数…)

get请求

获取所有用户
app.get(‘/users’, function (req, res) {}
根据id获取用户(某一个用户) 带参数
app.get(‘/users/:id’, function (req, res) {}
遍历数组 forEach/filter/for in/for of/for

  1. app.get('/', function (req, res) {
  2. console.log(req)
  3. })
  1. // 1. 导入express包
  2. const express = require('express')
  3. // 2. 实例化app对象
  4. const app = express()
  5. // 3. 编写路由
  6. // 模拟数据库
  7. const db = [
  8. { id: 1, name: 'xiaoming', age: 20 },
  9. { id: 2, name: 'xiaomei', age: 18 },
  10. { id: 3, name: 'xiaopang', age: 2 },
  11. ]
  12. // 用户模块
  13. /**
  14. * 获取所有用户
  15. * GET /users
  16. */
  17. app.get('/users', function (req, res) {
  18. // 对于query参数, 使用req.query获得参数
  19. console.log(req.query)
  20. // 是一个数组
  21. res.send(db)
  22. })
  23. /**
  24. * 根据id获取用户
  25. * GET /users/:id
  26. * GET /users/1
  27. * 在req.params中形成{id: 1}
  28. */
  29. app.get('/users/:id', function (req, res) {
  30. // 通过req.params(路由参数)得到id的值
  31. // 解析get参数
  32. console.log(req.params.id) // {id: 1}
  33. // 数组的forEach. 数组的filter, for in for of
  34. for (let i = 0; i < db.length; i++) {
  35. if (db[i].id == req.params.id) {
  36. res.send(db[i])
  37. }
  38. }
  39. })

post请求

  • app.post(‘/users’, function (req, res) {}
  • 添加data end 两个事件
  • 将postdata转换成json对象
  • 给新添加的用户添加id属性
  • 将添加id后的用户添加到数据库

    1. app.post('/users', function (req, res) {
    2. // 解析请求体中的数据
    3. let postData = ''
    4. req.on('data', (data) => (postData += data))
    5. req.on('end', () => {
    6. console.log(postData)
    7. console.log(typeof postData) // string
    8. // 将postData(JSON格式的字符串) 转换成 JSON对象
    9. var user = JSON.parse(postData) // {name: 'xiaoming', age: 20}
    10. user.id = db.length + 1 // 最好使用guid(全球唯一的id, 不会重复)
    11. // 添加到db数据库
    12. db.push(user)
    13. res.send(db)
    14. })
    15. })

    put请求

  • app.put(‘/users/:id’, function (req, res) {}

  • 解析请求数据 如:id
  • 获取解析数据的属性 如:name/age
    1. - 添加data end事件
    2. - 将其转为JSON对象
  • 遍历数组
  • 查找对应id值相等的对象
  • 修改该对象的name/age等属性值,更新数组

    1. /**
    2. * 修改用户
    3. * PUT /users/:id 请求参数 {name: 'xiaoming-new', age: 21}
    4. */
    5. app.put('/users/:id', function (req, res) {
    6. // 解析请求的数据
    7. // 获取id的值
    8. const id = req.params.id
    9. // 获取name和age的值
    10. let postData = ''
    11. req.on('data', (data) => {
    12. postData += data
    13. })
    14. req.on('end', () => {
    15. const user = JSON.parse(postData)
    16. console.log(user)
    17. // 查找db数组中.id == 传递的id的对象, 更新数组
    18. db.forEach((item) => {
    19. if (item.id == id) {
    20. item.name = user.name
    21. item.age = user.age
    22. }
    23. })
    24. // 将更新后的结果返回
    25. res.send(db)
    26. })
    27. })

    delete请求

  • app.delete(‘/users’, function (req, res) {}

  • 解析请求参数
  • 遍历forEach db数组
  • 查找该参数对应在db中的数据,将其删除

array.splice(start, deleteCount) 删除数组中特定索引
satrt 索引
deleteCount 删除的个数
如: array.splice(2,3)
从数组索引为2开始删除3个数

  1. /**
  2. * 删除用户
  3. * DELETE /users/:id
  4. */
  5. app.delete('/users/:id', function (req, res) {
  6. // 解析请求参数
  7. const id = req.params.id
  8. // 查找db中的数据, 将其删除
  9. db.forEach((item, index) => {
  10. if (item.id == id) {
  11. // 数据的删除操作(第一个参数是索引index, 第二个参数是删除的个数)
  12. db.splice(index, 1)
  13. res.send(db)
  14. }
  15. })
  16. })

2) 获取请求参数

语法

  1. // get请求
  2. req.query.参数名

示例: get请求

  1. // 如果url是: /users/1, 通过params获取
  2. app.get('/users/:id', function(req, res) {
  3. res.send(req.params.id)
  4. })
  5. // 如果url是: /users?id=1, 通过query获取
  6. app.get('/users', function(req, res) {
  7. res.send(req.query.id)
  8. })

示例: post请求

  1. // 1. 导入express包
  2. const express = require('express')
  3. // 2. 实例化对象
  4. const app = express() // app是一个对象
  5. // 3. 编写路由(中间件)
  6. app.post('/', function(req, res) {
  7. let postData = ''
  8. req.on('data', data => postData += data)
  9. req.on('end', () => {
  10. res.send(JSON.parse(postData))
  11. })
  12. })
  13. // 4. 监听端口
  14. app.listen(3000, function () {
  15. console.log('server is running on http://localhost:3000')
  16. })

根据id查找对应的数据并返回
编写post.http

  1. POST http://localhost:3000/
  2. Content-Type: application/json
  3. {
  4. "name": "xiaoming"
  5. }

3) 响应对象

响应对象用于向客户端返回数据, 在处理函数中需要调用以返回数据
image.png
常用的有两个

  • res.send(): 返回各种类型
  • res.json(): 返回json格式的数据

    四. 中间件

    1 概念及作用

    概念
    中间件是在请求和响应中间的处理程序, 是一个个功能独立的函数
    作用
    扩展原始程序的插件

    2 中间件类型

    A. Application-level middleware 应用级中间件
    app.use()
    app.method()
    B. Router-level middleware 路由级中间件
    操作步骤
    1,编写routes/路由文件

    1. - **导入express包**
    2. - **创建路由对象**
    3. - **编写相关路由**
    4. - **导出路由对象**

2,在入口文件中导入路由对象
3,注册路由中间件
C. Error-handling middleware 错误处理中间件
D. Built-in middleware 内置中间件
express.json
让程序支持JSON格式的请求体
app.use(express.json( ))
express.urlencoded
让程序支持urlencoded格式的请求体
app.use(express.urlencoded( ))
E. Third-party middleware 第三方中间件
image.png

3 应用级中间件

在Express中, 使用app.use或者app.METHOD注册的中间件叫做应用级中间件
中间件就是一个函数

  1. app.use('path', function (req, res, next) {
  2. next()
  3. })

注意

在中间件中需要通过调用next()执行下一个中间件
如果不执行next(), 也没有调用send(). 这次请求将会被挂起

app.use( )

全局中间件
会给每一个路由规则都添加一个中间件处理函数
app.use( )
一般写在路由的前面

  1. // 不写第一个参数, 给所有访问都注册了一个中间件
  2. app.use(function (req, res, next) {
  3. console.log('Time:', Date.now())
  4. next()
  5. })

app.method( )

局部中间件
给一个特定的路由规则添加中间件处理函数
app.method(‘/‘, function (req, res, next) { next( ) }
在实际项目中,多用app.use( )写局部中间件

  1. app.use('/user/:id', function (req, res, next) {
  2. console.log('Request Type:', req.method)
  3. next()
  4. })
  5. app.get('/user/:id', function (req, res, next) {
  6. res.send('USER')
  7. })

示例三

可以同时注册多个中间件函数

  1. app.use('/user/:id', function (req, res, next) {
  2. console.log('Request Type:', req.method)
  3. next()
  4. }, function (req, res, next) {
  5. console.log('Request Params:', req.params.id)
  6. next()
  7. })
  8. app.get('/user/:id', function (req, res, next) {
  9. res.send('USER')
  10. })

示例四

app.use除了注册函数做为中间件外, 还可注册一个express.Router()对象

  1. const router = express.Router()
  2. app.use('/user/:id', router)

4 路由级中间件

express.Router()对象也可以注册中间件.
使用router.use或者router.METHOD注册的中间件叫做路由级中间件

  1. var app = express()
  2. var router = express.Router()
  3. router.use(function (req, res, next) {
  4. console.log('Time:', Date.now())
  5. next()
  6. })
  7. router.get('/users/', function(req, res) {
  8. res.send('hello')
  9. })

路由级中间件的应用
当路由很多的时候, 如果全部写在app入口会使用文件过大, 不好维护. 可以把不同的路由拆分成多个模块
app.js

  1. // 1. 导入express的包
  2. const express = require('express')
  3. // 2. 实例app对象
  4. const app = express()
  5. // 3. 编写路由
  6. // 用户模块 5个接口
  7. const usersRouter = require('./routes/users.js')
  8. app.use(usersRouter)
  9. // 文章模块 5个接口
  10. const articlesRouter = require('./routes/articles.js')
  11. app.use(articlesRouter)
  12. // 4. 监听端口
  13. app.listen(3000)

routes/users.js

  1. // 以/users开头的接口
  2. // 一. 导入express包
  3. const express = require('express')
  4. // 二. 创建路由对象
  5. const router = express.Router()
  6. // 三. 编写跟/users相关的路由
  7. router.get('/users', function (req, res) {
  8. res.send('users')
  9. })
  10. router.post('/users', function (req, res) {
  11. res.send('user')
  12. })
  13. // 四. 导出路由对象
  14. module.exports = router

routes/articles.js

  1. // 以/articles开头的接口
  2. // 一. 导入express包
  3. const express = require('express')
  4. // 二. 创建Router对象
  5. const router = express.Router()
  6. // 三. 编写跟article相关的路由
  7. router.get('/articles', function (req, res) {
  8. res.send('articles')
  9. })
  10. // 四. 导出router对象
  11. module.exports = router

5 内置中间件

Built-in middleware 内置中间件
express.json
让程序支持JSON格式的请求体
app.use(express.json( ))
express.urlencoded
让程序支持urlencoded格式的请求体
app.use(express.urlencoded( ))

  1. // 内置中间件
  2. // express.json()
  3. // express.urlencoded()
  4. // 中间件的作用: 扩展原始程序的插件
  5. const express = require('express')
  6. const app = express()
  7. // 让所有的路由都支持 解析请求体数据
  8. app.use(express.json()) // 让程序支持json格式的请求体
  9. app.use(express.urlencoded()) // 让程序支持urlencoded格式的请求体
  10. app.post('/users', function (req, res) {
  11. console.log(req.body)//{ name: 'xiaoming', age: 20 }
  12. })
  13. app.put('/users/:id', function (req, res) {
  14. console.log(req.body)//{ name: 'xiaoming-new', age: 21 }
  15. })
  16. app.listen(3000)

五. 数据库操作

1 安装mysql库

参照npm.mysql官方文档

  1. npm i mysql

2 入门案例

操作数据库, 就是模拟客户端. 向MySQL的服务端发送SQL语句. 基本步骤如下:

  1. 引入mysql包
  2. 创建数据库连接
  3. 连接数据库
  4. 执行SQL查询
  5. 关闭连接

image.png

  1. //1,导入mysql包(masql客户端)
  2. const { createConnection } = require('mysql');
  3. const mysql = require('mysql');
  4. const Connection = require('mysql/lib/Connection');
  5. //2,创建连接
  6. const con = mysql.createConnection({
  7. host: '127.0.0.1',
  8. port: 3306,
  9. user: 'root', //数据库用户名
  10. password: '1234',
  11. database: 'users',
  12. });
  13. //3,连接数据库
  14. con.connect()
  15. //4,执行sql语句
  16. con.query('select * from student',function(err,data){
  17. if(err){
  18. //查询错误, 抛出异常
  19. throw err
  20. }
  21. //没有异常就打印数据库服务端返回的数据
  22. console.log(data);
  23. })
  24. //5,关闭数据库连接
  25. con.end()

3 集成到express

示例
获取所有的用户

  1. // 1. 导入express包
  2. const express = require('express')
  3. // 2. 实例化app对象
  4. const app = express()
  5. // 3. 路由
  6. /**
  7. * 获取所有的用户信息
  8. */
  9. app.get('/users', function (req, res) {
  10. // 导入mysql的包
  11. const mysql = require('mysql')
  12. // 创建连接
  13. const con = mysql.createConnection({
  14. host: '127.0.0.1',
  15. user: 'root',
  16. password: '123456',
  17. database: 'user',
  18. })
  19. // 连接数据
  20. con.connect()
  21. // 执行sql语句
  22. let sql = 'select * from student'
  23. con.query(sql, function (err, data) {
  24. if (err) throw err
  25. // 返回结果
  26. res.send(data)
  27. })
  28. })
  29. // 4. 监听端口
  30. app.listen(3000)

实现 /users/:id根据id获取用户信息

  1. /**
  2. * 根据id获取用户信息
  3. * GET /users/:id
  4. */
  5. app.get('/users/:id', function (req, res) {
  6. // 一. 解析请求数据
  7. const id = req.params.id
  8. // 二. 操作数据库
  9. // 导入mysql的包
  10. const mysql = require('mysql')
  11. // 创建连接
  12. const con = mysql.createConnection({
  13. host: '127.0.0.1',
  14. user: 'root',
  15. password: '123456',
  16. database: 'user',
  17. })
  18. // 连接数据
  19. con.connect()
  20. // 执行sql语句
  21. let sql = `select * from student where id=${id}`
  22. con.query(sql, function (err, data) {
  23. if (err) throw err
  24. // 返回结果
  25. res.send(data)
  26. })
  27. })

我们发现操作数据库部分的代码是重复的.
因此, 我们需要对这部分的内容进行封装(模块化编程的思想)

4 封装mysql

在src下创建db/index.js, 编写如下内容

  1. // 封装数据操作模块
  2. // 1. 导入mysql的包
  3. const mysql = require('mysql')
  4. // 2. 创建连接
  5. const con = mysql.createConnection({
  6. host: '127.0.0.1',
  7. port: 3306,
  8. user: 'root',
  9. password: '123456',
  10. database: 'user',
  11. })
  12. // 3. 连接
  13. con.connect()
  14. // 4. 操作
  15. // 4.1 获取所有的数据
  16. // function getAll(sql, callback) {
  17. // // sql = 'select * from student'
  18. // // callback = function (abc) {console.log(abc)}
  19. // con.query(sql, function (err, data) {
  20. // if (err) throw err
  21. // // callback(data) --> 调用callback函数
  22. // //(function (abc) {console.log(abc)})(data)
  23. // callback(data)
  24. // })
  25. // }
  26. function getAll(sql) {
  27. return new Promise((resolve, reject) => {
  28. con.query(sql, function (err, data) {
  29. if (err) reject(err)
  30. resolve(data)
  31. })
  32. })
  33. }
  34. // 4.2 根据id获取单个数据
  35. function getById(sql) {
  36. return new Promise((resolve, reject) => {
  37. con.query(sql, function (err, data) {
  38. if (err) reject(err)
  39. data[0] ? resolve(data[0]) : resolve(null)
  40. })
  41. })
  42. }
  43. // 4.3 写入操作(增/删/改)
  44. function exec(sql) {
  45. return new Promise((resolve, reject) => {
  46. con.query(sql, function (err, data) {
  47. if (err) reject(err)
  48. resolve(data)
  49. })
  50. })
  51. }
  52. // 5. 导出一个对象
  53. module.exports = {
  54. getAll,
  55. getById,
  56. exec,
  57. }

封装后的操作

  1. // 1. 导入express包
  2. const express = require('express')
  3. // process是当前node的进程对象. cwd(current working directory)
  4. // 在node中不推荐使用相对路径, 相对路径 相当于 cwd()
  5. // console.log(process.cwd())
  6. // 导入db(数据库操作的包)
  7. /*
  8. db = {
  9. getAll,
  10. getById,
  11. exec,
  12. }
  13. */
  14. // const db = require('./db/index')
  15. const { getAll, getById, exec } = require('./db/index')
  16. // 2. 实例化app对象
  17. const app = express()
  18. // 处理请求体的数据. 使用express.json()中间件
  19. app.use(express.json())
  20. // 3. 路由
  21. /**
  22. * 获取所有的用户信息
  23. * GET /users
  24. */
  25. app.get('/users', function (req, res) {
  26. // 编写sql语句
  27. let sql = 'select * from student'
  28. // 执行sql语句
  29. // getAll返回一个promise对象. 调用then方法得到data数据
  30. getAll(sql).then((data) => {
  31. res.send(data)
  32. })
  33. })
  34. /**
  35. * 根据id获取用户信息
  36. * GET /users/:id
  37. */
  38. app.get('/users/:id', function (req, res) {
  39. // 一. 解析请求数据
  40. const id = req.params.id
  41. // 二. 操作数据库
  42. // 2.1 编写sql语句
  43. let sql = `select * from student where id=${id}`
  44. // 2.2 执行sql语句
  45. getById(sql).then((data) => {
  46. res.send(data)
  47. })
  48. })
  49. /**
  50. * 新增用户
  51. * POST /users {name: 'test', age: 20}
  52. */
  53. app.post('/users', function (req, res) {
  54. // 一. 解析请求数据
  55. console.log(req.body)
  56. // 对象的解构, 将body对象解构出name和age两个变量
  57. const { name, age } = req.body
  58. // console.log(name, age)
  59. // 二. 操作数据库
  60. // 2.1 编写sql语句(插入3个点: 表, 字段, 值)
  61. let sql = `insert into student (name, age) values ('${name}', ${age})`
  62. // !!!!!!!!!!!!!! 重要调试技巧. 当sql执行出错时, 打印sql, 到控制台执行
  63. console.log(sql)
  64. // 2.2 执行sql语句
  65. exec(sql).then((data) => {
  66. // 成功时返回的对象
  67. console.log(data)
  68. res.send({
  69. id: data.insertId,
  70. name, // name: name(当属性名和值相同时, 可以简写)
  71. age: age,
  72. })
  73. })
  74. })
  75. /**
  76. * 修改用户
  77. * PUT /users/:id {name:'xiaoming-new', age: 21}
  78. */
  79. app.put('/users/:id', function (req, res) {
  80. // 一. 解析请求数据
  81. const id = req.params.id
  82. // 二. 操作数据库
  83. const { name, age } = req.body
  84. // 2.1 编写sql语句(更新4个点 表, 字段, 值, 条件)
  85. let sql = `update student set name='${name}', age=${age} where id=${id}`
  86. // 2.2 执行sql语句
  87. exec(sql).then((data) => {
  88. console.log(data)
  89. // 返回. 修改后的数据
  90. res.send({
  91. id: id,
  92. name: name,
  93. age: age,
  94. })
  95. })
  96. })
  97. /**
  98. * 删除用户
  99. * DELETE /users/:id
  100. */
  101. app.delete('/users/:id', function (req, res) {
  102. // 一. 解析请求数据
  103. const id = req.params.id
  104. // 二. 操作数据库
  105. // 2.1 编写sql语句
  106. let sql = `delete from student where id=${id}`
  107. // 2.2 执行sql语句
  108. exec(sql).then((data) => {
  109. console.log(data)
  110. res.status(204).send('')
  111. })
  112. })
  113. // 4. 监听端口
  114. app.listen(3000)

5 使用async await简化

同步: 排队 (javascript就是典型的同步代码, 按顺序执行)

异步: 客户端向服务器发送请求的时候, 用户可以进行其他的操作 (互联网上对数据的操作都是异步的)

1 async介绍

// async: 异步, 写在function关键字的前面

// 同步函数
function a() {
  return 123
}

console.log(a())

// 使用async修饰函数, 使其做为一个异步函数
// 1. 可以单独使用
// 2. 让函数返回一个promise对象

async function b() {
  // Promise.resovle(123)
  return 123
}
const p = b()
// promise(只有两个属性: result/status)
console.log(p)
p.then((data) => {
  console.log(data) // 123
})

2 await介绍

// 1. await不能单独使用, 必须跟async连用. 存在于异步函数中
// 2. await关键字后面跟一个promise对象
//      关键字后面不是promise, 自动转换成promise对象
// 3. await表达式, 返回promise的结果

;(async function () {
  const p = new Promise((resovle, reject) => {
    resovle(123)
  })

  // p.then((data) => {
  //   console.log(data)
  // })
  const test = await p // 123
  console.log(test)
})()
<script>
  // async
  /*
      同步: 排队
      异步: 客户端向服务器发送请求的时候, 用户可以进行其他的操作 (互联网上对数据的操作都是异步的)
      */

  /* 1.模拟同步 */
  /* console.log(123);
        console.log(245);
        log; //执行到这里就会报错, 后面的不会执行
        console.log(666); */

  /* 2.模拟异步 */
  console.log(1);
  setTimeout(() => {
    console.log(2);
  });
  Promise.resolve(100).then((res) => {
    console.log(res);
  });
  console.log(3);
  // 打印顺序: 1-3-100-2  Promise执行的优先级别比setTimeout高

  /* 3.async异步 */
  // 如果函数前面加上async,name得到的返回值, 就是promise
  async function go() {
    return 10;
  }
  var res = go();
  console.log(res); //Promise {<fulfilled>: 10}

  /* 4.await */
  // await可以获取promise--resolve的值 (相当于调用then方法)
  // await获取promise--reject的值 可以使用 try-catch语句
  // await只能在async函数中使用
  var p = new Promise((resolve, reject) => {
    resolve(100);
  });
  async function getRes() {
    var res = await p;
    console.log(res);
  }
  getRes(); //100

  var p = new Promise((resolve, reject) => {
    reject(200);
  });
  async function getRes() {
    try {
      let res = await p;
      console.log(res);
    } catch (err) {
      console.log(err);
    }
  }
  getRes(); //200
</script>

3 进行简化

// 1. 导入express包
const express = require('express')

// process是当前node的进程对象. cwd(current working directory)
// 在node中不推荐使用相对路径, 相对路径 相当于 cwd()
// console.log(process.cwd())
// 导入db(数据库操作的包)
/* 
db = {
  getAll,
  getById,
  exec,
}
*/
// const db = require('./db/index')
const { getAll, getById, exec } = require('./db/index')
// 2. 实例化app对象
const app = express()

// 处理请求体的数据. 使用express.json()中间件
app.use(express.json())
// 3. 路由
/**
 * 获取所有的用户信息
 * GET /users
 */
app.get('/users', async function (req, res) {
  // 编写sql语句
  let sql = 'select * from student'
  // 执行sql语句
  // getAll返回一个promise对象. 调用then方法得到data数据
  // await等待promise返回结果, 将结果作为表达式的值返回
  const data = await getAll(sql)
  res.send(data)
})

/**
 * 根据id获取用户信息
 * GET /users/:id
 */
app.get('/users/:id', async function (req, res) {
  // 一. 解析请求数据
  const id = req.params.id
  // 二. 操作数据库
  // 2.1 编写sql语句
  let sql = `select * from student where id=${id}`
  // 2.2 执行sql语句
  const data = await getById(sql)
  res.send(data)
})

/**
 * 新增用户
 * POST /users {name: 'test', age: 20}
 */
app.post('/users', async function (req, res) {
  // 一. 解析请求数据
  console.log(req.body)
  // 对象的解构, 将body对象解构出name和age两个变量
  const { name, age } = req.body
  // console.log(name, age)
  // 二. 操作数据库
  // 2.1 编写sql语句(插入3个点: 表, 字段, 值)
  let sql = `insert into student (name, age) values ('${name}', ${age})`
  // !!!!!!!!!!!!!! 重要调试技巧. 当sql执行出错时, 打印sql, 到控制台执行
  console.log(sql)
  // 2.2 执行sql语句
  const data = await exec(sql)
  res.send({
    id: data.insertId,
    name: name,
    age: age,
  })
})

/**
 * 修改用户
 * PUT /users/:id {name:'xiaoming-new', age: 21}
 */
app.put('/users/:id', async function (req, res) {
  // 一. 解析请求数据
  const id = req.params.id
  // 二. 操作数据库
  const { name, age } = req.body
  // 2.1 编写sql语句(更新4个点 表, 字段, 值, 条件)
  let sql = `update student set name='${name}', age=${age} where id=${id}`
  // 2.2 执行sql语句
  await exec(sql)

  res.send({
    id: id,
    name: name,
    age: age,
  })
})

/**
 * 删除用户
 * DELETE /users/:id
 */
app.delete('/users/:id', async function (req, res) {
  // 一. 解析请求数据
  const id = req.params.id
  // 二. 操作数据库
  // 2.1 编写sql语句
  let sql = `delete from student where id=${id}`
  // 2.2 执行sql语句
  await exec(sql)

  res.status(204).send('')
})
// 4. 监听端口
app.listen(3000)