一. 需求分析

1 系统框架

选择前后端分离的系统架构

Express框架应用-实现用户模块 - 图1

2 具体的业务需求

  1. 有一个页面, 可以展示用户的列表
  2. 有一个页面, 可以添加用户信息
  3. 有一个页面, 可以修改用户信息
  4. 点击删除按钮, 可以删除用户信息

Express框架应用-实现用户模块 - 图2

二. 技术方案

1 数据库设计

用户表 (users)

字段名 类型 备注
id int 主键, 自增
name varchar(255) 用户的姓名
age tinyint unsigned 用户的年龄

使用Navicate建表Express框架应用-实现用户模块 - 图3

2 接口设计

1) baseURL

  1. http://localhost:3000

2) 用户模块

获取所有用户

请求

请求方式: GET
请求URL: /users

GET /users

响应

[
  {
    "id": 1,
    "name": "xiaoming",
    "age": 20
    },
  {
    "id": 2,
    "name": "xiaomei",
    "age": 18
    },
]

根据id获取单个用户

请求

请求方式 GET
请求地址 /users/:id

GET /users/:id
GET /users/1

响应

{
  "id": 1,
  "name": "xiaoming",
  "age": 20
}

添加用户

请求

请求方式 POST
接口地址 /users

POST /users

请求参数

{
    "name": "xiaoming",
    "age": 20
}

响应

{
  "id": 1,
  "name": "xiaoming",
  "age": 20
}

修改用户

请求

请求方式 PUT
请求地址 /users/1

PUT /users/:id
PUT /users/1

请求参数

{
    "name": "xiaoming-new",
    "age": 200
}

响应

{
  "id": 1,
  "name": "xiaoming-new",
  "age": 200
}

删除用户

请求

请求方式 DELETE
请求地址 /users/:id

DELETE /users/:id
DELETE /users/1

响应

三. 技术实现

1 后端

1) 项目搭建

安装express脚手架

执行命令, 全局安装脚本架(也称为项目生成器)

npm i express-generator -g

安装完成后, 在全局会多一个命令

express

通过脚手加搭建项目

在根目录下, 执行命令

express --no-view backEnd
  • 在目录下创建一个backEnd的目录, 作为后端项目的目录
  • --no-view: 创建一个数据服务, 不提供页面服务

安装相关依赖

进入backEnd目录, 执行命令, 根据package.jsoon中的依赖项, 安装项目所有的依赖
image.png

  • cookie-parser: 解析cookie的中间件
  • debug: 调试代码的中间件
  • express: express框架包
  • morgan: 记录日志的中间件
npm install

启动项目

使用nodemon启动项目,
nodemon作为开发时依赖安装

npm i nodemon -D

会在package.json中, 生成devDependencies

"devDependencies": {
  "nodemon": "^2.0.15"
}

修改pagckage.json中的脚本

"scripts": {
  "start": "nodemon ./bin/www"
},

执行

npm run start

使用浏览器测试

Express框架应用-实现用户模块 - 图5

2) 实现获取所有用户

编写router/users.js文件

router.get('/', (req, res) => {
  // 一. 编写sql语句
  // 二. 执行sql语句, 获得结果
  // 三. 返回数据
})

安装mysql包

npm i mysql

复用数据库操作模块

Express框架应用-实现用户模块 - 图6

修改配置Express框架应用-实现用户模块 - 图7

导入db模块Express框架应用-实现用户模块 - 图8

示例

const { getAll, getById, exec } = require('../db')
// 编写接口
// GET /users
router.get('/', async (req, res) => {
  // 一. 编写sql语句
  let sql = 'select * from users'
  // 二. 执行sql语句, 获得结果
  const users = await getAll(sql)
  // 三. 返回数据
  res.send(users)
})

测试

创建test/users.http测试文件

@baseURL = http://localhost:3000

###
GET {{baseURL}}/users

Express框架应用-实现用户模块 - 图9

3) 实现根据id获取单个用户

// 根据id获取单个用户
// GET /users/:id -> {}
router.get('/:id', async (req, res) => {
  // 一. 解析参数
  let { id } = req.params

  // 二. 操作数据库
  let sql = `select * from users where id=${id}`
  const user = await getById(sql)

  // 三. 返回结果
  res.send(user)
})

测试Express框架应用-实现用户模块 - 图10

4) 实现添加用户

// 添加用户
// POST /users {"name":"test", "age":20}
router.post('/', async (req, res) => {
  // 一. 解析参数
  const { name, age } = req.body
  // 二. 操作数据库
  let sql = `insert into users (name, age) values ('${name}', '${age}')`
  // console.log(sql)
  const resData = await exec(sql)
  //console.log(resData)
  // 三. 返回结果
  res.send({
    id: resData.insertId,
    name, // name: name
    age, // age: age
  })
})

测试Express框架应用-实现用户模块 - 图11

5) 实现修改接口

// 修改用户
// PUT /users/:id {"name":"test-new", "age":30}
router.put('/:id', async (req, res) => {
  // 一. 解析参数
  let { id } = req.params
  let { name, age } = req.body
  // 二. 操作数据库
  let sql = `update users set name='${name}', age='${age}' where id=${id}`
  const resData = await exec(sql)
  // 三. 返回结果
  console.log(resData)
  res.send({
    id,
    name,
    age,
  })
})

测试Express框架应用-实现用户模块 - 图12

6) 实现删除接口

// 删除用户
router.delete('/:id', async (req, res) => {
  // 一. 解析参数
  let { id } = req.params
  // 二. 操作数据库
  let sql = `delete from users where id = '${id}'`
  await exec(sql)
  // 三. 返回结果
  res.status(204).send('')
})

测试Express框架应用-实现用户模块 - 图13

2 前端

前后端交互流程图
点击查看【processon】
用户模块-交互过程.png

1) 创建index.html

编写页面结构

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>用户列表</title>
  </head>
  <body>
    <h1>用户列表</h1>
    <div class="container">
      <a href="./add.html" class="add-btn">添加用户</a>
      <table class="user-list">
        <tr>
          <th>id</th>
          <th>name</th>
          <th>age</th>
          <th>操作</th>
        </tr>
      </table>
    </div>
  </body>
</html>

编写样式

* {
  margin: 0;
  padding: 0;
}

a {
  text-decoration: none;
}
table,
th,
td {
  border: 1px solid #000;
}
.container {
  width: 80%;
  padding: 20px 50px;
}
.container .add-btn {
  /* 第一段: position display */
  display: inline-block;

  /* 第二段: 盒子模型 margin padding border width height */
  padding: 12px 20px;
  border: 1px solid #169bd5;

  /* 第三段: 背景相关 */
  background-color: #ecf5ff;
  /* 第四段: 文本相关 */
  color: #169bd5;
  line-height: 1;
  text-align: center;
  cursor: pointer;

  /* 第五段: CSS3新增属性 */
  border-radius: 5px;
  box-sizing: border-box;
  transition: all 0.2s;
}
.container .add-btn:hover {
  background-color: #fff;
  color: #169bd5;
}
.container .user-list {
  margin-top: 20px;
  width: 500px;
  border: 1px solid #000;
  border-spacing: 0px;
  border-collapse: collapse;
  text-align: center;
}

.form-item {
  margin: 20px auto;
}

.form-item input {
  padding: 0 15px;
  border: 1px solid #dcdfe6;
  height: 40px;

  color: #606266;
  outline: none;
  transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
  border-radius: 4px;
}

.form-item input:focus {
  border-color: #409eff;
}

编写js

引入jquery, 使用npm下载. 使用离线版文件

<script src="./lib/jquery.min.js"></script>

发送ajax请求

// 调用接口(获取所有用户)
$.ajax({
  url: 'http://localhost:3000/users',
  type: 'GET',
  success: function (res) {
    console.log(res)
  },
})

发现报错:
Express框架应用-实现用户模块 - 图15

原因

发生了跨域请求

跨域请求

  1. 由于浏览器同源策略导致跨域问题
  2. 当浏览器从一个域向另一个域发送请求时, 它认为这种请求不安全, 不允许发送

域 = 协议 + 域名 + 端口

最常用的解决方案

在服务端开启CORS, 在服务端回复的响应头中, 加入特殊的头信息, 允许浏览器发送跨域请求
在后端安装cors中间件
https://www.npmjs.com/package/cors

npm i cors

在app.js中导入cors中间件

const cors = require('cors')

全局注册cors()中间件

app.use(cors())

改造前台

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>用户列表</title>
    <link rel="stylesheet" href="./css/reset.css" />
    <link rel="stylesheet" href="./css/index.css" />
    <script src="./lib/jquery.min.js"></script>
  </head>
  <body>
    <h1>用户列表</h1>
    <div class="container">
      <a href="./add.html" class="add-btn">添加用户</a>
      <table class="user-list">
        <tr>
          <th>id</th>
          <th>name</th>
          <th>age</th>
          <th>操作</th>
        </tr>
      </table>
    </div>
    <script src="./js/index.js"></script>
  </body>
</html>
// 通过jquery发送ajax请求. 调用接口, 获取数据
$.ajax({
  url: 'http://localhost:3000/users',
  type: 'GET',
  success: function (res) {
    // 发送请求, 获取的数据存放在res里
    console.log(res)

    // 遍历res数组
    res.forEach((item) => {
      // 渲染table表格
      let str = `<tr>
                  <td>${item.id}</td>
                  <td>${item.name}</td>
                  <td>${item.age}</td>
                  <td>
                    <a href="./edit.html">修改</a>
                    <a href="#">删除</a>
                  </td>
                </tr>`

      $('.user-list').append(str)
    })
  },
})

2) 创建add.html

编写页面结构

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>添加用户</title>
    <link rel="stylesheet" href="./css/reset.css" />
    <link rel="stylesheet" href="./css/index.css" />
  </head>
  <body>
    <h1>添加用户</h1>
    <div class="container">
      <div class="form-item">
        用户名:
        <input type="text" id="name" name="name" placeholder="请输入用户名" />
      </div>
      <div class="form-item">
        年龄:
        <input type="text" id="age" name="age" placeholder="请输入年龄" />
      </div>
      <button id="btn" class="add-btn">添加</button>
    </div>
  </body>
</html>

编写样式

.form-item {
  margin: 20px auto;
}
.form-item input {
  padding-left: 15px;
  border: 1px solid #dcdfe6;
  height: 40px;

  color: #606266;
  outline: none;
  cursor: pointer;

  border-radius: 4px;
  transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
}
.form-item input:focus {
  border-color: #409eff;
}

编写js

3) 创建edit.html

修改入口

$.ajax({
  url: 'http://localhost:3000/users',
  type: 'GET',
  success: function (res) {
    // console.log(res)
    // 遍历res数组
    // 创建一个tr元素, 追加到表格的最后
    res.forEach((item) => {
      const tr = `<tr>
                    <td>${item.id}</td>
                    <td>${item.name}</td>
                    <td>${item.age}</td>
                    <td>
                      <a href="./edit.html?id=${item.id}">修改</a>
                      <a href="#" onclick="handleDel(${item.id})">删除</a>
                    </td>
                  </tr>`
      $('.user-list').append(tr)
    })
  },
})

编写页面

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>修改用户</title>
    <!-- 二. 编写样式 -->
    <link rel="stylesheet" href="css/reset.css" />
    <link rel="stylesheet" href="css/list.css" />
    <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
  </head>
  <body>
    <!-- 一. 编写HTML结构 -->
    <h1>修改用户</h1>
    <div class="container">
      <div class="form-item">
        用户名:
        <input
               type="text"
               id="username"
               name="username"
               placeholder="请输入用户名"
               />
      </div>
      <div class="form-item">
        年龄:
        <input type="text" id="age" name="age" placeholder="请输入年龄" />
      </div>
      <button id="btn" class="add-btn">提交</button>
    </div>
    <script>
      // 三. 发送ajax请求, 根据id查找用户的信息
      // console.log(window.location)
      // console.log(window.location.search)
      // console.log(window.location.search.replace('?', ''))
      // console.log(window.location.search.replace('?', '').split('='))
      // console.log(window.location.search.replace('?', '').split('=')[1])
      const id = window.location.search.replace('?', '').split('=')[1]
      $.ajax({
        type: 'GET',
        url: 'http://localhost:3000/users/' + id,
        success: function (res) {
          console.log(res)
          // 设置input的值
          $('#username').val(res.name)
          $('#age').val(res.age)
        },
      })

      // 绑定btn的click事件
      $('#btn').click(function () {
        // 获取input新输入的值
        const name = $('#username').val()
        const age = $('#age').val()

        if (name == '' || age == '') {
          alert('用户名密码不能为空')
          return
        }

        // 发送put请求
        $.ajax({
          type: 'PUT',
          url: 'http://localhost:3000/users/' + id,
          data: { name, age },
          success: function (res) {
            alert('更新成功')
            window.location.href = './index.html'
          },
        })
      })
    </script>
  </body>
</html>

4) 实现删除

// 处理删除
function handleDel(id) {
  // 通过id参数得到 要删除的 数据的id
  $.ajax({
    type: 'DELETE',
    url: 'http://localhost:3000/users/' + id,
    success: function (res) {
      window.location.href = './index.html'
    },
  })
}