Node.js学习笔记

目录

一、基础

1.1 Node.js简介

1.2 nvm

1.3 npm与包

1.4 npx

1.5 其他包管理器

二、模块化

2.1 概念

2.2 加载模块

2.3 向外暴露成员

三、内置模块

3.1 fs 模块

3.2 path 模块

3.3 http 模块

四、Express

4.1 基础

4.2 使用方法

4.3 req 与 res

4.4 静态资源托管

4.5 Router

4.6 CORS

4.7 接口编写

4.8 中间件

 4.9 express-generato

五、基于 express 案例 

5.1 文件上传与下载 

六、Node.js中的MySQL

5.1 MySQL 基本使用

5.2 SQL语句

5.3 在项目中操作数据库

七、JWT身份认证

6.1 概念

6.2 Express 中的 JWT 

免责说明


一、基础

1.1 Node.js简介

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 的后端运行环境,是单进程单线程应用程序;

Node.js 中无法调用 DOM 和 BOM 等浏览器内置 API。

官网:Node.js

 基本使用方法:

        查看是否安装成功:终端输入命令 node –v 查看 Node.js 版本号。

        执行js文件:切换到js文件目录 → 终端输入 node 文件路径

Tips:终端中的快捷键:

         ↑ 键 ,快速定位上一次执行的命令

        tab 键,快速补全路径

        esc 键,快速清空当前已输入的命令

        cls ,清空终端

        ctrl+c 键,终止服务器

1.2 nvm

nvm:nodejs的版本管理工具。

nvm安装包下载地址:Releases · coreybutler/nvm-windows · GitHub

注意:新建nvm和nodejs文件夹,路径尽量不要出现中文,双击安装包安装。

nvm的基本使用:

nvm off                     // 禁用node.js版本管理(不卸载任何东西)
nvm on                      // 启用node.js版本管理
nvm install <version>       // 安装node.js的命名 version是版本号 例如:nvm install 8.12.0
nvm uninstall <version>     // 卸载node.js是的命令,卸载指定版本的nodejs,当安装失败时卸载使用
nvm ls                      // 显示所有安装的node.js版本
nvm list available          // 显示可以安装的所有node.js的版本
nvm use <version>           // 切换到使用指定的nodejs版本
nvm v                       // 显示nvm版本
nvm install stable          // 安装最新稳定版

1.3 npm与包

包:Node.js 中的第三方模块又叫做包。

npm:Node Package Manager 简称 npm 包管理工具 ,安装node自带npm,npm社区官网:npm | Home

npm基本使用:

①  初始化清单文件 :npm init -y(得到 package.json 文件,有则略过此命令)

② 下载包 :

       下载项目依赖包: npm i 软件包名称 

        下载全局包: npm i 软件包名称  -g

        下载指定版本包:npm i 软件包名称@版本号

        Tips:npm install 可简写 npm i

        解决下载包慢的问题:配置 npm 淘宝镜像

        npm config set registry http://registry.npm.taobao.org

③ 常用命令:        

npm -v                      // 查看 npm 版本号

npm i 包的完整名称           // 在项目中安装最新版本的包

npm i 包的完整名称@版本号    // 在项目中安装指定版本的包,会覆盖之前下载的包

npm uni 包名                // 卸载指定包 

npm i 包名 -D               // 安装指定包,并记录到devDependdencies节点中

npm i 软件包名 -g           // 下载全局软件包

npm run 自定义命令          // 运行自定义命令

包的分类:

       ①  项目包:项目执行所依赖;

       ②  全局包:在执行 npm install 命令时,如果提供了 -g 参数,则会把包安装为全局包,只有工具性质的包,才有全局安装的必要性。因为它们提供了好用的终端命令。

        全局包 默认安装位置: C:\Users\xxx\AppData\Roaming\npm\node_modules,如果使用nvm方式安装的nodejs,默认安装位置为:xxx/nodejs/node_modules,此nodejs文件夹与nvm处于同一个文件夹下。

文件目录介绍:

        node_modules 文件夹:存放所有已安装到项目中的包。

        package-lock.json 配置文件:记录 node_modules 下包的下载信息。

        package.json :包管理配置文件。

Tips:关于 package.json

        package.json 中必须包含 name,version,main 这三个属性,分别代表包的名字、版本号、包的入口;

        dependencies(生产环境) :用来记录使用 npm install 命令安装了哪些包;

        devDependencies (开发环境):如果某些包只在项目开发阶段会用到,在项目上线之后不会用到,则建议把这些包记录到 devDependencies 节点中。

解决下包慢的问题:添加淘宝镜像,具体操作不赘述。

Tips:npm i 中 -S, -D,-g 的区别

        -S  等同于--save,保存在package.json文件中,是在dependencies 下,生产环境,默认可省略;

        -D  等同于--save-dev,也保存在package.json文件中,是在devDependencies下,本地开发环境

        -g  等同于--global的简写,对模块进行全局安装,作用于全局环境下。

1.4 npx

npx是一个由Node.js官方提供的用于快速执行npm包中的可执行文件的工具。它可以帮助我们在不全局安装某些包的情况下,直接运行该包提供的命令行工具。npx会在执行时,检查本地项目中是否安装了对应的依赖,如果没有安装则会自动下载安装,并执行命令。如果本地已经存在该依赖,则直接执行命令。

npx 不会像 npm 或 yarn 一样将包下载到本地的 node_modules 目录中。

eg: npx nodemon xxx

1.5 其他包管理器

1.5.1 yarn

 yarn 是一个新的包管理工具,yarn 弥补了 npm 的一些缺陷,执行速度更快。yarn 默认有一个 yarn.lock 文件锁定版本,保证环境统一。

安装 yarn:npm install -g yarn

yarn 的常用命令:

yarn -v                  // 查看版本

yarn add 包名@版本        // 安装指定版本的包

yarn global add 包名     // 安装全局包

yarn upgrade 包名        // 升级指定包

yarn remove 包名         // 移除指定包

yarn 自定义命令           // 执行自定义命令

1.5.2 pnpm

        一优势:比同类工具快2倍左右、节省磁盘空间 

安装:npm install -g pnpm

        用法与yarn类似

二、模块化

2.1 概念

Node.js 遵循了 CommonJS 模块化规范,CommonJS 规定了模块的特性和各模块之间如何相互依赖。原生JavaScript遵循 ECMAScript 模块化规范。

Tips:Node.js 默认支持 CommonJS 标准语法如需使用 ECMAScript 标准语法,在运行模块所在文件夹新建 package.json 文件,并设置 { "type" : "module" }

2.2 加载模块

// 1.加载内置模块
const fs = require("fs");

// 2.加载自定义模块
const custom = require("./custom.js");

// 3.加载第三方包
const express = require("express");

 模块加载机制:

2.3 向外暴露成员

语法:

        module.exports.变量 = { }

        module.exports = { }

        exports.变量 

注意:如果要对外暴露属性或方法,就用 exports 就行,要暴露对象(类似class,包含了很多属性和方法),就用 module.exports

三、内置模块

3.1 fs 模块

概念:fs 模块是 Node.js 官方提供的、用来操作文件的模块。

语法:

①  const fs = require('fs'):加载 fs 模块对象 。

②  fs.writeFile(file,data[,options],callback) :向指定的文件写入内容。

        参数1:必选参数,需要指定一个文件路径的字符串,表示文件的存放路径。

        参数2:必选参数,表示要写入的内容。

        参数3:可选参数,表示以什么格式写入文件内容,默认值是 utf8。

        参数4:必选参数,文件写入完成后的回调函数。

③  fs.readFile(path,[,options],callback) :读取指定文件中的内容,异步读取;

        fs.readFileSync() 同步读取。

        参数1:必选参数,字符串,表示文件的路径。

        参数2:可选参数,表示以什么编码格式来读取文件。

        参数3:必选参数,文件读取完成后,通过回调函数拿到读取的结果。

// 1.加载 fs 模块
const fs = require("fs");

// 2.写入文件内容
fs.writeFile('./files/1.txt', 'hello node', function(err) {
  if (err) {
    return console.log('文件写入失败!' + err.message)
  }
  console.log('文件写入成功!')
})

// 3.读取文件内容
fs.readFile('./files/1.txt', 'utf8', function(err, dataStr) {
  if (err) {
    return console.log('读取文件失败!' + err.message)
  }
  console.log('读取文件成功!' + dataStr)
})

3.2 path 模块

概念:path 模块是 Node.js 官方提供的、用来处理路径的模块。

__dirname:内置变量,表示当前文件所处的目录。

语法:

        ① const path = require('path'): 加载path模块。

        ② path.join(__dirname,'相对路径'):拼接路径。

        ③ path.basename(path[,ext ]) :获取路径中的文件名。

                path <string> 必选参数,表示一个路径的字符串;

                ext <string> 可选参数,表示文件扩展名;

                返回: <string> 表示路径中的最后一部分。

        ④ path.extname(path) :获取路径中的扩展名。

const fs = require("fs");
// 1.加载 path 模块
const path = require("path");
// 2.调用 path.join() 配合 __dirname 组成文件的绝对路径
fs.readFile(path.join(__dirname, './files/1.txt'), 'utf8', function(err, dataStr) {
  if (err) {
    return console.log(err.message)
  }
  console.log(dataStr)
})

3.3 http 模块

概念:http 模块是 Node.js 官方提供的、用来创建 web 服务器的模块。

使用 http 模块 创建一个基本的服务器:

        ① 导入http模块:const http = require('http')

        ② 创建 web 服务器实例:调用 http.createServer() 方法;

        ③ 为服务器实例绑定 request 事件,监听客户端的请求;

        ④ 启动服务器;

        ⑤ 运行 node命令执行文件。

// 1. 导入 http 模块
const http = require('http')
// 2. 创建 web 服务器实例
const server = http.createServer()
// 3. 为服务器实例绑定 request 事件,监听客户端的请求
server.on('request', function (req, res) {
  console.log('Someone visit our web server.')
})
// 4. 启动服务器
server.listen(8080, function () {  
  console.log('server running at http://127.0.0.1:8080')
})
//tops:8080端口号,http://127.0.0.1:本地ip地址

Tips:

        IP地址和域名是一 一对应的关系;

        127.0.0.1 对应的域名是 localhost,都代表本电脑;

        也可以指定局域网的IPv4地址进行访问

        端口号:标记服务器里不同功能的服务程序;

        端口号范围:0-65535 之间的任意整数,http 协议默认访问 80 端口(80可省略)。

        跨域:协议名与域名、端口号不同;

        跨站:顶级域名与二级域名不同。

四、Express

4.1 基础

概念:Express 是基于 Node.js 平台,快速、开放、极简的 Web 开发框架。本质是一个 npm 上的第三方包,提供了快速创建 Web 服务器的便捷方法,官网:Express - 基于 Node.js 平台的 web 应用开发框架 - Express中文文档 | Express中文网

安装:npm i express@4.17.1 (这里安装4.17.1版本)

nodemon:

        作用:监听项目文件的变动,当代码被修改后,nodemon 会自动帮我们重启项目

        安装:npm i -g nodemon

        使用:nodemon 文件路径 或  npx nodemon 文件路径

4.2 使用方法

// 1. 导入 express
const express = require('express')
// 2. 创建 web 服务器
const app = express()

const port = 8080 //端口号
const ip = "127.0.0.1" //本地主机IP地址,也可以使用局域网的IPv4地址

// 4. 监听客户端的 GET 和 POST 请求,并向客户端响应具体的内容
app.get('/user', (req, res) => {
  // 调用 express 提供的 res.send() 方法,向客户端响应一个 JSON 对象
  res.send({ name: 'zs', age: 20, gender: '男' })
})
app.post('/user', (req, res) => {
  // 调用 express 提供的 res.send() 方法,向客户端响应一个 文本字符串
  res.send('请求成功')
})
app.get('/', (req, res) => {
  // 通过 req.query 可以获取到客户端发送过来的 查询参数
  // 注意:默认情况下,req.query 是一个空对象
  console.log(req.query)
  res.send(req.query)
})
// 注意:这里的 :id 是一个动态的参数
app.get('/user/:ids/:username', (req, res) => {
  // req.params 是动态匹配到的 URL 参数,默认也是一个空对象
  console.log(req.params)
  res.send(req.params)
})

// 3. 启动 web 服务器
app.listen(port,ip, () => {
  console.log('express server running at http://127.0.0.1')
})

4.3 req 与 res

Tips:

// req 常用

req.query;  //获取客户端通过查询字符串(拼接到url的数据)发送到服务器的数据(一般为get请求)
req.body;   //通常用来获取POST请求中的数据
req.params; // 获取 URL 中,通过 : 匹配到的动态参数

// res 常用

res.send(); //把处理好的内容,发送给客户端

4.4 静态资源托管

概念:创建一个静态资源服务器,文件对外开放访问。

语法:app.use( [url,]express.static("文件夹相对路径") )

注意:如果要托管多个静态资源目录,请多次调用 express.static() 函数。

4.5 Router

概念:路由(Router)指的是客户端的请求与服务器处理函数之间的映射关系。

组成:请求类型、请求 URL 地址、处理函数:app.METHOD(PATH,HANDLER)

基本使用:

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

// 挂载路由
app.get('/', (req, res) => {
  res.send('hello world.')
})
app.post('/', (req, res) => {
  res.send('Post Request.')
})

app.listen(80, () => {
  console.log('http://127.0.0.1')
})

模块化路由的使用方法:

        ① 创建路由模块对应的 router.js 文件;

        ② 调用 express.Router() 函数创建路由对象;

        ③ 向路由对象上挂载具体的路由;

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

        ⑤ 使用 app.use() 函数注册路由模块;

        ⑥ 为路由模块添加前缀:与托管静态资源一样。

eg:

router.js

// 这是路由模块
// 1. 导入 express
const express = require('express')
// 2. 创建路由对象
const router = express.Router()

// 3. 挂载具体的路由
router.get('/user/list', (req, res) => {
  res.send('Get user list.')
})
router.post('/user/add', (req, res) => {
  res.send('Add new user.')
})

// 4. 向外导出路由对象
module.exports = router

app.js

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

// 1. 导入路由模块
const router = require('./03.router')
// 2. 注册路由模块
app.use('/api', router)

app.listen(80, () => {
  console.log('http://127.0.0.1')
})

4.6 CORS

接口的跨域问题: GET 和 POST接口不支持跨域请求。

解决方案:CORS(主流解决方案)

使用方法:

        ① 安装中间件:npm i cors;

        ② 导入中间件: const cors = require('cors')

        ③ 在 路由 之前调用 app.use(cors()) 配置中间件。

app.js

// 导入 cors 中间件
const cors = require("cors");
// 将 cors 注册为全局中间件 在 路由 之前调用!!!!!
app.use(cors());

4.7 接口编写

const express = require('express')
const router = express.Router()

// 在这里挂载对应的路由

// 不区别请求方法,'/*'无匹配路由时返回404
router.all('/*',(req, res) =>{
res.send(404)
})

// 定义 GET 接口
router.get('/get', (req, res) => {
  // 通过 req.query 获取客户端通过查询字符串,发送到服务器的数据
  const query = req.query
  // 调用 res.send() 方法,向客户端响应处理的结果
  res.send({
    status: 0, // 0 表示处理成功,1 表示处理失败
    msg: 'GET 请求成功!', // 状态的描述
    data: query, // 需要响应给客户端的数据
  })
})

// 定义 POST 接口
router.post('/post', (req, res) => {
  // 通过 req.body 获取请求体中包含的 url-encoded 格式的数据
  const body = req.body
  // 调用 res.send() 方法,向客户端响应结果
  res.send({
    status: 0,
    msg: 'POST 请求成功!',
    data: body,
  })
})

// 定义 PUT 接口
router.put('/put', (req, res) => {
  res.send({
    status: 0,
    msg: 'PUT请求成功',
  })
})

// 定义 DELETE 接口
router.delete('/delete', (req, res) => {
  res.send({
    status: 0,
    msg: 'DELETE请求成功',
  })
})

module.exports = router

4.8 中间件

4.8.1 基础

概念:指业务流程的中间处理环节。

 作用:多个中间件之间,共享同一份 req 和 res。基于这样的特性,我们可以在上游的中间件中,统一为 req 或 res 对象添加自定义的属性或方法,供下游的中间件或路由进行使用

格式:Express 的中间件,本质上就是一个 function 处理函数,中间件函数的形参列表中,必须包含 next 参数。而路由处理函数中只包含 req 和 res。next 函数的作用:next 函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由。

4.8.2 中间件的分类:

        ① 全局中间件:

        客户端发起的任何请求,到达服务器之后,都会触发的中间件;

        通过调用 app.use(中间件函数),即可定义一个全局生效的中间件;

        可使用 app.use() 连续定义多个全局中间件。客户端请求到达服务器之后,会按照中间件定义的先后顺序依次进行调用。

注意:除了错误级别的中间件,其他的中间件,必须在路由之前进行配置 ! ! ! 

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

// 定义第一个全局中间件
app.use((req, res, next) => {
  console.log('调用了第1个全局中间件')
  next()
})
// 定义第二个全局中间件
app.use((req, res, next) => {
  console.log('调用了第2个全局中间件')
  next()
})

// 定义一个路由
app.get('/user', (req, res) => {
  res.send('User page.')
})

app.listen(80, () => {
  console.log('http://127.0.0.1')
})

        ②局部中间件:

        不使用 app.use() 定义,只在当前路由生效的中间件。

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

// 1. 定义中间件函数
const mw1 = (req, res, next) => {
  console.log('调用了局部生效的中间件1')
  next()
}

const mw2 = (req, res, next) => {
  console.log('调用了局部生效的中间件2')
  next()
}

// 2. 创建路由
app.get('/', mw1,mw2, (req, res) => {
  res.send('Home page.')
})

// 也可以写成数组
app.get('/home', [ mw1,mw2 ], (req, res) => {
  res.send('Home page.')
})

app.listen(80, function () {
  console.log('Express server running at http://127.0.0.1')
})

4.8.3 自定义中间件


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

// 在路由之前,封装向客户端响应 处理失败 的结果,res.cc()
app.use((req, res, next) => {
  // status 默认值为1,表示失败的情况
  // err 的值可能是一个错误对象,也可能是字符串
  res.cc = function (err, status = 1) {
    res.send({
      status,
      message: err instanceof Error ? err.message : err,
    });
  };
  next();
});

//导入使用路由模块 注意路由位置
const router = express.Router() 
app.use('/api',router)

// 定义错误级别的中间件 路由之后
app.use((err, req, res, next) => {
  if (err instanceof xxx) {
    return res.cc(err);
  }
  // 未知的错误
  res.cc(err);
});

app.listen(8080, function () {
  console.log("api server running at http://127.0.0.1:8080");
});

4.8.4 常用内置中间件

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

//快速托管静态资源的内置中间件
app.use(express.static('./home')) 

// 解析表单中的 JSON 格式的数据
app.use(express.json()) 

// 解析表单中的application/x-www-form-urlencoded格式的数据
app.use(express.urlencoded({ extended: false })) 

app.post('/login', (req, res) => {
  // 在服务器端,可以通过 req.body 来获取 JSON 格式的表单数据和 url-encoded 格式的数据
  console.log(req.body)
  res.send('ok')
})

app.listen(80, function () {
  console.log('Express server running at http://127.0.0.1')
})

 4.9 express-generato

4.9.1 概念:通过应用生成器工具 express-generator 可以快速创建一个应用的骨架。

4.9.2 实现步骤:

① 安装express-generator全局包:

npm install -g express-generator

查看所有可执行命令: 

express -h 

② 创建项目文件夹并进入,终端输入命令: express ,自动生成应用骨架。

eg:创建了一个名称为 myapp 的 Express 应用。此应用将在当前目录下的 myapp 目录中创建,并且设置为使用 Pug 模板引擎(view engine)

express --view=pug myapp

③ 进入项目文件夹并安装所有依赖包

npm install

④ 运行项目(不同操作系统命令查看官网,这里是win指令)

npm start 

        然后在浏览器中打开 http://localhost:3000/ 网址就可以看到这个应用了 。

4.9.3 文档目录简介:

.
├── app.js              // 应用核心配置文件
├── bin                 // 可执行文件目录
│   └── www
├── package.json        // 项目依赖配置及开发者信息
├── public              // 静态文件根目录,存放图片、脚本、样式等文件
│   ├── images
│   ├── javascripts
│   └── stylesheets
│       └── style.css
├── routes              // 路由模块目录
│   ├── index.js
│   └── users.js
└── views               // 视图目录,用于存储所有的ejs模板
    ├── error.pug
    ├── index.pug
    └── layout.pug

Tips: package.json中的scripts属性是用于定义操作命令,比如默认的start,用 npm start 代表执行 node ./bin/www 命令,如果安装了 nodemon ,修改指令 node ./bin/www → nodemon ./bin/www ,可实现保存文件自动开启服务。

        目录详细可参考大佬写的文章 → Node.js开发框架Express4.x | 粉丝日志

五、基于 express 案例 

5.1 文件上传与下载 

 基于第三方包  formidable 实现表单 form-data 格式文件的上传。

formidable:最常用、最灵活、最快速的多部分表单数据流式解析器。

5.1.1 文件上传

        使用 formidable(3.5.1) 实现文件上传

const express = require("express");
// 导入 formidable 中 IncomingForm 模块 "formidable": "^3.5.1"
const { IncomingForm } = require("formidable");
const router = express.Router();

// formidable 配置项
const options = {
  encoding: "utf-8", //设置表单域的字符集
  uploadDir: "public/upload", //设置上传目录文件夹
  keepExtensions: true, //保留上传文件的后缀
  multiples: true, //支持多文本上传
};

router.post("/", (req, res, next) => {

  // 创建form对象接收客户端的formdata中的数据:使用formidable模块的IncomingForm
  let form = new IncomingForm(options);

  // 解析客户端的formdata中的数据并返回结果
  form.parse(req, (err, fields, files) => {
    if (err) {  
      return next(err);
    }
    res.send({ fields, files, meta: { msg: "上传成功", status: 200 } });
  });
});

module.exports = router;

        关于 formidable 其他配置项可查看官网文档。也可以使用 multer:GitHub - expressjs/multer 实现文件上传功能。

5.1.2 文件的下载

        后端部分:路由模块

const express = require("express");
const router = express.Router();
const path = require("path");

// 动态路由
router.get("/download/:file(*)", function (req, res, next) {

// 文件的绝对路径 = path.join(当前文件路径, 目标文件文件夹, 前端提供的文件相对路径)
let _path = path.join(__dirname, "files", req.params.file); 

  res.download(_path, function (err) {
    // 200状态
    if (!err) {
      return;
    }
    // 500状态
    if (err.status !== 404) {
      return next(err);
    }
    // 404状态
    res.statusCode = 404;
    res.send("没有这个文件!");
  });
});

module.exports = router;

        前端部分:点击 a 标签下载 功能

<a href="/download/文件.txt">某文件</a>

<-- 注意:href 属性值= /download + 对应路由模块路径关系 -->

六、Node.js中的MySQL

  安装,配置数据库不将赘述

5.1 MySQL 基本使用

        在终端中操作(需管理员权限):

        卸载数据库:sc delete MySQL80

        启动服务:net start MySQL80

        停止服务:net stop MySQL80

        登录数据库:mysql -u 数据库用户名 -p 

        输入正确密码即可进入mysql命令行;注意:mysql命令行 “ ; ” 表示命令结束 ,建议使用反引号 ` 避免与关键字冲突。

        修改数据库密码:ALTER USER '数据库用户名'@'localhost' IDENTIFIED WITH mysql_native_password BY '新密码';

        

        删除tests数据库:drop database tests;

        创建tests数据库:create database tests;

        

        查看数据库:show databases;

        

        使用tests数据库:use tests;

        

        创建test表:create table `test`(字段名+数据类型+字段属性+注释);

        

        查看库中表:show tables;

        

        查看test表结构:desc tests;

        

        删除test表:drop table test;

        

        查看创建表语句:show create table test\G

        常用字段属性: 

字段属性(关键字)释义
NULL数据列可包含NULL值
NOT NULL数据列不允许包含NULL值
DEFAULT默认值
PRIMARY KEY主键
FOREIGN KEY外键,是当前表中的字段和另外表的主键字段直接的对应关系
AUTO_INCREMENT自动递增,适用于整数类型
UNSIGNED无符号
CHARACTER SET 字符集指定一个字符集

        常用数据类型:

整数类型字节有符号数取值范围无符号数取值范围
TINYINT1-128~1270~255
SMALLINT2-32768~327670~65535
MEDIUMINT3-8388608~83886070~16777215
INT、INTEGER4-2147483648~21474836470~4294967295
BIGINT8-9223372036854775808~92233720368547758070~18446744073709551615
时间名称日期格式最大值
YEARYYYY或YY2155

TIME

时间HH:MM:SS838:59:59
DATE日期YYYY-MM-DD9999-12-03
DATETIME日期时间YYYY-MM-DD HH:MM:SS9999-12-31 23:59:59
TIMESTAMP日期 时间YYYY-MM-DD HH:MM:SS2038-01-19 03:14:07UTC
文本类型长度特点长度范围
CHAR(M)M固定长度0 <= M <= 255
VARCHAR(M)M可变长度0 <= M <= 65535
TINYTEXTL小文本、可变长度0 <= L <= 255
TEXTL文本、可变长度0 <= L <= 65535
MEDIUMTEXTL中等文本、可变长度0 <= L <= 16777215
LONGTEXTL大文本、可变长度0 <= L<= 4294967295

5.2 SQL语句

Tips:sql语句不区分大小写。

5.2.1 查询数据

       语法①: SELECT * FROM 表名称

       释义:从FROM指定的【表中】,查询出【所有的】数据。*表示【所有列】

       语法②:SELECT 列表名 FROM 表名称

       释义:从FROM指定的【表中】,查询出指定列名称(字段)的数据

-- 通过 * 把 test 表中所有的数据查询出来
 select * from test

-- 从test表中把username和password对应的数据查询出来
 select username,password from test

5.2.2 插入数据

        语法:INSERT INTO table_name (列1,列2,...)  VALUES (值1,值2,...)

        释义:向指定表中,插入几列数据,列的值通过values 一 一 指定,值用逗号(,)隔开可批量添加。

-- 向test表中,插入新数据,username的值为tony stark password的值为098123
 insert into test (username,password) values ('tony stark', '098123')

5.2.3 更新数据

        语法:UPDATE 表名称 SET 列名称=新值 WHERE 列名称=某值

        释义:用update指定要更新哪个表中的数据,用set指定列对应的新值,用where指定更新的条件。

-- 将id为3的用户密码,更改为88888888
 update test set password='88888888' where id=3

-- 更新 id为2的用户,把密码更新为 admin123 同时,把用户状态更新为1
 update test set password='admin123',status=1 where id=1

        WHERE:WHERE 子句用于限定选择的标准。在 SELECT、UPDATE、DELETE 语句中,皆可使用 WHERE 子句来限定选择的标准; 

5.2.4 删除数据

        ① DELETE 删除表中的所有数据,不会重置自增序列

        语法:DELETE FROM 表名称 WHERE 列名称=值

-- 删除 test 表中,id为 3 的用户 
 delete test users where id=3

        ②  TRUNCATE 删除表中的所有数据,并重置自增序列

        语法:TRUNCATE TABLE 表名称

-- 清空test表中数据
truncate table test

5.2.5  AND 和 OR 

        AND(也可以用 &&)表示必须同时满足多个条件,OR(也可以用 ||) 表示只要满足任意一个条件即可。

-- 使用and来显示所有状态为0且id小于3的用户
 select * from test where status=0 and id<3

-- 使用 or 来显示所有状态为1 或username为zs的用户
 select * from test where status=1 or username='zs'

5.2.6  ORDER BY排序

        升序ASC(默认),降序DESC。

-- 对test表中的数据,按照status字段进行升序排序
 select * from test order by status

-- 按照id对结果进行降序的排序
 select * from test order by id desc

-- 对test表中的数据,先按照status进行降序排序,再按照username字母的顺序,进行升序的排序
 select * from test order by status desc, username asc

 5.2.7  AS :设置别名

-- 使用 as 关键字给列起别名
select username as '用户名' from test where id<10
-- 也可以省略 as
select username '用户名' from test where id<10

5.2.8 聚合函数

        ① 求和 SUM()

-- 给test表中所有id值求和 'id值的和' 为sum(id)的别名
select sum(id)  'id值的和' from test

        ② 求最值 MAX() 、 MIN()、AVG() 

-- 求最大值
select max(id)  'id值的最大值' from test
-- 求最小值
select min(id)  'id值的最小值' from test
-- 求平均值
select avg(id)  'id值的平均值' from test

        ③ 计数 COUNT(*)

-- 使用count(*)来统计test表中,状态为0的总数量
 select count(*) from test where status

5.2.9 分页查询

        语法:limit m,n;

                m:记录数据库的下标,从零开始;

                n:数据长度 。

-- 在 test 表中,返回id,username,第一页10条记录
select id,username from test limit 0,10

Tips:m = ( 当前页 - 1 ) * n 

5.2.10 模糊查询

        ① 包含:like "%关键字%" ;

        ② 以关键字开头:like "关键字%";

        ③ 以关键字结尾:like "%关键字"。

-- 在 test 表中查询 包含 "坤"关键字的信息
select * from test like "%坤%";

-- 在 test 表中查询以"坤"关键字 开头 的信息
select * from test like "坤%";

-- 在 test 表中查询以"坤"关键字 结尾 的信息
select * from test like "%坤";

5.3 在项目中操作数据库

使用方法:

① 安装操作MySQl数据库的第三方模块(mysql):npm i mysql;

② 配置mysql并连接MySQl;

③ 在nodejs中调用。

// 1. 导入 mysql 模块
const mysql = require('mysql')
// 2. 建立与 MySQL 数据库的连接关系
const db = mysql.createPool({
  host: '127.0.0.1', // 数据库的 IP 地址
  user: 'xxx', // 登录数据库的账号
  password: 'xxx', // 登录数据库的密码
  database: 'test', // 指定要操作哪个数据库
})

// 测试 mysql 模块能否正常工作
db.query('select 1', (err, results) => {
  // mysql 模块工作期间报错了
  if(err) return console.log(err.message)
  // 能够成功的执行 SQL 语句
  console.log(results)
})

// 查询 users 表中所有的数据
const sqlStr1 = 'select * from users'
db.query(sqlStr1, (err, results) => {
  // 查询数据失败
  if (err) return console.log(err.message)
  // 查询数据成功
  // 注意:如果执行的是 select 查询语句,则执行的结果是数组
  console.log(results)
})

// 向 users 表中,新增一条数据,其中 username 的值为 zs,password 的值为 afasfa
const user = { username: 'zs', password: 'afasfa' }
// 定义待执行的 SQL 语句
const sqlStr2 = 'insert into users (username, password) values (?, ?)'
// 执行 SQL 语句
db.query(sqlStr2, [user.username, user.password], (err, results) => {
  // 执行 SQL 语句失败了
  if (err) return console.log(err.message)
  // 成功了
  // 注意:如果执行的是 insert into 插入语句,则 results 是一个对象
  // 可以通过 affectedRows 属性,来判断是否插入数据成功
  if (results.affectedRows === 1) {
    console.log('插入数据成功!')
  }
})

// 演示插入数据的便捷方式
const user2 = { username: 'zs2', password: 'ervdsf' }
// 定义待执行的 SQL 语句
const sqlStr3 = 'insert into users set ?'
// 执行 SQL 语句
db.query(sqlStr3, user2, (err, results) => {
  if (err) return console.log(err.message)
  if (results.affectedRows === 1) {
    console.log('插入数据成功')
  }
})

// 演示如何更新用户的信息
const user3 = { id: 6, username: 'aaa', password: '000' }
// 定义 SQL 语句
const sqlStr4 = 'update users set username=?, password=? where id=?'
// 执行 SQL 语句
db.query(sqlStr4, [user3.username, user3.password, user3.id], (err, results) => {
  if (err) return console.log(err.message)
  // 注意:执行了 update 语句之后,执行的结果,也是一个对象,可以通过 affectedRows 判断是否更新成功
  if (results.affectedRows === 1) {
    console.log('更新成功')
  }
})

// 演示更新数据的便捷方式
const user4 = { id: 6, username: 'aaaa', password: '0000' }
// 定义 SQL 语句
const sqlStr5 = 'update users set ? where id=?'
// 执行 SQL 语句
db.query(sqlStr5, [user4, user4.id], (err, results) => {
  if (err) return console.log(err.message)
  if (results.affectedRows === 1) {
    console.log('更新数据成功')
  }
})

// 删除 id 为 5 的用户
const sqlStr6 = 'delete from users where id=?'
db.query(sqlStr6, 5, (err, results) => {
  if (err) return console.log(err.message)
  // 注意:执行 delete 语句之后,结果也是一个对象,也会包含 affectedRows 属性
  if (results.affectedRows === 1) {
    console.log('删除数据成功')
  }
})

// 标记删除
const sqlStr7 = 'update users set status=? where id=?'
db.query(sqlStr7, [1, 6], (err, results) => {
  if (err) return console.log(err.message)
  if (results.affectedRows === 1) {
    console.log('标记删除成功')
  }
})

Tips:涉及到update、insert 、delete语句都需对 affectedRows 属性进行状态判断。

七、JWT身份认证

6.1 概念

定义:JWT(英文全称:JSON Web Token)是目前最流行的跨域认证解决方案。

工作机制(图片资源来自黑马程序员):

 JWT 的组成部分: Header(头部)、Payload(有效荷载)、Signature(签名)

        Payload 部分才是真正的用户信息,它是用户信息经过加密之后生成的字符串。

        Header 和 Signature 是安全性相关的部分,只是为了保证 Token 的安全性。

6.2 Express 中的 JWT 

①  安装 JWT 相关的包并导入相关包;

        npm i jsonwebtoken express-jwt

        jsonwebtoken用于生成JWT字符串,express-jwt用于将JWT字符串解析还原成JSON对象

// 用于生成JWT字符串
const jwt = require('jsonwebtoken')

// 用于将JWT字符串解析还原成JSON对象 "express-jwt": "^8.4.1",
const { expressjwt: expressJWT } = require("express-jwt"); 

② 定义 secret 密钥;

        用于加密和解密信息的密钥

// 任意字符串
const secretKey = 'jinishizaishitaimei'

③ 生成 JWT 字符串;

// 从数据库获取用户信息,并清空敏感信息
const user = { ...results[0], password: "", user_pic: "" };

// 对用户信息进行加密,生成Token字符串
// expiresIn token保存时长
const tokenStr = jwt.sign(user, secertKey, { expiresIn: '24h' });

④ 将 JWT 字符串还原为 JSON 对象;

// 在路由之前注册
// 只要配置成功了 express-jwt 这个中间件,就可以把解析出来的用户信息挂载到 req.auth 属性上
// 使用.unless({path:[/^\/api\//]})指定哪些接口不需要进行Token的身份认证
app.use(expressJWT({ secret: secretKey , algorithms: ["HS256"] }).unless({ path: [/^\/api\//] }));

  ⑤ 使用 req.auth(或req.user,依据express-jwt版本)获取token中的用户信息;

  ⑥ 捕获解析 JWT 失败后产生的错误。

// 错误级别的中间件
app.use((err, req, res, next) => {
  // 这次错误是由 token 解析失败导致的
  if (err.name === "UnauthorizedError") {
    return res.send({
      status: 401,
      message: "无效的token",
    });
  }
  res.send({
    status: 500,
    message: "未知的错误",
  });
});

免责说明

1、本博客中的文章摘自网上的众多博客,仅作为自己知识的补充和整理,并分享给其他需要的 coder,不会用于商用;

2、因为很多博客的地址已经记不清楚了,所以不会在这里标明出处;

3、强烈推荐一个nodejs学习网站:从零开始nodejs系列文章 | 粉丝日志

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值