Node.js

什么是Node.js

Node.js的定义

  • Node.js 是一个基于Chrome V8引擎 的 JavaScript 运行时

Node.js环境与浏览器环境的区别

  • 浏览器端:

    • ECMAScript
    • BOM
    • DOM
  • NoeJS端:

    • ECMAScript

    • 内置模块(fs, http, path等)

    • 第三方模块`(别人开发的模块)

    注意:NodeJS中没有DOM,也没有BOM,也没有window对象。

    浏览器是JS的前端运行环境,Node.js是JS的后端运行环境

下载安装 Node.js 环境

  1. 下载对应版本的安装包(https://nodejs.org/zh-cn/)
    注意:
    1.win10 可以随意安装任何版本的Node
    2.但是win7只能安装12及其以下的版本Node

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TqLy1zJB-1632398276317)(images/01.png)]

  2. 点击下载到的安装包,一路下一步默认安装
    注意:
    1.不能安装到中文目录如d:/软件,建议一直点击next即可
    2.安装完成之后, 它不会在桌面出现快捷图标

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1tpichw3-1632398276328)(images/02.png)]

  3. 打开小黑窗输入 node -v 能看到版本号表示安装成功
    在任意文件夹中最上方的路径中输入cmd后回车即可打开

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QMFTj7Vy-1632398276330)(images/03.png)]

小黑窗打开方式

  • 小黑窗: 命令行工具

  • window系统打开的几种方式:

    1. 按 windows + R 运行窗口中输入cmd 回车即可打开

    2. 在任意目录的最上方路径输入框中输入 cmd 回车接口打开 (推荐

    3. 在任意目录中按住 shift键 + 鼠标右键后在弹出菜单中点击 在此处打开命令窗口 或 在此处打开PowerShell窗口即可打开

    4. 在VSCode中,任意一个js文件上鼠标右键,选择在 集成终端中打开

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VRCOEG1O-1632398276331)(images/04)]

  • 苹果电脑: https://jingyan.baidu.com/article/375c8e1969b5f065f3a22967.html

常用的命令及按键

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iPiPWm9v-1632398276332)(images/05)]

fs 核心模块

导入核心模块

//const 变量名(自己随意取) = require('核心模块名')

// 导入核心模块  文件读写模块 fs 对象
const fs = require('fs');

console.log(fs);

同步读取文件

fs.readFileSync ( path,utf8编码 )

  • 语法:let res = fs.readFileSync(path[, options])

  • 参数:

    • path,读取文件的路径(相对路径或绝对路径)
    • options:读取文件的参数配置,通常用一个utf8字符串表示即可
  • 注意:读取文本内容文件时,utf8参数要加上,不然打印出来的是一个Buffer二进制内容

使用try{}catch{}处理同步读取文件的错误

  • try catch语法: try{ 放有可能出错的代码 } catch(err){ 报错后执行的代码,通常是输出错误 }
  • 处理同步读取文件的错误

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CSV4On3a-1632398276334)(images/08)]

// 引入核心模块
const fs = require('fs');

// try 里面放可能会出错的程序
// catch 捕获 try里面的程序出错了  catch会触发 里面做错误处理

try {
    // 开始同步读取文件
    const data = fs.readFileSync('./txt/1.txt', 'utf-8');
    console.log('-------------------------------------');
    console.log('同步读取文件');
    console.log(data);
    console.log('-------------------------------------');
} catch (err) {
    console.log('==================================================');
    console.log('发送邮件,错误处理');
    console.log(err);
    console.log('==================================================');
}


异步读取文件

fs.readFile ( path , utf8编码 , 回调函数 )

  • 语法:fs.readFile(path[, options], callback)

  • 参数:

    • path: 读取文件的路径(相对路径或绝对路径 - 必填
    • options:读取文件的参数配置,通常用一个utf8字符串表示即可 - 选填
    • callback: 读取完毕的回调函数(err,data)=>{} - 必填
  • (err,data)=>{ } 中有两个参数

    • 参数1:err 代表读取文件出错后的错误对象
    • 参数2:data 代表读取文件成功后的内容,如果读取失败则data的值为为undefined
  • err参数特点:

    • 如果文件读取成功则err为null,如果读取失败则err存储的具体的错误信息对象,通过如下if判断来处理错误

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y0cLVToU-1632398276334)(images/06)]

    ​ 出错的绝大部分原因是文件路径错误,典型的错误信息是

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ER2TqWG1-1632398276335)(images/07)]

// 引入核心模块
const fs = require('fs');

// 读取文件
fs.readFile('./txt/1.txt', 'utf8', (err, data) => {
    if (err) {
        console.log('==========');
        console.log('错误错误--------------');
        console.log('==========');
    } else {
        // 打印内容
        console.log('正常运行-----------------------');
        console.log(data);
    }
});

// 读取图片
fs.readFile('./images/1609683065082.jpg', (err, data) => {
    // 打印内容
    console.log(data);
});


同步写入文件

fs.writeFileSync ( path,content,utf8 )

  • 语法:fs.writeFileSync (path,data[, options])

  • 特点:writeFile方法是覆盖式写入,后面的内容会将前面的内容覆盖

  • 参数:

    • path,被写入文件的路径(相对路径或绝对路径)
    • data,要写入的内容,字符串格式
    • options:写入文件的参数配置,默认是utf8编码
  • 没有回调函数,结果返回undefined

const fs = require('fs');

try {
    // 写入内容  同步
    fs.writeFileSync('./txt/1.txt', '如果邪恶是华丽残酷的乐章');

    console.log('----------------------------------------------------');
    console.log('同步写入成功');
    console.log('----------------------------------------------------');
} catch (err) {
    console.log('========================================================');
    console.log('同步写入失败');
    console.log(err);
    console.log('========================================================');
}

// 总结:
// 如果文件有内容再写入内容 会覆盖
// 如果路径没有文件再写入内容 会创建文件并写入内容


异步写入文件

fs.writeFile ( path,content,utf8,回调函数 )

  • 语法:fs.writeFile (path,data[, options], callback)
  • 特点:writeFile方法是覆盖式写入,后面的内容会将前面的内容覆盖
  • 参数:
    • path: 被写入文件的路径(相对路径或绝对路径)
    • data: 要写入的内容,字符串格式
    • options:写入文件的参数配置,默认是utf8编码
    • callback: 写入完毕的回调函数(err)=>{}
const fs = require('fs');

// 写入内容  异步
fs.writeFile('./txt/2.txt', '丑八怪,别把灯打开', err => {
    //   err 有值:表示出错
    //   err 没有值,null:表示运行正常
    if (err) {
        console.log('===================================================');
        console.log('异步写入错误');
        console.log(err);
        console.log('===================================================');
    } else {
        console.log('---------------------------------------------------');
        console.log('异步写入成功');
        console.log('---------------------------------------------------');
    }
});

// 总结:
// 如果文件有内容再写入内容 会覆盖
// 如果路径没有文件再写入内容 会创建文件并写入内容


同步追加内容

fs.appendFileSync ( path,content,utf8 )

  • 语法:fs.appendFileSync (path,data[, options])
  • 特点:appendFileSync方法是追加式写入,后面的内容不会将前面的内容覆盖,只会追加到后面
  • 参数:
    • path,被写入文件的路径(相对路径或绝对路径)
    • data,要写入的内容,字符串格式
    • options:写入文件的参数配置,默认是utf8编码
  • 没有回调函数,结果返回undefined
const fs = require('fs');

let index = 0;

while (true) {
    index++;
    fs.appendFileSync('./txt/1.txt', index + '-');
    console.log('追加成功', index);
}

// 死循环追加,记得 ctrl + c

// try {
//     // 追加内容  同步
//     fs.appendFileSync('./txt/1.txt', '如果邪恶是华丽残酷的乐章');

//     console.log('----------------------------------------------------');
//     console.log('同步追加成功');
//     console.log('----------------------------------------------------');
// } catch (err) {
//     console.log('========================================================');
//     console.log('同步追加失败');
//     console.log(err);
//     console.log('========================================================');
// }


异步追加内容

fs.appendFile ( path,content,utf8,回调函数 )

  • 语法:fs.appendFile (path,data[, options], callback)
  • 特点:appendFile方法是追加式写入,后面的内容不会将前面的内容覆盖,只会追加到后面
  • 参数:
    • path,被写入文件的路径(相对路径或绝对路径)
    • data,要写入的内容,字符串格式
    • options:写入文件的参数配置,默认是utf8编码
    • callback:写入完毕的回调函数(err)=>{}
const fs = require('fs');

// 写入内容  异步
fs.appendFile('./txt/1.txt', '丑八怪,别把灯打开', err => {
    //   err 有值:表示出错
    //   err 没有值,null:表示运行正常
    if (err) {
        console.log('===================================================');
        console.log('异步追加错误');
        console.log(err);
        console.log('===================================================');
    } else {
        console.log('---------------------------------------------------');
        console.log('异步追加成功');
        console.log('---------------------------------------------------');
    }
});


案例: 拷贝图片

  • 需求: 使用fs模块的读写方法将3.jpg拷贝一份为4.jpg
    • 先使用fs读取 3.jpg的内容 . 注意:不能添加 utf8
    • 再使用fs将第1步读取到的文件内容写入到4.jpg
const fs = require('fs');

// // 异步
// // 1.读取图片
// fs.readFile('./images/1.png', (err, data) => {
//     if (err) {
//         console.log('读取错误');
//     } else {
//         console.log('读取成功');

//         // 2.写入文件
//         fs.writeFile('./images/2.png', data, (err, data) => {
//             if (err) {
//                 console.log('写入错误');
//             } else {
//                 console.log('写入成功');
//             }
//         });
//     }
// });

// 同步
try {
    // 1.读取图片
    let file = fs.readFileSync('./images/1.png');
    console.log('读取成功');

    try {
        // 2.写入文件
        fs.writeFileSync('./images/3.png', file);
        console.log('写入成功');
    } catch (err) {
        console.log('写入失败');
    }
} catch (err) {
    console.log('读取失败');
}


案例: JSON格式添加内容

  • 需求: 往JSON文件中添加 [1,2] => [1,2,3]

    • 先读取出JSON文件的内容,并转数组
    • 用push()方法追加内容,内容为数组的长度 + 1
    • 再写入就json文件,并转字符串
const fs = require('fs');// // 同步// let files = JSON.parse(fs.readFileSync('./libs/1.json', 'utf8'));// files.push(files.length + 1);// // console.log(files);// let data = fs.writeFileSync('./libs/1.json', JSON.stringify(files), 'utf8');// console.log(data);//异步fs.readFile('./libs/1.json', 'utf8', (err, data) => {    let arr = JSON.parse(data);    arr.push(arr.length + 1);    console.log(arr);    fs.writeFile('./libs/1.json', JSON.stringify(arr), err => {        console.log('写入成功');    });});

案例: 读取JSON文件根据条件分类

  • 需求: 把JSON文件内的内容根据男女分成两个JSON文件
    • 读取JSON文件内容,并转数组
    • 用filter()方法过滤出符合条件的内容
    • 转字符串分别写入新的JSON文件
const fs = require('fs');// 同步方法// 读取JSON文件并转数组let people = JSON.parse(fs.readFileSync('./1.json', 'utf8'));// 数组方法filter过滤const man = people.filter(item => item.gender === '男');const woman = people.filter(item => item.gender === '女');// 完整写法// constman = people.filter(item => {//     if (item.gender === '男') {//         return true;//     } else {//         return false;//     }// });console.log(man, woman);fs.appendFileSync('./man.json', JSON.stringify(man));fs.appendFileSync('./woman.json', JSON.stringify(woman));

案例: html页面局部内容替换

  • 需求: 把html页面局部内容
    • 读取html页面
    • 使用 replace() 方法 替换局部内容
    • 再写入原文件
let obj = {
    title: '培根',
    content: '不为人知的的秘密',
};

const fs = require('fs');

// 异步
fs.readFile('./1.html', 'utf8', (err, data) => {
    console.log(data);

    data = data.replace('{{title}}', obj.title);
    data = data.replace('{{content}}', obj.content);
    console.log(data);

    fs.writeFile('./1.html', data, err => {
        console.log('done width');
    });
});

path 核心模块

  • 作用:用来处理路径的拼接,分析,取后缀名

path.join() 自动拼接路径

 // path  核心模块 处理 路径问题
 
 const path = require("path");
 
 // 自动帮我们拼接路径  
 const url = path.join("data", "image", "2.json");
 console.log(url);

path 获取文件绝对路径

__dirname 返回当前文件的绝对路径

 const fs = require("fs"); const path = require("path");   // const filePath = path.join("data", "2.json");   // 相对于谁???  当前的文件本身 错了!!!  // 在哪里执行的  node xxx.js  相对于谁   // 如果用户在不同的目录下来运行当前的js文件  // js文件内用的相对路径 会变化!!     // 想要获取该文件的绝对地址  d c 。。。 const filePath = path.join(__dirname, "data", "2.json");  // 在node中 获取当前文件的绝对地址 // console.log(__dirname);  const data = fs.readFileSync(filePath, "utf8");  console.log(data); 

服务器相关概念

  • 服务端

    • 提供服务
  • 客户端

    • 享受服务
  • ip地址 — Internet Protocol Address

    • 表示计算机中唯一的地址
    • ipv4
    • ipv6
    • 本机地址
      • 127.0.0.1
      • localhost
  • 域名

    • ip地址的别名
    • 注册购买
    • 例: 220.181.38.149的别名为 www.baidu.com
  • http协议

    • 明确规定了请求数据响应数据格式(报文)
    • 2 规定客户端和服务端 交互信息的 约束
  • http协议报文

    • 请求报文 — 浏览器发送给服务器

      请求行存放 当前请求地址get或者post请求而已
      请求体存放 提交给后台的参数post 帐号密码
      请求头1. token 登录凭证2. 当前浏览器的一些相关信息
    • 响应报文 — 服务器响应给浏览器

      响应行http状态码是什么 200成功 404找不到 500服务器出错get或者post请求而已
      响应体响应客户端请求的数据post 帐号密码
      响应头告诉浏览器 当前的返回的内容的类型是什么图片 样式 js文件

http 核心模块

HTTP在线文档 https://nodejs.org/dist/latest-v14.x/docs/api/http.html

开启一个服务

// 1 引入http 核心模块const http = require("http");// 2 调用 createServer方法来创建一个服务 // 通过返回值 来指定端口const app = http.createServer((request, response) => {  // request 当浏览器来访问我的服务器 request 存放请求报文信息(行 头 体)  // response 用来 设置 返回给浏览器的响应 信息 (行 头 体)   response.end("hello byby");});// 3 开启指定端口app.listen(8001, () => {  console.log("8001 端口已经开启了 欢迎来快活 ");});

响应对象response常用属性

const http = require("http");const app = http.createServer((request, response) => {  // 解决中文乱码问题  response.setHeader('Content-Type', 'text/plain;charset="utf-8"');  // 设置响应的状态码  404 500 200   // response.statusCode = 404;  response.statusCode = 404;  // obj.title = 1234;  // obj.show();  // 显示中文  response.end("");});app.listen(8001, () => {  console.log("8001 开启成功");});

返回随机数

const http = require("http");const app = http.createServer((request, response) => {  // request 请求对象   // 请求报文的一些信息   // 请求行 请求头 请求体   // console.log(request);// F5   if (request.url === "/random") {    response.end(Math.random() + "");  } else {    // 设置响应状态码 404    response.statusCode = 404;    response.end("");  }});app.listen(8001, () => {  console.log("8001 开启");})

服务器提供静态资源

const http = require("http");const fs = require("fs");const app = http.createServer((req, res) => {  console.log(req.url);  // 判断当前请求的url   if (req.url === "/index.html") {    // 要返回真正html 字符串 给浏览器      // 读取 首页 index.html      res.setHeader("content-type", "text/html");    const indexHTML = fs.readFileSync("public/index.html", "utf8");    res.end(indexHTML);  } else if (req.url === "/cart.html") {    res.setHeader("content-type", "text/html");    const cartHTML = fs.readFileSync("public/cart.html", "utf8");    res.end(cartHTML);  } else if (req.url == "/css/index.css") {    // 找样式文件    // 设置响应头 当前文件的类型     res.setHeader("content-type", "text/css");    const css = fs.readFileSync("public/css/index.css");    res.end(css);  } else if (req.url == "/js/index.js") {    res.setHeader("content-type", "application/x-javascript");    const js = fs.readFileSync("public/js/index.js");    res.end(js);  } else if (req.url == "/imgs/1.jpg") {    res.setHeader("content-type", "image/jpeg");    const img = fs.readFileSync("public/imgs/1.jpg");    res.end(img);  }  else {    // 404     res.statusCode = 404;    res.end("");  }});app.listen(8001, () => {  console.log("8001");});

服务器提供静态资源-优化

// 引入核心模块const http = require('http');const fs = require('fs');// 创建一个服务器const app = http.createServer((req, res) => {    // 1 获取 客户端请求的 url    const url = req.url; // url = "/index.html"  => /1ndex.html => 返回404    console.log(url);    // 2 根据 url 找寻找服务器上的对应的那个文件  try catch    try {        const file = fs.readFileSync('public' + url);        // 3 将该文件 返回        res.end(file);    } catch (error) {        // 4 文件找不到        res.statusCode = 404;        res.end('');    }});app.listen(8001, () => {    console.log('8001');});

Web服务器处理接口响应

node接口服务器

/* 使用 接口的 三大要素 1 接口的地址  node 如何获取 浏览器的请求url   request.url 2 请求的类型  request.method   1 直接在浏览器中 输入 地址 当前的请求类型  是 GET 请求   3 请求的参数 (get请求的参数)*/// 可以手写 服务器 const http = require("http");const app = http.createServer((req, res) => {  console.log(req.method); // 获取当前客户端发送过来的请求的类型  res.end("返回数据啦")});app.listen(8001, () => {  console.log("8001 开启成功");});

案例: 不带参数的接口

  • 需求: 通过判定请求的url和请求类型来读取JSON文件,并返回读到的内容
    • 引入 http fs 模块
    • 创建一个服务
    • 监听
    • 判定 请求类型 和 请求的 url . 通过: 读取并返回数据 ; 不通过: 设置响应状态码为404,返回数据为空
const http = require("http");const fs = require("fs");const app = http.createServer((req, res) => {  // 1 判断 请求的url   // 1 判断 请求类型   if (req.url === "/getHero" && req.method === "GET") {    const db = fs.readFileSync("data/db.json", "utf8");    res.end(db);  } else {    res.statusCode = 404;    res.end("");  }}); app.listen(8001, () => {  console.log("8001 开启成功");});

获取 get 请求的参数

const http = require("http");const app = http.createServer((req, res) => {  // 获取get请求的参数   const url = req.url; // 客户端请求的url  http://127.0.0.1:8001/getHero?name=海贼王  // /getHero?name=baby&age=18  // 可以根据 name = baby  // 可以根据 age = 18   console.log(url);  res.end("");});app.listen(8001, () => {  console.log("8001 开启成功");});

获取 url 的参数

URLSearchParams解析参数

URLSearchParams可以将查询字符串解析成一个对象,通过get方法获取到指定参数值

// req.url const str = "/getHero?name=baby&age=18".split("?")[1]; // => name=baby&age=18// 1 种解决方式 靠大家的js 硬钢代码 // 2 新的对象 方便的实现功能 //  URLSearchParams  URL 地址  Search 寻找  Params 参数 const usp = new URLSearchParams(str);// 获取name // 获取ageconst name1 = usp.get("name");const age = usp.get("age");console.log(name1, age);

Postman工具

  • postman是一款api接口的测试工具,可以模拟get,post,文件上传等请求

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8PovJkZC-1632398276336)(images/09.png)]

案例: 根据 get请求的参数查询数据

  • 需求: get请求通过参数来查询JSON文件对应的数据并返回
    • 判断请求地址是不是 /getHero,请求参数是不是get
    • 获取get的参数 URLSearchParams
    • 读取JSON文件 转字符串
    • 根据英雄名称查询JSON文件对应的数据 find()
    • 返回数据
const http = require("http");const fs = require("fs");const app = http.createServer((req, res) => {  const url = req.url.split('?')[0];  const params = req.url.split('?')[1];  // 1 判断url 是不是 getHero  判断当前的请求类型是不是 get  if (url === "/getHero" && req.method === "GET") {    // 3 获取 get请求的参数       // URLSearchParams  接收的字符串  (params = name="海贼王")    const usp = new URLSearchParams(params);    const heroName = usp.get("name");// 海贼王    // 4 获取数组    let list = fs.readFileSync("data/db.json", "utf8");    list = JSON.parse(list);    // 根据 英雄的名称来查询该数组中的对应的数据    const hero = list.find(obj => obj.name === heroName);    res.end(JSON.stringify(hero));// end 接收的是一个字符串格式   } else {    res.statusCode = 404;    res.end("");  }});app.listen(8001, () => {  console.log("8001 开启成功");});

查询数组中某个元素 find()

const list = [{ "name": "海贼王", "gender": "男" }, { "name": "鸣人", "gender": "男" }, { "name": "女帝", "gender": "女" }, { "name": "索隆", "gender": "男" }, { "name": "培根", "gender": "男" }, { "name": "娜美", "gender": "女" }, { "name": "白骨精", "gender": "女" }, { "name": "送子观音", "gender": "女" }];const heroName = "鸣人";// forEach 不用  不能打断循环 // for 可以考虑 可以被打断   不够简洁 优雅 // filter   不用  不能被打断 循环 // findIndex 不用 找到了之后 就可以停下来了 但是 返回 当元素的索引  list[0] // find  考虑  找到了之后 直接返回 当前一个元素  obj const hero = list.find(obj => obj.name === heroName);console.log(hero);

服务器接收 post请求的参数

  • 在接收参数的过程中,会涉及req对象的两个事件data,end
    • data事件,每次收到一部分参数数据就会触发一次这个事件。
    • end事件,全部的参数数据接收完成之后会执行一次。
// 如何当前当前的请求 url getHero ||  getHeroSkin
// 如何判断当前请求 是get 还是post 
// 如何获取get请求的参数

// 但是 还没有学如何 获取post请求的参数!!

const http = require("http");
const app = http.createServer((req, res) => {

  // post请求的参数的获取 先要求 用户 执行post请求 同时在请求体中 传递数据 

  let data = "";// 接收 post请求的参数

  // 定义两个事件  执行 post请求的时候 参数 不断的触发 data事件
  req.on("data", (chunk) => {
    console.log("====");
    console.log(Date.now());
    console.log("----");
    // chunk 一小块数据 
    data += chunk;
  });
  // 数据终于传递完毕了
  req.on("end", () => {
    // data 等于 post请求上传过来的完成的数据 
    // data 也是字符串类型的数据   name=海贼王 
    console.log(data); //  用户的上传的参数  {name:"海贼王",gender:"男"}   => name='海贼王'&gender='男'  URLSearchParams
  });


  res.end("OK");
});

app.listen(8001, () => {
  console.log("8001 开启成功");
})

案例: post请求的案例

  • 需求:

    1. 用户执行post请求

    2. url http://127.0.0.1:8001/addHero

    3. 提交的参数 {naem:“英雄的名称”,gender:“男”}

    4. 服务端

    • 验证是不是post请求
    • 验证 url 是不是 /addHero
    • 验证name和gender属性有没有值
    • 随便一个不通过赶回404
    • 把新的数据插入到本地文件 db.json中
// 需求
// 1.用户执行post请求
// 2.url  http://127.0.0.1:8001/addHero
// 3.提交的参数   {naem:"英雄的名称",gender:"男"}
// 4.服务端
// 验证是不是post请求
// 验证 url 是不是 /addHero
// 验证name和gender属性有没有值
// 随便一个不通过赶回404
// 把新的数据插入到本地文件 db.json中

const http = require('http');
const fs = require('fs');

const app = http.createServer((req, res) => {
    // 验证是不是post请求, url 是不是 /addHero
    if (req.url === '/addHero' && req.method === 'POST') {
        // 用于接收post请求的参数
        let data = '';
        // post 请求的两个事件
        req.on('data', chunk => {
            data += chunk;
        });

        req.on('end', () => {
            // data数据接收完毕   data  =  name=海贼王&gender=男
            // 新建一个 URLSearchParams 对象,用于获取参数值
            const usp = new URLSearchParams(data);
            // 存放到对象中,便于post请求成功后添加数据
            let obj = {
                name: usp.get('name'),
                gender: usp.get('gender'),
            };

            // 判定name和gender属性有没有值
            if (!obj.name || !obj.gender) {
                res.statusCode = 500;
                res.end('name或gender参数有误');
            } else {
                // 1.读取文件转数组
                let list = JSON.parse(fs.readFileSync('./db.json', 'utf8'));
                // 2.push 追加新的数据
                list.push(obj);
                // 3.写入本地文件  转字符串
                fs.writeFileSync('./db.json', JSON.stringify(list));

                res.end('okokokokokokokokokokokokokokokokokokokokokokokokokokokokokok');
            }
        });
    } else {
        res.statusCode = 404;
        res.end('');
    }
});

app.listen(8001, () => {
    console.log('8001开启');
});

模块化与包管理工具

模块化的作用

每个js文件看作是一个模块,每个模块通过固定的方式引入,并且通过固定的方式向外暴露指定的内容

  • 能够对一类功能做很好的分类管理
  • 能够保护成员不被污染
  • 不用考虑导入顺序
  • 按需导入,可以随时更换模块,维护方便

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AkDrt8Zu-1632398276337)(images/10.png)]

自定义模块

  • js文件名最好能够见名知意

  • 自定义模块名称不能与核心模块同名

  • 通过module.exports关键字按需导出

  • 使用固定关键字 require()导入模块,参数带有路径

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1U6D7bPR-1632398276337)(images/11.png)]

两种导出方式

  • module.exports 关键字写法

  • exports 关键字写法

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yUzUu6Pb-1632398276338)(images/12.png)]

module.exports和export的关系

module.exports 和 export 二者指向同一个对象{}

模块以 module.exports 导出方式为准 , 建议直接使用module.exports

  • exports是module.exports的别名 exports === module.exports // 输出是 true

  • 如果在对象上添加属性两个对象的用法是一样的

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JVALtQIf-1632398276338)(images/13.png)]

引用自定义模块

// 引入自定义模块const obj = require('./js/index');// console.log(obj);  //  { log: [Function: log] }obj.log(); //  这是index.js

案例: post请求案例-模块化

// 需求// 1.用户执行post请求// 2.url  http://127.0.0.1:8001/addHero// 3.提交的参数   {naem:"英雄的名称",gender:"男"}// 4.服务端// 验证是不是post请求// 验证 url 是不是 /addHero// 验证name和gender属性有没有值// 随便一个不通过赶回404// 把新的数据插入到本地文件 db.json中const http = require('http');const fs = require('fs');// 导入自定义模块const addHero = require('./js/addHero');const app = http.createServer((req, res) => {    // 验证是不是post请求, url 是不是 /addHero    if (req.url === '/addHero' && req.method === 'POST') {        addHero(req, res);    } else {        res.statusCode = 404;        res.end('');    }});app.listen(8001, () => {    console.log('8001开启');});

NPM包管理工具

npm 下载和使用第三方模块

  1. 新建空的文件夹 ( 名称不能是中文 )

  2. 在空的文件内

    npm init --yesnpm init -y
    
  3. 下载第三方的模块

    npm install 模块名称npm i 模块名称npm install day.jsnpm i day.js
    
  4. 下载指定版本的第三方包

    npm install day.js@1.10.6npm i day.js@1.10.6
    
  5. 新建一个app.js文件

    // 引入 第三方模块 写法 类似 引入核心模块 const dayjs = require("dayjs");// dayjs 如何去使用   去查看它的使用文档。。。// format 格式化console.log(dayjs(Date.now()).format("YYYY-MM-DD HH:mm:ss"));
    

执行 npm install 变化发生

  1. 执行下载包

    npm install dayjs
    
  2. 本地项目中多了一个文件夹 node_modules/ 用来存放第三方模块

  3. 仔细观察 package.json 多了一个字段 dependencies

      "dependencies": {    "dayjs": "^1.10.7"  }
    

npm 卸载指定的第三方模块

手动卸载
  1. 手动删除掉 package.json 文件中 字段 dependencies 里面 模块的信息

      "dependencies": {    "dayjs": "^1.10.6",    "jquery": "^3.6.0"  }
    

    手动删除

      "dependencies": {    "jquery": "^3.6.0"  }
    
  2. 手动去删除 node_modules 中的 dayjs 文件夹

  3. npm 自带 卸载功能

    npm uninstall 模块的名称npm uninstall jquery
    

解决下载第三方模块慢的问题

  1. 打开命令行窗口

    npm install -g nrm 
    
  2. 下载成功后 测试

    nrm test
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MoohXs9S-1632398276339)(images/npm-01.png)]

    1. 切换镜像源 (npm下载地址)
    nrm use tencent 
    
    1. 以后还是和以前一样正常使用npm即可
    npm install dayjs 
    

全局安装和本地安装的区别

  1. 全局

    npm install -g  包的名称
    
  2. 在某个项目内

    npm install 包名称 
    

nodemon 全局安装

监听本地js文件的变化,自动重启

  1. 全局安装 nodemon

    npm install -g nodemon
    
  2. 找到你想要运行 node文件 app.js

    node app.js // 以前 nodemon app.js //  现在 
    

报错:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BzYAeaWm-1632398276340)(images/npm-02.png)]

解决:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-azhzUlH0-1632398276340)(images/npm-03.jpg)]

命令: set-executionpolicy remotesigned

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KuaZ4Jw0-1632398276341)(images/npm-04.png)]

命令: A

require 工作中常用

  1. 要引入的文件名

    index.js  index.json   
    
  2. 引入

    require("./index");// 如果引入的模块是自定义模块 建议加上 ./  相对路径
    
  3. 要引入的文件

    main/index.js

  4. 引入

    require("./main");
    
  5. 核心模块和第三模块

    require("模块名称")
    

Express框架

Express 是一个基于 Node.js 平台,快速、开放、极简的 web 开发框架,可以替代http模块

安装

  1. 安装 node.js 后,新建一个文件夹
  2. 文件夹内打开小黑窗
  3. npm init --yes 命令创建一个 package.json 文件
  4. npm install express 命令安装 Express
  5. 检查node_modules中如果有Express则表示安装成功

使用 express 框架创建服务器

1 2 4 是固定的 , 3 根据需求决定

// 1.引入 express 框架const express = require('express');// 2.创建一个服务器const app = express();// 3.定义url设置返回内容// http://127.0.0.1:8001app.get('/', (req, res) => {    // 设置返回    res.send('bingo✅');});// 4.设置监听app.listen(8001, () => {    console.log('8001 开启成功');});

express托管静态资源

// 1.引入express框架const express = require('express');// 2.创建一个服务器const app = express();// express 托管静态资源// app.use("设置url访问静态资源的前缀", "要托管的目录的路径");// http://127.0.0.1:8001/sss/// app.use(express.static('./public'));  //  前缀可省略app.use('', express.static('./public'));// 设置监听app.listen(8001, () => {    console.log('8001开启');});

express发送 get / post 请求

const express = require('express');const app = express();// get请求  /getList 返回 hello getListapp.get('/getList', (req, res) => {    res.send('get  hello getList');});// post请求 /addHero 返回 post addHeroapp.post('/getList', (req, res) => {    res.send('post post addHero');});app.listen(8001, () => {    console.log('8001✅');});

express - get请求 - 获取参数

const express = require('express');const app = express();// get请求  /getList 返回 hello getListapp.get('/getList', (req, res) => {    // 获取请求路径    // console.log(req.url);    // 获取请求方式    // console.log(req.method);    //  req.query 获取请求的参数  是对象格式  { name: '张三', gender: '男', age: '18' }    console.log(req.query);    res.send('get  hello getList');});app.listen(8001, () => {    console.log('8001✅');});

案例: get请求JSON文件返回数据

// 需求// 用户输入http://127.0.0.1:8001/getHero?name=海贼王// 返回海贼王数据// 1.引入express框架const express = require('express');// 2.引入fs模块const fs = require('fs');// 3.创建一个服务器const app = express();// 发送get请求,请求地址为 /getHeroapp.get('/getHero', (req, res) => {    // 异步读取JSON文件    fs.readFile('./db.json', 'utf8', (err, data) => {        // 转数组        data = JSON.parse(data);        // find()方法遍历数组,返回符合条件的数据重新赋值给data        data = data.find(obj => obj.name === req.query.name);        // console.log(data);        // 返回数据,转字符串        res.send(JSON.stringify(data));    });});app.listen(8001, () => {    console.log('8001✅');});

express - 获取post请求参数

// 统一处理post请求app.use(express.urlencoded());// post请求app.post('/addHero', (req, res) => {    // 获取post请求中的数据 req.body 来获取    console.log(req.body);    // 返回数据    res.send('addHero');});// 设置监听app.listen(8001, () => {    console.log('8001 开启成功');});

案例: post请求获取数据添加到JSON文件中

// 需求:// 用户执行 post 请求// http://127.0.0.1:8001/addHero    {name:"英雄名称",gender:"性别"}// 把接收到的数据添加到db,JSON中const express = require('express');const fs = require('fs');const app = express();// 统一处理post请求app.use(express.urlencoded());app.post('/addHero', (req, res) => {    // 获取post请求中的数据 req.body 来获取    console.log(req.body);    fs.readFile('./db.json', 'utf8', (err, data) => {        data = JSON.parse(data);        data.push(req.body);        console.log(data);        fs.writeFile('./db.json', JSON.stringify(data), (err, data) => {            console.log(data);        });    });    res.send('✅');});app.listen(8001, () => {    console.log('8001开启');});

express - 路由的体验

routes\hero.js

// 引入 express 框架const express = require('express');// 新建一个路由对象const Router = express.Router();// 定义英雄专有路由路径Router.get('/search', (req, res) => {    res.send('英雄查询');});Router.post('/add', (req, res) => {    res.send('英雄添加');});Router.post('/update', (req, res) => {    res.send('英雄修改');});// 导出module.exports = Router;

routes\goods.js

// 引入 express 框架
const express = require('express');

// 新建一个路由对象
const Router = express.Router();

// 定义商品专有路由路径
Router.get('/search', (req, res) => {
    res.send('商品查询');
});
Router.post('/add', (req, res) => {
    res.send('商品添加');
});
Router.post('/update', (req, res) => {
    res.send('商品修改');
});

// 导出
module.exports = Router;

express - 路由的体验.js

const express = require('express');
const app = express();

// 1.引入英雄路由
const hero = require('./routes/hero');

// 2.引入商品路由
const goods = require('./routes/goods');

// 1.2 让qpp来加载英雌路由
app.use('/hero', hero);

// 2.2 让app来加载商品路由
app.use('/goods', goods);

app.listen(8001, () => {
    console.log('8001   开启成功');
});

案例: 写接口 增删改查

  • 需求: [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cN4FZwjH-1632398276341)(images/路由作业.png)]

app.js

// 1.引入 express 框架const express = require('express');// 2.创建服务器const app = express();// 统一处理post请求app.use(express.urlencoded());// 4.引入hero路由const hero = require('./routes/hero');// 5.app加载路由app.use('/hero', hero);// 3.监听app.listen(8001, () => {    console.log('8001✅');});

routers/hero.js

// 01-引入 express 框架const express = require('express');// 02-新建路由对象const Router = express.Router();const fs = require('fs');let data = fs.readFileSync('./db.json', 'utf8');// 04-定义专有路径// 1.get请求 返回所有数据Router.get('/search', (req, res) => {    //返回所有数据    res.send(data);});// 2.get请求  返回单个数据Router.get('/searchOne', (req, res) => {    // 获取get请求参数  对象格式  { name: '海贼王' }    // console.log(req.query);    // 遍历数组,获取 符合条件的哪一个元素    let hero = JSON.parse(data).find(obj => obj.name === req.query.name);    console.log(hero);    res.send(JSON.stringify(hero));});// 3.post请求  添加英雌Router.post('/add', (req, res) => {    // 1.获取post请求参数,需要添加 express.urlencoded()方法,不然获取不到    // console.log(req.body);    data = JSON.parse(data);    // 2.往数组中添加数据    data.push(req.body);    // 3.数组写入本地文件中    fs.writeFileSync('./db.json', JSON.stringify(data));    res.send('添加成功');});// 错误: 全局读取文件,定义的const保存,转数组重新赋值,报错.// 解决: 把const 改成 let// 4.post请求 修改单个英雄Router.post('/update', (req, res) => {    data = JSON.parse(data);    // 先找到数组中 符合条件的那个元素所在的索引  findIndex    let index = data.findIndex(obj => obj.name === req.body.name);    // 找到索引后 让数组的元素的属性发生了改变    data[index].gender = req.body.gender;    // 写入到本地文件中    fs.writeFileSync('db.json', JSON.stringify(data));    res.send('修改单个英雌成功');});// 5.get请求 删除英雄Router.get('/delete', (req, res) => {    // 1.获取用户get上传过来的 参数  name     console.log(req.query.name)    data = JSON.parse(data);    // 2.filter()过滤,符合条件的重新赋值给data    data = data.filter(obj => obj.name != req.query.name);    // 3.写入到本地文件中    fs.writeFileSync('./db.json', JSON.stringify(data));    res.send('删除英雄成功');});// 03-导出路由module.exports = Router;

req对象

  • req.url : 获取请求url
  • req.method:获取请求方法
  • req.query: 获取url传入的查询字符串参数
    • 请求的url如果带有参数则会自动解析到query中,例如:/getHero?heroname=妲己
  • req.params : 获取url传入的路由参数
  • req.body:获取post请求体中的参数
    • 需要配合内置中间件完成 app.use(express.urlencoded()) 和 app.use(express.json())
  • res.send() : 作用类似于http模块中的res.end()
    • 举例:res.send(‘要响应的数据’) 它会自动增加content-type响应头,支持直接js对象参数作为响应数据
      res.send({name:“张三”})
  • res.json(): 直接将一个js对象或者数据以json字符串返回:res.json({name:“张三”})
  • res.status(): 设置响应状态码: res.status(404)
  • res.set() : 设置响应头
    • res.set(‘content-type’,‘text/html;charset=utf8’)
    • res.set(‘Access-Control-Allow-Origin’, “*”);

中间件

routers/hero.js

const express = require('express');const Router = express.Router();Router.get('/search', (req, res) => {    // // 01--中间件的基本使用    // console.log('/search', req.appTitle);    // // 02--自己写的中间件并打印    // console.log(req.body); //  { name: '张三李四' }    // res.send('请求所有数据');    // // 03--跨域    // // * 解决跨域报错    // // express 设置响应头的写法 res.set(key,value)    // res.set('Access-Control-Allow-Origin', '*'); // 允许哪个网站来请求我的数据  *: 所有    // res.set('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS'); //  允许哪些请求类型来访问 get post    // res.set('Access-Control-Allow-Headers', 'Content-Type,Content-Length, Authorization, Accept,X-Requested-With'); //  请求来源中 带有 Content-Type,Content-Length 数据    // res.send('请求所有数据');    // 04--跨域-中间件    res.send('请求所有数据');});module.exports = Router;

中间件的基本使用

  • 中间件本质就是一个函数,它被当作 app.use(中间件函数) 的参数来使用

  • req:请求报文对象

  • res:响应报文对象

  • next()作用:只有显示调用了next()才会进入到下一个中间件或者路由处理函数的执行,否则就到此为止

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RRLXYjgt-1632398276342)(images/中间件定义格式.png)]

routers/hero.js 01–中间件的基本使用

const express = require('express');const app = express();const hero = require('./routers/hero');// 中间件是一个函数  给 请求对象 添加一个自定义属性  当前项目名称: 妙蛙const fn = (req, res, next) => {    // req: 请求对象    // res: 响应对象    // next: 执行下一个中间件    req.appTitle = '妙蛙';    console.log('中间件被触发了');    next(); //  程序才可以往下执行};// app使用中间件app.use(fn);app.use('/', hero);app.listen(8001, () => {    console.log('8001 is running ');});

express中间件-4种匹配规则

  • app.use(中间件)是应用级中间件,所有的请求都能匹配。
  • app.use(’/apiname’,中间件) 。匹配请求路径是/apiname的请求。
  • app.get(’/apiname’,中间件) 。匹配get类型并且请求路径是/apiname的请求,就是我们前面说的路由。
  • app.get(’/apiname’,中间件1,中间件2) 。一个路由中使用多个中间件。

自己写的中间件并打印

routers/hero.js 02–自己写的中间件并打印

const express = require('express');const app = express();const hero = require('./routers/hero');// 中间件是一个函数  给 请求对象 添加一个自定义属性  当前项目名称: 妙蛙const fn = (req, res, next) => {    // req: 请求对象    // res: 响应对象    // next: 执行下一个中间件    // req.appTitle = '妙蛙';    // console.log('中间件被触发了');    // 自己写的中间件    req.body = { name: '张三李四' };    next(); //  程序才可以往下执行};// app使用中间件app.use(fn);app.use('/', hero);app.listen(8001, () => {    console.log('8001 is running ');});

跨域

routers/hero.js 03–跨域

const express = require('express');const app = express();const hero = require('./routers/hero');app.use('/', hero);app.listen(8001, () => {    console.log('8001 is running ');});

跨域-中间件

routers/hero.js 04–跨域-中间件

const express = require('express');
const app = express();

const hero = require('./routers/hero');

// 处理跨域的中间件 cors
const cors = (req, res, next) => {
    // * 解决跨域报错
    // express 设置响应头的写法 res.set(key,value)
    res.set('Access-Control-Allow-Origin', '*'); // 允许哪个网站来请求我的数据  *: 所有
    res.set('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS'); //  允许哪些请求类型来访问 get post
    res.set('Access-Control-Allow-Headers', 'Content-Type,Content-Length, Authorization, Accept,X-Requested-With'); //  请求来源中 带有 Content-Type,Content-Length 数据

    next();
};

// 调用 跨域的中间件
app.use(cors);
// ❌--报错: 调用完跨域的中间件没反应
// ⭕--解决: 调用跨域的中间件 必须写在 app加载路由的上面

app.use('/', hero);

app.listen(8001, () => {
    console.log('8001 is running ');
});

跨域-第三方模块

const express = require('express');
const app = express();

const hero = require('./routers/hero');

// 1.引入 解决跨域的 第三方模块
const cors = require('cors');

// 2.使用 中间件 解决跨域
app.use(cors);

app.use('/', hero);

app.listen(8001, () => {
    console.log('8001 is running ');
});

文件上传

  • 看文档

  • 下包

    npm install multer
    
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PTtGCORx-1632398276343)(images/文件上传.png)]

  • 新建文件夹,文件上传后的位置[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LH4jMURv-1632398276344)(images/文件上传后所在文件夹的位置.png)]

const express = require('express');
const app = express();

// 1.引入包  muler
const multer = require('multer');

// 2.创建中间件
// dest: 目标,文件上传后的位置
// uploads/: / 表示是一个文件夹
const upload = multer({ dest: 'uploads/' });

// 3.定义接口路由
// "cover": key的名称
// app.get('/apiname',中间件1,中间件2). 一个路由中使用多个中间件
// '/upload':  路由
//  upload.single('cover'):  中间件1
//  (req, res) => {: 中间件2
app.post('/upload', upload.single('cover'), (req, res) => {
    console.log(req.file);
    res.send('上传文件成功,返回改文件上传后的 地址');
});

app.listen(8001, () => {
    console.log('8001 is running ');
});

上传成功后,图片显示不出来,需要在html页面中引入图片,浏览器打开

指定文件上传目录

  • 看文档
/*
1.上传成功后,保存文件的时候 带上文件的后缀名
2.返回给前端一个该文件的在线链接,直接在浏览器url中访问的
*/

const express = require('express');
const app = express();
const path = require("path");

// 1.引入包  muler
const multer = require('multer');

// 2.2 express 托管静态资源
app.use('', express.static('./uploads'));

const storage = multer.diskStorage({
    // 指定存放文件的文件夹 地址
    destination: function (req, file, cb) {
        cb(null, 'uploads/');
    },
    // 地址文件的名称
    filename: function (req, file, cb) {
        console.log(file);

        // 获取文件的后缀名
        // 第一种:  const extname = file.originalname.split('.')[1];
        const extName = path.extname(file.originalname);// .jpg 
        // 随机生成一串 文件名
        const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
        // 对应第一种:  cb(null, uniqueSuffix + '.' + extname);
         cb(null, uniqueSuffix + extName);
    },
});

const upload = multer({ storage: storage });

// 3.定义接口路由
app.post('/upload', upload.single('cover'), (req, res) => {
    // console.log(req.file);
    // res.send('上传文件成功,返回改文件上传后的 地址');

    // 2.1 返回给前端的路径,需要自己拼接,不需要加 upload/ 文件目录 !
    res.send('http://127.0.0.1:8001/' + req.file.path);
});

app.listen(8001, () => {
    console.log('8001 is running ');
});

中间件-错误处理

  • 错误日志存放目录[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sVI8ZU1A-1632398276344)(images/错误日志存放目录.png)]
  • 错误日志记录[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pIe0u9vF-1632398276345)(images/错误日志记录.png)]
/*
1.不可避免的程序会报错
2.当后台程序出错的时候
    1.给用户一个友好的提示
    2.错误日志记录
    把字符串的错误信息 存到一个文件中即可
3.错误处理 中间件 来解决以上的问题
*/

// 定义一个错误处理中间件 ---函数
// 和普通的中间件不一样
// 1.错误处理中间件  4个参数  err: 错误信息
// 2.错误处理中间件的 代码调用顺序必须放在所有中间件的 末尾!!!
const errHandle = (err, req, res, next) => {
    console.log('程序报错了--- ---');

    // console.log(err); //  打断点来研究
    // err.message: 简洁的错误信息
    // err.stack: 很详细的错误信息

    // 定义变量 保存错误发生的 时间和错误信息
    const log = { date: Date.now(), message: err.message, stack: err.stack };
    // 追加到一个文件中
    fs.appendFileSync('./log/log', JSON.stringify(log));

    console.log('程序报错了--- ---');
    res.status(500);
    res.send('后端服务器正在休息,稍后再来');
};

const express = require('express');
const app = express();
const fs = require('fs');

// 定义一个路由,查询英雄信息
app.get('/list', (req, res) => {
    req()()();
    res.send('正常返回英雄信息');

    // try {
    //     req()()();
    //     res.send('正常返回英雄信息');
    // } catch {
    //     res.status(500);
    //     res.send('服务器正在休息,一会儿就好...');
    // }
});

// 调用错误处理中间件
app.use(errHandle); //  放在末尾了

app.listen(8001, () => {
    console.log('8001 is running ');
});

数据库 — MYSQL

Navicat基本使用

navicat 新建连接

  1. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fD3ngE0T-1632398276346)(images/新建连接01.png)]

  2. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BsLUjyOP-1632398276346)(images/新建连接02.png)]

  3. 默认灰色,双击连接变绿[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EuEq9liR-1632398276347)(images/新建连接03.png)]

  4. 可以删除,右键选择删除

navicat 新建数据库

  1. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jv9jHyJU-1632398276347)(images/新建数据库01.png)]
  2. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hL12pU6f-1632398276348)(images/新建数据库02.png)]
  3. 可以删除,右键选择

新建 student数据表

  1. 新建表[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Aoxe4LKB-1632398276349)(images/新建表01.png)]

  2. 弹窗 要求我们添加 字段信息[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Vb0SF9v-1632398276349)(images/新建表02.png)]

  3. 添加栏位,[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9dFe38HX-1632398276350)(images/新建表03.png)]

  4. student数据表字段的设置

    • int 是 MySQL中的整型
    • varchar 是 MySQL中的字符串类型
    • id必填,所以不是null
    • username必填,所以不是null
    • id设为主键,则id值不能重复
    • id设置自动递增,则添加数据时会自增

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hN6yDT2H-1632398276351)(images/新建表04.png)]

  5. 添加成功[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LyhYLzNs-1632398276351)(images/新建表05.png)]

手动添加数据

  1. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ExLYKhP8-1632398276352)(images/添加数据01.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p7b7oXBk-1632398276352)(images/添加数据02.png)]

查询数据操作

  1. 点击查询[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cwjbQxQj-1632398276353)(images/查询数据01.png)]
  2. 新建查询[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nE75nh1D-1632398276354)(images/查询数据02.png)]
  3. 跳出弹框,编写SQL语句

SQL语句

查询

  • SELECT 字段, 字段, … FROM 表名

  • select 字段, 字段, … from 表名 where 条件

  1. 查询所有
--  查询student表格中 所有的数据   *: 所有字段
select * from student 
  1. 查询所有数据中的 指定 的字段 — , 分隔 (英文)
select username,age from student 
  1. 查询带条件 — where 后面跟条件 多个条件时 and 连接
-- 查询男同学
-- select * from student where sex = '男'
-- 查询年龄大于20的
-- select * from student where age > 20
-- 查询年龄小于30 且 性别为女
select * from student where age < 30 and sex = '女'

查询 排序

  • select 字段, 字段, … from 表名 [where 条件] order by 字段 排序规则

  • 升序:asc,默认就是升序

  • 降序:desc

  • 有条件和排序,条件在前,排序在后

-- 根据年龄来排序 升序  asc-- select * from student order by age asc --  根据年龄来排序 降序  desc--  select * from student order by age desc -- 先筛选 性别为男 查询  在排序 升序select * from student where sex = '男'  order by age asc

查询指定位置指定数量的数据

  • select 字段, 字段, … from 表名 limit 开始索引,查询条数

  • 使用limit 开始索引,查询条数

    • 注意: 索引不是 id , 是数据在数据库表格中的位置

从下标1开始,查询3条数据

-- 查询指定位置指定数量的数据 select * from student  limit 1,3

查询符合条件的数据长度

  • select count(表主键) from 表名
-- 查询 一共  几条数据-- select count(*) from student -- 查询  性别为男   几条数据select count(*) from student where sex = '男'

添加

  • insert into 表名(字段1,字段2,…) values(字段1值,字段2值,
-- 添加一条数据  添加一条记录insert into student (username,sex,age) values('网管','男',17)

更新

  • update 表名 set 字段=值, 字段=值, … [where 条件]

注意: 一定要添加条件,不加条件将会修改全部数据!!!

-- 修改性别为女  条件  年龄 = 17   一定要添加条件!!!!update student set sex = '女' where age = 17

删除

  • delete from 表名 [where 条件]

注意: 一定要添加条件, 不加条件将会删除全部数据!!!

-- 删除 年龄 = 17 的数据
delete from student where age = 17

mysql模块

  • 使用步骤

    // 1. 加载mysql模块
    const mysql = require('mysql');
    
    // 2. 创建连接对象
    const conn  = mysql.createConnection({
      host     : 'localhost',
      user     : 'me',
      password : 'secret',
      database : 'my_db'
    });
     
    // 3. 连接到mysql服务器
    conn.connect();
     
    // 4. 执行SQL语句
    conn.query('select * from student', (err, result) {
      if (err) throw err;
      console.log(result); // result 是执行SQL的结果
    });
     
    // 5. 关闭连接
    conn.end();
    

mysql模块初体验

  • 先创建一个空文件 名字为 01-mysql
  • 然后执行初始化 npm init -y
  • 然后安装 mysql 模块
  • 编写代码
// 1.引入 mysql 模块const mysql = require('mysql');// 2.创建链接const connection = mysql.createConnection({    // 2.1主机名 或 ip地址    host: 'localhost',    // 2.2用户名    user: 'root',    // 2.3密码    password: 'wanghao',    // 2.4数据库名称    database: 'sy126',});// 3.开始连接connection.connect();// 4.开始查询// 回调函数(错误信息,查询结果,字段?)connection.query('select * from student', function (error, results, fields) {    if (error) {        // 如果出错,错误处理        console.log('error');        console.log(error);    } else {        // 正常查询        console.log('查询成功');        console.log(results.length);        // results  数组        console.table(results);    }});connection.end();

新增

SQL语句: insert into student (username,sex,age) values(“法外”,“男”,17)

const mysql = require('mysql');const connection = mysql.createConnection({    host: 'localhost',    user: 'root',    password: 'wanghao',    database: 'sy126',});connection.connect();connection.query('insert into student (username,sex,age) values("法外","男",17)', function (error, results, fields) {    if (error) {        // 如果出错,错误处理        console.log('error');        console.log(error);    } else {        // 正常查询        console.log('新增成功');        console.log(results);    }});connection.end();

修改

SQL语句: update student set sex = “女” where age = 33

const mysql = require('mysql');

const connection = mysql.createConnection({
    host: 'localhost',
    user: 'root',
    password: 'wanghao',
    database: 'sy126',
});

connection.connect();

connection.query('update student set sex = "女" where age = 33', function (error, results, fields) {
    if (error) {
        // 如果出错,错误处理
        console.log('error');
        console.log(error);
    } else {
        // 正常查询
        console.log('修改成功');
        console.log(results);
    }
});

connection.end();

删除

SQL语句: delete from student where age = 17

const mysql = require('mysql');

const connection = mysql.createConnection({
    host: 'localhost',
    user: 'root',
    password: 'wanghao',
    database: 'sy126',
});

connection.connect();

connection.query('delete from student where age = 17', function (error, results, fields) {
    if (error) {
        // 如果出错,错误处理
        console.log('error');
        console.log(error);
    } else {
        // 正常查询
        console.log('修改成功');
        console.log(results);
    }
});

connection.end();

express和mysql模块结合 - 综合了 ( 增 删 改 查 )

// express mysql
const express = require('express');

const app = express();

// 处理post请求
app.use(express.urlencoded());

// 1 定义 一个接口
// 1.1 url http://127.0.01:8001/getStudents
// 1.2 get
// 1.3 返回 student 表格中 所有数据
app.get('/getStudents', (req, res) => {
    const mysql = require('mysql');

    const connection = mysql.createConnection({
        host: 'localhost',
        user: 'root',
        password: 'wanghao',
        database: 'sy126',
    });

    connection.connect();

    connection.query('select * from student', function (error, results, fields) {
        if (error) {
            console.log('error');
            console.log(error);
        } else {
            console.log('查询成功');
            // console.log(results.length);
            // console.table(results);

            // 数据返回给前端
            res.send(results);
        }
    });

    connection.end();
});

// 2 定义 一个接口
// 2.1 url http://127.0.01:8001/addStudents
// 2.2 post 请求 {username,sex,age}
// 2.3 成功或者失败的提示即可
// 2.4 执行真正 数据库添加数据
app.post('/addStudents', (req, res) => {
    // 先解构获取 post请求 的参数
    const { username, sex, age } = req.body;

    const mysql = require('mysql');

    const connection = mysql.createConnection({
        host: 'localhost',
        user: 'root',
        password: 'wanghao',
        database: 'sy126',
    });

    connection.connect();

    // 需要我们修改的地方  特别要注意es6 模板字符和 sql规定的引号!!
    connection.query(`insert into student (username,sex,age) values("${username}","${sex}",${age})`, function (error, results, fields) {
        if (error) {
            res.send('新增失败');
            console.log(error);
        } else {
            res.send('新增成功');
            console.log(results);
        }
    });

    connection.end();
});

// 3 定义 一个接口
// 3.1 url http://127.0.01:8001/updateStudents
// 3.2 post 请求 {id,username,sex,age}
// 3.3 成功或者失败的提示即可
app.post('/updateStudents', (req, res) => {
    // 解构获取 post请求 的参数
    const { id, username, sex, age } = req.body;

    const mysql = require('mysql');

    const connection = mysql.createConnection({
        host: 'localhost',
        user: 'root',
        password: 'wanghao',
        database: 'sy126',
    });

    connection.connect();

    // sql语句和es6 模板字符 处理 小心!!
    connection.query(
        `update student set username = "${username}" , sex = "${sex}" , age = ${age} where id = ${id}`,
        function (error, results, fields) {
            if (error) {
                // 如果出错,错误处理
                console.log(error);
                res.send('修改错误');
            } else {
                // 正常查询
                console.log(results);
                res.send('修改成功');
            }
        }
    );

    connection.end();
});

// 4 定义 一个接口
// 4.1 url http://127.0.01:8001/deleteStudents
// 4.2 get  id=8 把id带过去
// 4.3 成功或者失败的提示即可
app.get('/deleteStudents', (req, res) => {
    // 解构获取 get请求 的参数  req.query
    const { id } = req.query;

    const mysql = require('mysql');

    const connection = mysql.createConnection({
        host: 'localhost',
        user: 'root',
        password: 'wanghao',
        database: 'sy126',
    });

    connection.connect();

    connection.query(`delete from student where id = ${id}`, function (error, results, fields) {
        if (error) {
            // 如果出错,错误处理
            console.log(error);
            res.send('删除失败');
        } else {
            // 正常查询
            console.table(results);
            res.send('删除成功');
        }
    });

    connection.end();
});

app.listen(8001, () => {
    console.log('8001 is running ');
});

封装mysql

// express mysql
const express = require('express');

const app = express();

// 处理post请求
app.use(express.urlencoded());

// 引入封装的函数
const sqlHelper = require('./db/sqlHelper');

// 1 定义 一个接口
// 1.1 url http://127.0.01:8001/getStudents
// 1.2 get
// 1.3 返回 student 表格中 所有数据
app.get('/getStudents', (req, res) => {
    sqlHelper('select * from student', function (error, results, fields) {
        if (error) {
            console.log('error');
            console.log(error);
        } else {
            console.log('查询成功');
            // console.log(results.length);
            // console.table(results);

            // 数据返回给前端
            res.send(results);
        }
    });
});

// 2 定义 一个接口
// 2.1 url http://127.0.01:8001/addStudents
// 2.2 post 请求 {username,sex,age}
// 2.3 成功或者失败的提示即可
// 2.4 执行真正 数据库添加数据
app.post('/addStudents', (req, res) => {
    // 先解构获取 post请求 的参数
    const { username, sex, age } = req.body;

    // 需要我们修改的地方  特别要注意es6 模板字符和 sql规定的引号!!
    sqlHelper(`insert into student (username,sex,age) values("${username}","${sex}",${age})`, function (error, results, fields) {
        if (error) {
            res.send('新增失败');
            console.log(error);
        } else {
            res.send('新增成功');
            console.log(results);
        }
    });
});

// 3 定义 一个接口
// 3.1 url http://127.0.01:8001/updateStudents
// 3.2 post 请求 {id,username,sex,age}
// 3.3 成功或者失败的提示即可
app.post('/updateStudents', (req, res) => {
    // 解构获取 post请求 的参数
    const { id, username, sex, age } = req.body;

    // sql语句和es6 模板字符 处理 小心!!
    sqlHelper(
        `update student set username = "${username}" , sex = "${sex}" , age = ${age} where id = ${id}`,
        function (error, results, fields) {
            if (error) {
                // 如果出错,错误处理
                console.log(error);
                res.send('修改错误');
            } else {
                // 正常查询
                console.log(results);
                res.send('修改成功');
            }
        }
    );
});

// 4 定义 一个接口
// 4.1 url http://127.0.01:8001/deleteStudents
// 4.2 get  id=8 把id带过去
// 4.3 成功或者失败的提示即可
app.get('/deleteStudents', (req, res) => {
    // 解构获取 get请求 的参数  req.query
    const { id } = req.query;

    sqlHelper(`delete from student where id = ${id}`, function (error, results, fields) {
        if (error) {
            // 如果出错,错误处理
            console.log(error);
            res.send('删除失败');
        } else {
            // 正常查询
            console.table(results);
            res.send('删除成功');
        }
    });
});

app.listen(8001, () => {
    console.log('8001 is running ');
});

db/sqlHelper.js

// 1.引入 mysql 模块
const mysql = require('mysql');

module.exports = (sql, callback) => {
    // 2.创建链接
    const connection = mysql.createConnection({
        // 2.1主机名 或 ip地址
        host: 'localhost',
        // 2.2用户名
        user: 'root',
        // 2.3密码
        password: 'wanghao',
        // 2.4数据库名称
        database: 'sy126',
    });

    // 3.开始连接
    connection.connect();

    // 4.开始查询
    // 回调函数(错误信息,查询结果,字段?)
    connection.query(sql, callback);

    connection.end();
};

脚本(代码) 新建数据库和数据表

  1. 新建数据库 herodb

  2. 查询中运行代码 创建 数据表 hero

    -- 创建hero表,记录英雄信息
    create table heros(
    	id int not null primary key auto_increment, 
    	name varchar(255) not null, 
    	gender varchar(255),
    	img varchar(255),
    	isdelete tinyint default 0
    )
    character set utf8;
    
    
  3. 运行代码 创建数据表 user

    -- 创建user表,用来记录用户注册信息
    create table user (
    	id int not null primary key auto_increment, 
    	username varchar(255) not null, 
    	password varchar(255) not null
    )
    character set utf8;
    
  4. 查看数据表,如果没有,关闭连接在重启查看.

搭建项目的基本结构

  1. 新建文件夹 node68

  2. 初始化 npm init -y

  3. 安装 npm i express

  4. 新建基本的文件

    1. app.js

      const express = require('express');
      const app = express();
      const hero = require('./routers/hero');
      
      app.use('/', hero);
      
      app.listen(8001, () => {
          console.log('8001 is running ');
      });
      
      
    2. 英雄路由文件 (简单写个接口测试)

      routers/hero.js

      const express = require('express');
      const Router = express.Router();
      
      Router.get('/search', (req, res) => {
          res.send('英雄 测试');
      });
      
      module.exports = Router;
      
      
  5. 编写路由接口代码,使用 Postman 工具管理测试

    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yAup71kl-1632398276355)(images/postman项目管理01.png)]
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uMQbrPhC-1632398276356)(images/postman项目管理02.png)]

接口实现

  1. 数据来自于数据库
  2. 在node中使用 mysql模块来操作数据库
  3. 安装和使用mysql模块
  4. mysql查询代码封装
  5. 才是在接口中直接使用!!
  6. 统一了接口响应的数据格式
  7. 查询了指定字段(不返回 isdelete 给用户)

数据库的 isdelete 字段

isdelete是否删除 软删除

  1. 0 false 不删除
  2. 1 true 表示删除

文件上传

  1. 借助了第三方模块的帮助 multer
  2. 成功上传好文件之后,想要在浏览器中直接访问到 做静态托管

node 如何来生成 token

token 唯一 很长 隐藏个人信息的 字符串

下载第三方模块

  1. 安装

    npm i  jsonwebtoken 
    
  2. 关键代码

    const jwt = require("jsonwebtoken");
    
    /* 
    token
    1 格式是字符串
    2 可以设置过期时间 expiresIn: 一小时过期 
    3 可以隐藏 信息  { username: '小明' }
    4 使用的时候 要指定一个 钥匙  - 自己定义的字符串 
     */
    const token = jwt.sign({ username: '小明' }, 'node66', { expiresIn: '1h' });
    
    console.log(token);
    

MD5 加密

MD5 加密方法 策略

  1. MD5 不像token加密 (token加密 允许解密)
  2. MD5 只能加密 不存在解密!!

项目中如何使用

  1. 前端在填写表单的时候 - 登录

    1. 用户名 二狗 铁蛋
    2. 密码 123456
  2. 前端用户 点击 登录按钮的时候

    1. 使用 md5 对 密码加密处理
    2. 把表单数据 发送给后台
      1. 用户名 二狗
      2. 密码 md5加密过的 字符串
  3. 后端 把数据设置到数据库中

    1. 用户名 二狗
    2. 密码 - md5加密过
  4. 后端想要判断 当前的用户名和密码是否正确

    1. 用户名 - 数据库存的 和 现在用户新发送过来 都是 明文
    2. 密码 - 数据库存的是md5加密过, 用户执行新的登录,密码 也是加密过!!
  5. 小结

    1. md5 加密 用户的密码 是在前端加密还是后端加密!!!

      前端

    代码实现

    1. 使用第三方模块 md5

      npm i md5
      
    2. 关键代码

      const md5 = require("md5");
      // md5 加密
      const password = md5("fghjkl;dfghjkjhgfdsdfghgjhhgfdfgh");
      
      // 如何解密 ?  不存在加密
      console.log(password);
      

英雄数据接口代码:

app.js - 主文件

const express = require('express');
const app = express();
const hero = require('./routers/hero');
const user = require('./routers/user');
const jwt = require('express-jwt');

// 处理post请求
app.use(express.urlencoded());

// 静态托管图片
app.use('', express.static('./uploads'));

// 使用中间件来验证 token

// secret 钥匙
// HS256 加密的算法
// unless 哪些接口不需要 验证token
// app.use(jwt({ secret: 'node66', algorithms: ['HS256'] }));  // 都要验证
app.use(jwt({ secret: 'node66', algorithms: ['HS256'] }).unless({ path: ['/user/login', '/user/register'] }));

app.use('/hero', hero);
app.use('/user', user);

app.listen(8001, () => {
    console.log('8001 is running ');
});

routers/hero.js - 英雄路由

/* 

1 在所有的接口响应值中  一些规范
  1 返回值 一般是对象格式
    code: 后端自己可以的定义 错误码   “0:正常 , 1:网络繁忙 2 :没有权限,200:查询成功”
    msg:文字提示说明 和 code 来搭配 
    data: 真实的数据的返回值!! 

  2 code 错误码  200 正常  500 错误!! 

*/

const express = require('express');

const Router = express.Router();
const sqlHelper = require('../utils/sqlHelper');

const path = require('path');
const multer = require('multer');
const storage = multer.diskStorage({
    // 指定存放文件的文件夹 地址
    destination: function (req, file, cb) {
        cb(null, 'uploads/');
    },
    // 地址文件的名称
    filename: function (req, file, cb) {
        console.log(file);

        // 获取文件的后缀名
        // 第一种: const extName = file.originalname.split('.')[1];
        const extName = path.extname(file.originalname); // .jpg

        // 随机生成一串 文件名
        const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
        // 对应第一种:  cb(null, uniqueSuffix + '.' + extName);
        cb(null, uniqueSuffix + extName);
    },
});
const upload = multer({ storage: storage });

// 查询所有  get
Router.get('/getHeroList', (req, res) => {
    sqlHelper('select id,name,gender,img from heros where isdelete = 0', function (err, results) {
        if (err) {
            console.log(err.message);
            res.send({
                code: 500,
                data: null,
                msg: '查询所有英雄失败',
            });
        } else {
            console.log('查询所有英雄成功');
            res.send({
                code: 200,
                data: results,
                msg: '查询所有英雄成功',
            });
        }
    });
});

// 查询单个  get
Router.get('/getHeroById', (req, res) => {
    // 解构获取 get请求 的参数  req.query
    const { id } = req.query;

    sqlHelper(`select id,name,gender,img from heros where id = ${id} and isdelete = 0`, function (err, results) {
        if (err) {
            console.log(err.message);
            res.send({
                code: 500,
                data: null,
                msg: '查询单个英雄失败',
            });
        } else {
            console.log('查询单个英雄成功');
            res.send({
                code: 200,
                data: results,
                msg: '查询单个英雄成功',
            });
        }
    });
});

// 添加英雄  post
Router.post('/addHero', (req, res) => {
    // 先解构获取 post请求 的参数
    const { name, gender, img } = req.body;

    sqlHelper(`insert into heros (name,gender,img) values("${name}",'${gender}','${img}') `, function (err, results) {
        if (err) {
            console.log(err.message);
            res.send({
                code: 500,
                msg: '添加英雄失败',
            });
        } else {
            console.log('添加英雄成功');
            res.send({
                code: 200,
                msg: '添加英雄成功',
            });
        }
    });
});

// 更新英雄  post
Router.post('/updateHero', (req, res) => {
    // 先解构获取 post请求 的参数
    const { id, name, gender, img } = req.body;

    sqlHelper(`update heros set name = "${name}" , gender = "${gender}" , img = '${img}' where id = ${id}`, function (err, results) {
        if (err) {
            console.log(err.message);
            res.send({
                code: 500,
                msg: '更新英雄失败',
            });
        } else {
            console.log('更新英雄成功');
            res.send({
                code: 200,
                msg: '更新英雄成功',
            });
        }
    });
});

// 删除单个英雄  get
Router.get('/delHeroById', (req, res) => {
    // 解构获取 get请求 的参数  req.query
    const { id } = req.query;

    sqlHelper(`delete from heros where id = ${id}`, function (err, results) {
        if (err) {
            console.log(err.message);
            res.send({
                code: 500,
                msg: '删除单个英雄失败',
            });
        } else {
            console.log('删除单个英雄成功');
            res.send({
                code: 200,
                msg: '删除单个英雄成功',
            });
        }
    });
});

// 上传英雄头像  post
Router.post('/uploadFile', upload.single('cover'), (req, res) => {
    console.log(req.file);
    // res.send('上传文件成功,返回改文件上传后的 地址');

    // 2.1 返回给前端的路径,需要自己拼接,不需要加 upload/ 文件目录 !
    res.send('http://127.0.0.1:8001/' + req.file.path);
});

module.exports = Router;

routers/user.js - 用户路由

const express = require('express');
const Router = express.Router();
const sqlHelper = require('../utils/sqlHelper');
const jwt = require('jsonwebtoken');

// 注册 post请求
Router.post('/register', (req, res) => {
    /* 
  1 获取用户 post请求过来 数据 req.body  (username , password)
  2 要先搜索一下 数据库 有没有已经使用了 名称 
  3 第一次查询结束后
    1 对查询结果 做 判断
      1 如果报错 直接返回 响应 注册失败
      2 如果 没有报错
  4 第一次查询后 没有报错
    1 还得去判断 查询结果 数组 有没有长度 
    2 如果长度 等于 0 ,表示以前没有注册过 现在可以注册-添加数据
    3 如果长度 不等于 0  表示 以前有注册过了,现在 响应 注册失败即可
 
   */

    const { username, password } = req.body;
    // 1.查询数据库中是否已经存在相同的username
    sqlHelper(`select * from user where username = '${username}'`, (err1, results1) => {
        if (err1) {
            console.log(err1.message);
            res.send({ code: 500, data: null, msg: '注册失败' });
        } else {
            // res.send({ code: 200, data: results1, msg: '查询成功' });
            // 2.查询成功 还判断有没有数据被查出来
            if (results1.length === 0) {
                // res.send({ code: 200, data: null, msg: '允许注册' });

                // 3.数据库中没有当前要注册的用户  所以允许注册  直接去操作数据库完成 注册-添加
                sqlHelper(`insert into user(username,password) values('${username}','${password}')`, (err2, results2) => {
                    if (err2) {
                        res.send({ code: 500, data: null, msg: '注册失败' });
                    } else {
                        res.send({ code: 200, msg: '注册成功' });
                    }
                });
            } else {
                // 找到了相同的名字  已经存在该用户了  不允许注册
                res.send({ code: 500, data: null, msg: '该用户已存在' });
            }
        }
    });
});

//登陆 post请求
Router.post('/login', (req, res) => {
    /* 
  1 接收 用户的post请求参数 (username,password)
  2 拿用户名和密码去数据库中查询 
  3 如果查到了 表示 登录成功
  4 如果查不到 表示 帐号或者密码错误
  
   */

    const { username, password } = req.body;
    sqlHelper(`select * from user where username = '${username}' and password = '${password}'`, (err, results) => {
        if (err) {
            console.log(err.message);
            res.send({ code: 500, data: null, msg: '账号或密码错误' });
        } else {
            if (results.length === 0) {
                //  找到不到这个账号密码 登录失败
                res.send({ code: 500, data: null, msg: '账号或密码错误' });
            } else {
                // 登录成功

                // 生成token
                const token = jwt.sign({ username }, 'node68', { expiresIn: '1h' });
                res.send({ code: 200, data: null, msg: '登录成功', token });
            }
        }
    });
});

module.exports = Router;

utils/sqlHelper.js - mysql函数封装

// 1.引入 mysql 模块
const mysql = require('mysql');

module.exports = (sql, callback) => {
    // 2.创建链接
    const connection = mysql.createConnection({
        // 2.1主机名 或 ip地址
        host: 'localhost',
        // 2.2用户名
        user: 'root',
        // 2.3密码
        password: 'wanghao',
        // 2.4数据库名称
        database: 'herodb',
    });

    // 3.开始连接
    connection.connect();

    // 4.开始查询
    // 回调函数(错误信息,查询结果,字段?)
    connection.query(sql, callback);

    connection.end();
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Henry_ww

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

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

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

打赏作者

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

抵扣说明:

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

余额充值