Express笔记

 1. 简介

1.1 概念

Express是一个简介灵活的node.js web应用框架,提供了一系列强大特性 帮助创建各种web应用,和丰富的工具。使用Express可以快速搭建一个完整功能的网站

1.2 本质

对之前的内置模块http进行了封装,使用更方便

1.3 核心

可以设置中间件来响应HTTP请求

定义了路由表用于执行不同的HTTP请求动作

1.4* 核心概念

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

中间件:从请求开始到响应结束这个业务流程中的所有处理环节

2. 安装使用

2.1 express安装

新建英文目录(目录名不以express开头)

进入目录 初始化(地址栏输入打开cmd:npm init -y)

在此处安装express(npm i express)

2.2 使用

新建js文件,编写代码

执行代码: node .\demo.js

//1. 导入express包
const express = require("express");
const path = require("path");
//2. 实例化对象
const app = express()
//3. 处理请求
app.get("/", function(req,res) {
    //end原生。发字符串,send什么都能发
    //res.sendFile(path.join(__dirname, "../file/news.html"))
  	res.send("<h1>Hello</h1>");
})
app.get("*", function(req,res) {
    res.send("其它路径!")
})
//4. 设置端口
app.listen(3000, () => {console.log("访问地址:http://localhost:3000");})

2.3 express集成nodemon

1. 修改package.json的script脚本

        "dev": "nodemon src/index.js"

2. 使用 npm run dev 执行代码

2.4 区别(对比http创建web服务)

不需要处理乱码问题

不需要判断请求方式

2.5 res.send()与res.end()

end:原生http模块方法 express也支持。只能传字符串,不能处理乱码问题

send:express中封装的方法。可以传任何类型,可以处理乱码问题

3. Express路由

3.1 概念

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

3.2 语法

app.请求方式(访问路径, 处理函数)

        请求方式:get,post,put,delete

        访问路径:也可以正则( * 通配符)

        处理函数:匿名函数,匹配未列举的路径

3.3 注意事项

匹配顺序:从上到下 ↓

请求方式和访问路径同时匹配成功,express会将请求转移到对应的处理函数处理

4. 跨域请求问题

从一个请求跳到另外一个请求,协议/域名/端口 只要有一个不同,即为跨域请求

解决: res.setHeader('Access-Control-Allow-Origin','*') //允许跨域请求

5. Express增删改查

5.1 查询 app.get()

查询所有 http://localhost:3000/users            后台: /users 直接返回数组

查询一个 http://localhost:3000/users?id=1   后台: /users 通过req.query获取参数

查询一个 http://localhost:3000/users/1         后台 /users/:id 通过req.params获取参数

5.2 新增 app.post()

前台

http://localhost:3000/users application/json {"name":"赵六","age":26}

后台

        获取请求体数据

        设置新增用户的id

        把新增的用户添加到数组

5.3 修改 app.put()

前台

http://localhost:3000/users/1 application/json {"name":"赵六","age":26}

后台

        获取要修改元素的id

        获取请求体数据

        查找id相同的元素进行修改

5.4 删除 app.delete()

前台

http://localhost:3000/users/1

后台

        获取要修改元素的id

        查找id相同的元素进行删除

🟢 代码

//1. 引入模块
const express = require("express");
//2. 创建server服务
const app = express();

const db = [
    {id:1, name:"张三", age:23},
    {id:2, name:"李四", age:24},
]
//3. 处理请求
//查全部
app.get("/users", function(req, res) {
    //解决跨域请求
    res.setHeader("Access-Control-Allow-Origin", "*")
    res.send(db);
})
//查一个query
app.get("/users", function(req, res) {
    //解决跨域请求
    res.setHeader("Access-Control-Allow-Origin", "*")
    //获取id
    db.forEach(item => {
        if (item.id == req.query.id){
            res.send(item);
        }
    });
})
//查一个params
app.get("/users/:id", function(req, res) {
    //解决跨域请求
    res.setHeader("Access-Control-Allow-Origin", "*")
    //获取id
    db.forEach(item => {
        if(item.id == req.params.id){
            res.send(item);
        }
    })
})

//增
app.post("/users", function(req, res) {
    //解决跨域请求
    res.setHeader("Access-Control-Allow-Origin", "*")
    let postData = "";
    req.on("data", data => postData += data)
    req.on("end", () => {
        let item = JSON.parse(postData);
        item.id = db.length + 1;
        db.push(item);
        res.send(db)
    })
})
//删
app.delete("/users/:id", function(req,res) {
    //解决跨域请求
    res.setHeader("Access-Control-Allow-Origin", "*")
    db.forEach((item, index) => {
        if (item.id == req.params.id) {
            db.splice(index, 1)
        }
    })
    res.send(db)
})
//改
app.put("/users/:id", function(req, res) {
    //解决跨域请求
    res.setHeader("Access-Control-Allow-Origin", "*")
    let getData = "";
    req.on("data", data => getData += data)
    req.on("end", () => {
        db.forEach(item => {
            let user = JSON.parse(getData); //??
            if (item.id == req.params.id) {
                item.name = user.name;
                item.age = user.age;
            }
        })
        res.send(db)
    })
})
//4. 设置端口
app.listen(3000, () => { console.log(" http://localhost:3000"); })

6. 中间件

6.1 抽取及中间件简化

中间件函数

概念(middieWare)

        指业务流程的中间处理环节,本质是一个function处理函数

调用流程

        当一个请求到达express服务器之后,可以连续调用多个中间件,对请求进行预处理

分类

        按作用范围

                局部生效中间件

                全局生效中间件

        按级别分

                express内置中间件

                第三方 如:处理跨域请求

                        应用级中间件

                        路由级中间件

注意

        中间件函数形参列表中必须含next参数,与路由处理函数不同(路由只包含req、res)

        next作用:实现多个中间件连续调用,把流转关系移交到下一个中间件 或 处理函数。(接力棒)

6.2 中间件的范围划分

局部生效中间件

概念:只在某些访问路径中使用

举例:getPostData中间件,只在新增与修改 的路由中生效,处理请求时要将中间件函数名写在参数中

// 定义中间件函数m1
const m1 = function(req,res,next){
  console.log('这是中间件m1');
  next()  // 以next结尾
}
app.get("/index", m1, m2, function(req, res) {}) //连用中间件

注意

        要在路由前注册中间件

        客户端发来的请求,可以连续调用多个中间件处理

        执行完中间件业务代码后,务必调用next()!

        防止代码逻辑混乱,以next()结尾

        连续调用多个中间件,共享req和res对象

全局生效中间件

        概念:客户端发起的任何请求,到达服务器都会触发的中间件

        使用:使用app.use(中间件函数) 来定义全局中间件

6.3 🟡中间件的级别划分

内置中间件

概念:由express官方提供,常见3个

分类:

        express.json 解析json格式的请求体数据

        express.urlencoded 解析url-encode格式的请求体数据

        express.static 快速托管静态资源,可以帮助加载html文件、css样式、图片

使用:

        app.use(express.json())

        app.use(express.urlencoded())

        app.use(express.static(path.join(__dirname,"../../file/")))

        引入内置中间件:注册托管静态资源的中间件 将在file文件夹下的静态进行托管

        效果: http://localhost:3000/new.html 可以直接加载

        index.html不必输入文件名 http://localhost:3000

第三方中间件

        概念:第三方个人/团队开发,使用前需下载

        分类:cors() 处理跨域请求

使用

        下载:npm i cors

        导包:const cors = require("cors")

        引入:app.use(cors())

原理:每个响应中添加响应头

应用级中间件

        概念:通过app.use() app.get() app.post()绑定到app实例上的

        注意:应用及中间件,可以全局可以局部,但都要绑定到app实例上

路由级中间件

        概念:绑定到路由对象(express.router()创建的)中间件

        注意:路由级中间件用处不是很多,了解

6.4 🟢模块化路由

产生的原因

        1. 路由很多时,若全都卸载app入口文件,文件太大不好维护

        2. 项目中有不同类型的请求路径(用户相关,商品相关),都放在一个文件中不好维护

        3. 为了便于对路由进行模块化管理,express不建议将路由直接挂在在app上(建议将路由抽成单独模块)

使用步骤

        1. 创建路由模块对应的js文件,放在routes文件夹下

        2. 调用express.router()创建路由器对象

        3. 向路由对象挂载具体路由

        4. 使用module.exports向外共享路由对象

        5. 在入口文件中使用app.use() 注册路由模块

代码

        调用 http://localhost:3000/goods/list

//导入express包
const express = require("express");

//实例化express对象
const app = express()

//导入路由模块
const goodsRouter = require("../routes/goods");
const usersRouter = require("../routes/users");

//注册各个路由模块
app.use("/goods", goodsRouter)
app.use("/users", usersRouter)

//设置监听端口
app.listen(3000, () => {
    console.log("运行在: http://localhost:3000");
})
//导入express包
const express = require("express");

//使用express创建路由对象
const router = express.Router()

//向router挂在具体路由
router.get("/list", function(req, res) {
    res.send("商品列表页")
})
router.get("/add", function(req, res) {
    res.send("商品添加页")
})

//导出路由对象(对外共享
module.exports = router

7. 数据库操作

7.1 node连接数据库

报错解决:

alter user 'root'@'localhost' identified with mysql_native_password by '1234';

Error: ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by serv_畱䶒的博客-CSDN博客

7.2 增删改查(数组实现,优化)

//使用内置中间件处理请求体
app.use(express.json());
app.use(express.urlencoded());
//使用第三方中间件处理跨域问题 --需下载安装
app.use(cors());

7.3 增删改查(数据库实现)

思路

        1. 导包、创建连接、连接,三个步骤拷贝进去

        2. 在路由里 编写sql语句,执行并返回数据

7.4 增删改查(提取数据库操作)

目的:将数据库操作的代码单独放到一个文件中,便于后期代码维护

做法

        1. 将数据库导包、创建连接、连接 代码剪切进一个js文件中

        2. 提供查询所有getAll 查询单个getById 增删改exec方法,方法里用promise封装

        3. 导出这三个方法

        4. 在后台代码中导入js文件,解构这三个方法并使用

模块导出简写:

//导出对象
module.exports = {
    getAll: getAll,
    getById: getById,
    exec: exec,
};
//属性名和属性值相同,可简写为一个
module.exports = {
    getAll,
    getById,
    exec,
};
//引入:const {getAll, exec}= require("./引入.js")

8. ES7 语法糖(async_await)

8.1 async 异步

作用:将同步函数变成异步函数(返回promise对象),就可以使用then() 调用

使用:

//定义
async function m1() {
    return 222;
}
//调用
const p = m1()
p.then((data) => {
    console.log(data); //222
});

8.2 await 等待

作用:await可以等待后面的 promise对象执行后,拿到返回的结果

注意:

        1. await不能单独使用,必须跟async连用,存在于异步函数中

        2. await后面必须跟一个promise对象,如果不是promise对象,自动转成promise对象

        3. await表达式,返回的是promise执行后的结果

使用:

//在外面套一个异步函数壳,或将外层函数添加async关键字改为异步
async function fn() {
    async function m1() {
        return 222;
    }
    //await 等待m1返回的promise对象执行完后,拿到返回的值
    const res = await m1(); 
    console.log(res);
}
fn();

8.3 增删改查await改写

app.get("/users", async function(req, res) {
    let sql = 'select * from student';
    const data = await exec(sql);//执行SQL语句
    res.send(data);//发给浏览器
})

9. 错误处理机制

throw "错误信息"
try{ 
     //可能会出问题的代码
} catch (err) { 
     //出问题的处理方案
}

10. 🟢用户管理系统搭建

10.1 思路

1. 需求分析(系统框架、具体业务分析)

2. 技术方案

        数据库设计

        设计接口

                前台:发送请求的url,需要的参数

                后台:返回数据的格式

3. 技术实现(编写代码)

        先写后端(express脚手架快速生成)再写前端

10.2 用户管理系统搭建

1. 全局安装脚手架(项目生成器) npm i express-generator -g

2. 创建项目文件夹,执行命令生成后端目录  express --no-view backEnd

        在目录下创建一个`backEnd`的目录, 作为后端项目的目录

        `--no-view`: 创建一个数据服务, 不提供页面服务

3. 在后端目录安装相关依赖(cd backEndnpm i

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

4. 启动项目

        1)npm i nodemon -D

                将nodemon作为开发时的依赖安装(会在package.json中, 生成devDependencies)

        2)修改启动脚本: package.json>"scripts">"start": "nodemon ./bin/www"

        3)安装mysql和cors包(npm i mysqlnpm i cors

                安装好后会自动添加在package.json

        4)执行 npm run start 可以在3000端口看到 express脚手架欢迎页面

        5. 导入数据库操作模块

                将写好的db文件夹拷贝到backEnd

                在routes/users.js中导入模块

//1. 导入mysql包
const mysql = require("mysql");

//2. 创建连接,数据库参数可以放到配置文件中(config/index.js)
var con = mysql.createConnection({
    host: "localhost",
    port: 3306,
    user: "root",
    password: "1234",
    database: "db01",
    timezone: "SYSTEM",
});

//3. 连接数据库
con.connect();

//4. 查询所有(获取查询的数据)
function getAll(sql) {
    return new Promise((resolve, reject) => {
      	//执行sql语句
        con.query(sql, (err, data) => {
            //有错,把失败的数据带回去
            if (err) reject(err);

            //将获取到的数据带回去
            resolve(data);
        });
    });
}

//5. 查询一个(获取查询的数据)
function getById(sql) {
    return new Promise((resolve, reject) => {
      	//执行sql语句
        con.query(sql, (err, data) => {
            //有错,把失败的数据带回去
            if (err) reject(err);

            //将获取到的数据带回去
            //易报错!
            resolve(data[0] ? data[0] : null);
        });
    });
}

//6. 管理(增删改)
function exec(sql) {
    return new Promise((resolve, reject) => {
      	//执行sql语句
        con.query(sql, (err, data) => {
            //有错,把失败的数据带回去
            if (err) reject(err);

            //将获取到的数据带回去
            resolve(data);
        });
    });
}

//导出方法
/* module.exports = {
    getAll:getAll,
    getById:getById,
    exec:exec
} */
//属性名和属性值相同,可简写为一个
module.exports = {
    getAll,
    getById,
    exec,
};

6. 导入跨域请求模块

        在app.js中导入 const cors = require("cors");

        在app.js中注册 app.use(cors()) 注册路由之前

10.3 后端编写流程

1. 在用户【路由模块】users.js下编写代码

2. 编写获取所有用户,使用get请求,调用getAll()方法,返回所有用户的数组(data)

3. 编写获取一个用户,使用get请求,调用getById()方法,返回指定id的用户(data)

4. 编写新增一个用户,使用post请求,调用exec()方法,返回新增的用户(data.insertId)

5. 编写修改一个用户,使用put请求,调用exec()方法,返回新增的用户(无需data)

6. 编写删除一个用户,使用delete请求,调用exec()方法,设置状态码,返回空字符串(无需data)

        es.status(204).send("")

var express = require('express');

//导入数据库操作模块
const {getAll, getById, exec} = require("../db");

var router = express.Router();

// 获取所有用户
router.get('/', async function(req, res, next) {
  let sql = "select * from users";
  res.send(await getAll(sql))
});

// 获取一个用户
router.get('/:id', async function(req, res, next) {
  let sql = `select * from users where ${req.params.id} = id`;
  res.send(await getById(sql))
});

// 添加一个用户
router.post('/', async function(req, res, next) {
  let {name, age} = req.body;
  let sql = `insert into users (name, age) values("${name}", ${age}) `;
  let data = await exec(sql)
  res.send({
    id: data.insertId,
    name,
    age
  })
});

// 修改一个用户
router.put('/:id', async function(req, res, next) {
  let {name, age} = req.body;
  let sql = `update users set name = "${name}", age = ${age} where id = ${req.params.id}`;
  res.send({
    id: req.params.id,
    name,
    age,
    data: await exec(sql),
  })
});

// 删除一个用户
router.delete('/:id', async function(req, res, next) {
  let sql = `delete from users where id = ${req.params.id} `;

  let data = await exec(sql)
  //设置状态码
  res.status(204).send("")
});

module.exports = router;

10.4 前端编写流程

查询(显示所有用户)

1. 新建 fontEnd 文件夹

2. 新建3个html页面

3. 编写list.html页面的骨架

4. 编写基本样式base.css

5. 编写list页面样式style.css

6. 引入jquery,发送ajax请求(已经引入了cors处理跨域请求)

7. 遍历获取到的数据,动态拼接 tr 元素,追加到table下面

<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>
    $.ajax({
      url: "http://localhost:3000/users",
      type: "GET",
      success: function (data) {
        console.log(data); //js数组

        //遍历数组
        data.forEach((item) => {
          // console.log(item);
          const tr = `<tr>
                      <td>${item.id}</td>
                      <td>${item.name}</td>
                      <td>${item.age}</td>
                      <td>
                        <a href="./edit.html?id=${item.id}" class="edit-btn">修改</a>
                        <a href="#" onclick="delUser(${item.id})">删除</a>
                      </td>
                    </tr>`;
          $(".user-list").append(tr);
        });
      },
    });

    //删除
    function delUser(id) {
      console.log(id);
      $.ajax({
        url: "http://localhost:3000/users/" + id,
        type: "DELETE",
        success: function (res) {
          console.log(res);
          alert("删除成功");
          location.reload();
        },
      });
    }
  </script>
</body>

新增

1. 编写add.html页面骨架

2. 在style.css中,添加add.html的样式

3. 监听add按钮的点击,在点击事件中获取用户输入的姓名与年龄进行判断

4. 输入为空,直接返回。否则用ajax发送post请求,提交到后台,修改数据库中数据

5. 修改成功,弹出提示,跳转回list.html页

<body>
  <h1>添加用户</h1>
  <div class="container">
    <ul>
      <li>
        <label for="userName">用户名</label>
        <input type="text" name="userName" id="userName" placeholder="请输入用户名" />
      </li>
      <li>
        <label for="userAge">年龄</label>
        <input type="text" name="userAge" id="userAge" placeholder="请输入年龄" />
      </li>
    </ul>
    <button class="submit-btn">提交</button>
  </form>

    <script>
      $(".submit-btn").click(function () {
        const name = $("#userName").val().trim()
        const age = $("#userAge").val().trim()

        //判断
        if (name == "" || age == "") {
          alert("用户名或年龄不能为空")
          return
        }

        //发送异步请求
        $.ajax({
          url: "http://localhost:3000/users",
          type: "POST",
          data: { name, age },
          success: function (res) {
            alert("添加成功")
            location.href = "./list.html";
          },
        });
      });
    </script>
</body>

修改

1. 编写edit.html骨架

2. 在list.html中为 修改a标签 的href拼接id属性

   `href="./edit.html?id=${item.id}"`

         动态绑定

3. 在edit.html页获取路径携带的id值

    window.location.search.replace('?','').split('=')[1]

4. 用ajax发送get请求,把根据id查找到的值回显到表单中

   $('#age').val(res.age)

5. 为按钮添加点击事件,获取用户输入的名字年龄,为空直接返回,否则用ajax发送put请求,提交到后台 修改数据库中数据

6. 修改成功,弹出提示,跳转到list.html页面

<body>
<h1>修改用户</h1>
<div class="container">
  <ul>
    <li>
      <label for="userName">用户名</label>
      <input type="text" name="userName" id="userName" placeholder="请输入用户名" />
    </li>
    <li>
      <label for="userAge">年龄</label>
      <input type="text" name="userAge" id="userAge" placeholder="请输入年龄" />
    </li>
  </ul>
  <button class="submit-btn">修改</button>
  </form>

  <script>
    const id = location.search.replace("?", "").split("=")[1]

    $.ajax({
        url: "http://localhost:3000/users/" + id,
        type: "GET",
        success: function (res) {
          console.log(res);
          //回显数据(设置input里的值)
          // alert("查找成功")
          $("#userName").val(res.name)
          $("#userAge").val(res.age)
        },
    });

    $(".submit-btn").click(function () {
      const name = $("#userName").val().trim()
      const age = $("#userAge").val().trim()

      //判断
      if (name == "" || age == "") {
        alert("用户名或年龄不能为空")
        return
      }

      //发送异步请求
      $.ajax({
        url: "http://localhost:3000/users/" + id,
        type: "PUT",
        data: { name, age },
        success: function (res) {
          console.log(res);
          //回显数据(设置input里的值)
          alert("修改成功")
          location.href = "./list.html";
        },
      });
    });
  </script>
</body>

删除

1. 在list.html页 为删除a标签 添加点击事件,传入id

2. 弹出确认框

3. 用ajax发送delete请求,删除数据库中数据

4. 删除成功,刷新

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

假以时日♪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值