什么是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 环境
-
下载对应版本的安装包(https://nodejs.org/zh-cn/)
注意:
1.win10 可以随意安装任何版本的Node
2.但是win7只能安装12及其以下的版本Node[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TqLy1zJB-1632398276317)(images/01.png)]
-
点击下载到的安装包,一路下一步默认安装
注意:
1.不能安装到中文目录如d:/软件,建议一直点击next即可
2.安装完成之后, 它不会在桌面出现快捷图标[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1tpichw3-1632398276328)(images/02.png)]
-
打开小黑窗输入 node -v 能看到版本号表示安装成功
在任意文件夹中最上方的路径中输入cmd后回车即可打开[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QMFTj7Vy-1632398276330)(images/03.png)]
小黑窗打开方式
-
小黑窗: 命令行工具
-
window系统打开的几种方式:
-
按 windows + R 运行窗口中输入cmd 回车即可打开
-
在任意目录的最上方路径输入框中输入 cmd 回车接口打开 (推荐)
-
在任意目录中按住 shift键 + 鼠标右键后在弹出菜单中点击 在此处打开命令窗口 或 在此处打开PowerShell窗口即可打开
-
在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请求的案例
-
需求:
-
用户执行post请求
-
url http://127.0.0.1:8001/addHero
-
提交的参数 {naem:“英雄的名称”,gender:“男”}
-
服务端
- 验证是不是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 下载和使用第三方模块
-
新建空的文件夹 ( 名称不能是中文 )
-
在空的文件内
npm init --yesnpm init -y
-
下载第三方的模块
npm install 模块名称npm i 模块名称npm install day.jsnpm i day.js
-
下载指定版本的第三方包
npm install day.js@1.10.6npm i day.js@1.10.6
-
新建一个app.js文件
// 引入 第三方模块 写法 类似 引入核心模块 const dayjs = require("dayjs");// dayjs 如何去使用 去查看它的使用文档。。。// format 格式化console.log(dayjs(Date.now()).format("YYYY-MM-DD HH:mm:ss"));
执行 npm install 变化发生
-
执行下载包
npm install dayjs
-
本地项目中多了一个文件夹
node_modules/
用来存放第三方模块 -
仔细观察
package.json
多了一个字段dependencies
"dependencies": { "dayjs": "^1.10.7" }
npm 卸载指定的第三方模块
手动卸载
-
手动删除掉
package.json
文件中 字段dependencies
里面 模块的信息"dependencies": { "dayjs": "^1.10.6", "jquery": "^3.6.0" }
手动删除
"dependencies": { "jquery": "^3.6.0" }
-
手动去删除
node_modules
中的dayjs
文件夹 -
npm 自带 卸载功能
npm uninstall 模块的名称npm uninstall jquery
解决下载第三方模块慢的问题
-
打开命令行窗口
npm install -g nrm
-
下载成功后 测试
nrm test
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MoohXs9S-1632398276339)(images/npm-01.png)]
- 切换镜像源 (npm下载地址)
nrm use tencent
- 以后还是和以前一样正常使用npm即可
npm install dayjs
全局安装和本地安装的区别
-
全局
npm install -g 包的名称
-
在某个项目内
npm install 包名称
nodemon 全局安装
监听本地js文件的变化,自动重启
-
全局安装 nodemon
npm install -g nodemon
-
找到你想要运行 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 工作中常用
-
要引入的文件名
index.js index.json
-
引入
require("./index");// 如果引入的模块是自定义模块 建议加上 ./ 相对路径
-
要引入的文件
main/index.js
-
引入
require("./main");
-
核心模块和第三模块
require("模块名称")
Express框架
Express 是一个基于 Node.js 平台,快速、开放、极简的 web 开发框架,可以替代http模块
安装
- 安装 node.js 后,新建一个文件夹
- 文件夹内打开小黑窗
- npm init --yes 命令创建一个 package.json 文件
- npm install express 命令安装 Express
- 检查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.send(‘要响应的数据’) 它会自动增加content-type响应头,支持直接js对象参数作为响应数据
- 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 新建连接
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fD3ngE0T-1632398276346)(images/新建连接01.png)]
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BsLUjyOP-1632398276346)(images/新建连接02.png)]
-
默认灰色,双击连接变绿[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EuEq9liR-1632398276347)(images/新建连接03.png)]
-
可以删除,右键选择删除
navicat 新建数据库
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jv9jHyJU-1632398276347)(images/新建数据库01.png)]
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hL12pU6f-1632398276348)(images/新建数据库02.png)]
- 可以删除,右键选择
新建 student数据表
-
新建表[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Aoxe4LKB-1632398276349)(images/新建表01.png)]
-
弹窗 要求我们添加 字段信息[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Vb0SF9v-1632398276349)(images/新建表02.png)]
-
添加栏位,[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9dFe38HX-1632398276350)(images/新建表03.png)]
-
student数据表字段的设置
- int 是 MySQL中的整型
- varchar 是 MySQL中的字符串类型
- id必填,所以不是null
- username必填,所以不是null
- id设为主键,则id值不能重复
- id设置自动递增,则添加数据时会自增
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hN6yDT2H-1632398276351)(images/新建表04.png)]
-
添加成功[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LyhYLzNs-1632398276351)(images/新建表05.png)]
手动添加数据
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ExLYKhP8-1632398276352)(images/添加数据01.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p7b7oXBk-1632398276352)(images/添加数据02.png)]
查询数据操作
- 点击查询[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cwjbQxQj-1632398276353)(images/查询数据01.png)]
- 新建查询[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nE75nh1D-1632398276354)(images/查询数据02.png)]
- 跳出弹框,编写SQL语句
SQL语句
查询
-
SELECT 字段, 字段, … FROM 表名
-
select 字段, 字段, … from 表名 where 条件
- 查询所有
-- 查询student表格中 所有的数据 *: 所有字段
select * from student
- 查询所有数据中的 指定 的字段 — , 分隔 (英文)
select username,age from student
- 查询带条件 — 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();
};
脚本(代码) 新建数据库和数据表
-
新建数据库 herodb
-
查询中运行代码 创建 数据表 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;
-
运行代码 创建数据表
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;
-
查看数据表,如果没有,关闭连接在重启查看.
搭建项目的基本结构
-
新建文件夹
node68
-
初始化
npm init -y
-
安装
npm i express
-
新建基本的文件
-
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 '); });
-
英雄路由文件 (简单写个接口测试)
routers/hero.js
const express = require('express'); const Router = express.Router(); Router.get('/search', (req, res) => { res.send('英雄 测试'); }); module.exports = Router;
-
-
编写路由接口代码,使用 Postman 工具管理测试
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yAup71kl-1632398276355)(images/postman项目管理01.png)]
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uMQbrPhC-1632398276356)(images/postman项目管理02.png)]
接口实现
- 数据来自于数据库
- 在node中使用 mysql模块来操作数据库
- 安装和使用mysql模块
- mysql查询代码封装
- 才是在接口中直接使用!!
- 统一了接口响应的数据格式
- 查询了指定字段(不返回
isdelete
给用户)
数据库的 isdelete 字段
isdelete
是否删除 软删除
- 值
0
false
不删除 - 值
1
true
表示删除
文件上传
- 借助了第三方模块的帮助
multer
- 成功上传好文件之后,想要在浏览器中直接访问到 做静态托管
node 如何来生成 token
token 唯一 很长 隐藏个人信息的 字符串
下载第三方模块
-
安装
npm i jsonwebtoken
-
关键代码
const jwt = require("jsonwebtoken"); /* token 1 格式是字符串 2 可以设置过期时间 expiresIn: 一小时过期 3 可以隐藏 信息 { username: '小明' } 4 使用的时候 要指定一个 钥匙 - 自己定义的字符串 */ const token = jwt.sign({ username: '小明' }, 'node66', { expiresIn: '1h' }); console.log(token);
MD5 加密
MD5 加密方法 策略
- MD5 不像token加密 (token加密 允许解密)
- MD5 只能加密 不存在解密!!
项目中如何使用
-
前端在填写表单的时候 - 登录
- 用户名 二狗 铁蛋
- 密码 123456
-
前端用户 点击 登录按钮的时候
- 使用 md5 对 密码加密处理
- 把表单数据 发送给后台
- 用户名 二狗
- 密码 md5加密过的 字符串
-
后端 把数据设置到数据库中
- 用户名 二狗
- 密码 - md5加密过
-
后端想要判断 当前的用户名和密码是否正确
- 用户名 - 数据库存的 和 现在用户新发送过来 都是 明文
- 密码 - 数据库存的是md5加密过, 用户执行新的登录,密码 也是加密过!!
-
小结
-
md5 加密 用户的密码 是在前端加密还是后端加密!!!
前端
代码实现
-
使用第三方模块
md5
npm i md5
-
关键代码
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();
};