Node.js基础:从入门到实战

初识 Node.js 与内置模块

(初识)
1、知道什么是node.js
2、知道node.js可以做什么
3、node.js 中js的组成部分
(内置模块)
4、用 fs 模块读写操作文件
5、使用 path 模块处理路径
6、使用http 模块写一个基本的web服务器

初识 Node.js

回顾与思考

回忆浏览器中的 JavaScript 组成:

在这里插入图片描述

为什么JavaScript可以在浏览器中被执行,是因为浏览器中存在JavaScript解析引擎,而不同的浏览器使用的解析引擎是不一样的:

在这里插入图片描述

在这里插入图片描述

因此可以总结出 JavaScript 的运行环境就包括下面两个部分:

在这里插入图片描述

由上述内容我们可以总结出两点:

1、V8 引擎负责解析和执行 JavaScript 代码

2、内置 API 是由运行环境提供的特殊接口,只能在所属的运行环境中被调用

那么 JavaScript 能否做后端开发呢?

在这里插入图片描述

当然是没有问题的,JavaScript 本身只是一门语言,这门语言所编写出来的代码想要执行的话离不开运行时环境,如果将 JavaScript 的代码放在浏览器里运行那么浏览器本身就是一个运行时环境,此时 JavaScript 就可以用来做前端开发,同时如果我们将 JavaScript 代码放在 Node.js 环境(Node.js 也是一个 JavaScript 的运行时环境,只不过是一个后端的运行时环境)当中,通过 Node.js 就可以让我们的 JavaScript 去做后端开发了。

Node.js 简介

先来看一段官方的介绍:

在这里插入图片描述

为什么是基于 Chrome V8 呢?之前说过,因为它最牛逼。所以使用 V8 来做 Node.js 的引擎用以解析 JavaScript 的代码,这样可以让 JavaScript 跑的更快。

所以我们的 Chrome 浏览器和 Node.js 用的是同一款 JavaScript 解析引擎,即 V8 ;

只不过 V8 用在不同的地方做的事情是不一样的,在 Chrome 浏览器中用 V8 解析 JavaScript 做的是前端的开发,而在 Node.js 中使用 V8 解析 JavaScript 则做的是后端开发,仅此而已。

Node.js 的运行时环境

在这里插入图片描述

可以看见,Node.js 为我们提供了后端开发所需要的所有模块的 API,因此学习 Node.js 很大程度上就是学习怎么使用这些内置的后端开发的 API。

Node.js 可以做什么

在这里插入图片描述

一句话,全栈!

Node.js 怎么学

在这里插入图片描述

Node.js 环境的安装

在这里插入图片描述

官方网址:Node.js

在这里插入图片描述

直接下载完成后双击安装即可,一路按照默认的来就行。

检测安装是否成功,打开 cmd 命令终端输入 node -v,能正常显示版本号即正常:

在这里插入图片描述

这样就安装完成了。

什么是终端

在这里插入图片描述

在 Node.js 环境中执行 JavaScript 代码

下面介绍的是比较朴素的方式,因为现在都使用 IDE 了,我用的是 WebStorm,比较推荐,IDE 的使用就不介绍了,网上很多,不再赘述。

就两步:

在这里插入图片描述

先来写一个 1.js 文件:

在这里插入图片描述

然后进入终端,在当前文件目录的命令行下,用 node 命令启动即可:

在这里插入图片描述

这样就可以运行 JavaScript 代码啦。

有一种便捷打开命令行的方式,即在我们的文件目录下,按住 shift 后点击鼠标右键会有一个打开 PowerShell 的选项:

在这里插入图片描述

点击它:

在这里插入图片描述

可以看见这种方式更加的快捷,那么 PowerShell 和我们之前的 CMD 方式有什么区别呢?

CMD 方式是出现的比较早的一种方式,是旧版本的 windows 里的终端,后来 windows 做了升级,改成了 PowerShell ,也就是新版本的 CMD(其实用哪个都行,但是 PowerShell 的功能更加强大一些)。

终端中常用的一些快捷键:

在这里插入图片描述

使用WebStorm编写 Node.js 代码没有提示问题解决

参考这篇文章:使用WebStorm编写 Node.js 代码没有提示问题解决

fs 文件系统模块

什么是 fs 文件系统模块

在这里插入图片描述

我们只需要知道在安装 Node.js 的时候这些模块就都被安装到电脑本地了即可,然后需要用到哪个模块,就使用 require 方法将其导入进来即可。

读取指定文件中的内容

fs.readFile() 的语法格式

在这里插入图片描述

示例代码如下:

// 1、到入 fs 模块操作文件
const fs = require('fs')//2、调用 fs.readFile() 方法读取文件
// 参数1、 读取文件的存放路径
// 参数2、 读取文件时候采用的编码格式,一般默认指定 utf8
// 参数3、 回调函数,拿到读取失败和成功的结果,err dataStr
fs.readFile('./1.txt', 'utf8', function (err, dataStr){// 打印失败的结果// 如果读取成功,则err 的值为null// 如果读取失败,则 err 的值为错误对象,dataStr 的值为 undefined// 因此可以通过判断 err 对象是否为 null,来判断文件读取是否成功console.log(err)console.log("----------------")// 打印成功的结果// 如果读取成功,那么dataStr就是从文件当中读取的值// 如果读取失败,那么dataStr就是undefinedconsole.log(dataStr)
})

运行结果如下:

在这里插入图片描述

关于fs.readFile()第三个参数是回调函数的解释:
fs.readFile('./1.txt', 'utf8', function (err, dataStr){console.log(err)console.log("----------------")console.log(dataStr)
})

这段代码中的回调函数是作为 fs.readFile 方法的最后一个参数传递进去的。根据 Node.js 中的约定,回调函数的第一个参数通常用于表示错误信息,第二个参数则是成功时返回的数据或结果(这是 fs.readFile() 函数的形式约定)。

所以,当你使用 fs.readFile 方法时,如果文件读取成功,Node.js 会将 err 参数置为 null,而将文件内容作为 dataStr 参数传递给回调函数;如果文件读取失败,Node.js 会将 err 参数设置为相应的错误对象,而 dataStr 则会是 undefined。

因此,通过检查 err 参数是否为 null,你可以轻松地判断文件读取是否成功。如果 err 为 null,则表示读取成功,可以在 dataStr 中访问文件内容;如果 err 不为 null,则表示读取失败,dataStr 会是 undefined,同时你可以查看 err 对象来了解具体的错误信息。

向指定的文件中写入内容

fs.writerFile()的语法格式

在这里插入图片描述

示例代码如下:

const fs = require('fs')fs.writeFile('./2.txt', 'abcd', 'utf8', function (err){// 如果文件写入成功,则 err 的值等于 null// 如果文件写入失败,则 err 的值等于一个错误对象console.log(err)
})

运行结果如下:

在这里插入图片描述

因为运行成功,因此 err 是 null 值。

fs 模块 - 路径动态拼接的问题

在这里插入图片描述

出现路径拼接错误的问题,是因为提供了 ./ 或者 …/ 开头的相对路径。

如果要解决这个问题,可以直接提供一个完整的文件存放路径(即绝对路径)即可。

但是这又会带来一种新的问题,就是代码的移植性非常差,不利于维护。

那么如何完美解决这个问题呢?可以使用 Node.js 给我们提供的 __dirname 参数:

在这里插入图片描述

测试也比较简单,打印出来即可知道 __dirname 就是代表当前文件所处的目录,因此不再赘述。

path 路径模块

什么是 path 路径模块

在这里插入图片描述

路径拼接

path.join() 的语法格式

在这里插入图片描述

代码示例如下:

const path = require('path')// 注意:../ 会抵消前面的路径
const pathStr = path.join('/a','/b/c','../','./d','e')console.log(pathStr) // 输出:\a\b\d\e//今后凡是涉及到路径拼接的操作,都要使用 path.join() 方法进行处理。
// 不要用 + 进行字符串拼接
const pathFile = path.join(__dirname, '/a/1.txt')console.log(pathFile)

运行结果如下:

在这里插入图片描述

获取路径中的文件名

path.basename() 的语法格式

在这里插入图片描述

示例代码:

const path = require('path')//定义文件的存放路径
const fpath = '/a/b/c/index.html'const fullName = path.basename(fpath)
console.log(fullName) //输出:index.htmlconst nameWithoutExt = path.basename(fpath, '.html')
console.log(nameWithoutExt) //输出:index

运行结果如下:

在这里插入图片描述

获取路径中的文件扩展名

path.extname() 的语法格式

在这里插入图片描述

示例代码如下:

const path = require('path')//这是文件的存放路径
const fpath = '/a/b/c/index.html'const fext = path.extname(fpath)console.log(fext)

运行结果如下:

在这里插入图片描述

关于 path 模块需要注意的两个小点

在这里插入图片描述

http 模块

什么是 http 模块

在这里插入图片描述

进一步理解 http 模块的作用:

在这里插入图片描述

创建最基本的 web 服务器

在这里插入图片描述

上面的步骤细分下来其实就是下面这样:

第一步:导入 http 模块

在这里插入图片描述

第二步:创建 web 服务器实例

在这里插入图片描述

第三步:为服务器实例绑定 request 事件

在这里插入图片描述

第四步:启动服务器

在这里插入图片描述

接下来我们来代码实操一下:

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

运行效果如下:

在这里插入图片描述

在这里插入图片描述

可以发现当我们在浏览器访问该地址的时候,我们的监听事件已经监听到了事件。

补充:什么是箭头函数

这是 JavaScript 中的箭头函数语法。()=>{} 是一个简单的箭头函数,它表示一个没有参数的函数,并返回一个空对象(即函数体内没有执行任何操作)。箭头函数是 ES6(ECMAScript 2015)中引入的一种新的函数声明方式,它可以更简洁地定义函数,并且在一些情况下具有更清晰的语义。

req 请求对象

在这里插入图片描述

代码示例如下:

const http = require('http')
server = http.createServer()
// req 是请求对象,包含了与客户端相关的数据和属性
server.on('request', (req)=>{// req.url 是客户端请求的 url 地址const url = req.url//req.method 是客户端请求的 method 类型const method = req.methodconst str = `Your request url is ${url}, and request method is ${method}`console.log(str)
})server.listen(80,function (){console.log('Server running at http://127.0.0.1')
})

运行效果如下:

在这里插入图片描述

在这里插入图片描述

res 响应对象

在这里插入图片描述

示例代码如下:

const http = require('http')
server = http.createServer()
// req 是请求对象,包含了与客户端相关的数据和属性
server.on('request', (req, res)=>{// req.url 是客户端请求的 url 地址const url = req.url//req.method 是客户端请求的 method 类型const method = req.methodconst str = `Your request url is ${url}, and request method is ${method}`console.log(str)// 调用 res.end() 方法向客户端响应一些内容res.end(str)
})server.listen(80,function (){console.log('Server running at http://127.0.0.1')
})

运行效果如下:

在这里插入图片描述

解决中文乱码的问题

在这里插入图片描述

代码示例如下:

const http = require('http')
server = http.createServer()
// req 是请求对象,包含了与客户端相关的数据和属性
server.on('request', (req, res)=>{// req.url 是客户端请求的 url 地址const url = req.url//req.method 是客户端请求的 method 类型const method = req.methodconst str = `你的请求路径是 ${url}, 请求方法是 ${method}`console.log(str)// 发送数据前设置响应头,设置编码方式res.setHeader('Content-Type', 'text/html; charset=utf-8')// 调用 res.end() 方法向客户端响应一些内容res.end(str)
})server.listen(80,function (){console.log('Server running at http://127.0.0.1')
})

运行效果如下:

在这里插入图片描述

根据不同的 url 响应不同的 html 内容

在这里插入图片描述

动态响应内容的代码示例:

const http = require('http')server = http.createServer()// req 是请求对象,包含了与客户端相关的数据和属性
server.on('request', (req, res)=>{//1、获取请求的 url 地址const url = req.url//2、设置默认的响应内容为 404 Not Foundlet content = '404 Not Found'//3、判断用户请求的是否为 / 或者 /index.html 页面//4、判断用户请求的是否为 /about.html 关于页面if(url === '/' || url === '/index.html'){content = '<h1>首页</h1>'}else if(url === '/about.html'){content = '<h1>关于页面</h1>'}//5、设置 Content-Type 响应头,防止中文乱码res.setHeader('Content-Type', 'text/html; charset=utf-8')//6、使用 res.end() 把内容响应给客户端res.end(content)
})server.listen(80,function (){console.log('Server running at http://127.0.0.1')
})

运行效果如下:

在这里插入图片描述

在这里插入图片描述

补充:${} 模板字符串语法

${} 是 JavaScript 中的模板字符串语法。在字符串中使用 ${} 可以插入变量或表达式的值。在这种情况下,${url} 表示将变量 url 的值插入到字符串中。这种语法使得字符串拼接更加清晰和简洁。

模块化

在这里插入图片描述

模块化的基本概念

模块化是指解决一个复杂问题时,自顶向下逐层把系统划分为若干模块的过程。对于整个系统来说,模块是可组合、分解和更换的单元。

在这里插入图片描述

模块化规范

在这里插入图片描述

Node.js 中模块的分类

在这里插入图片描述

加载模块

在这里插入图片描述

注意:在使用 require 加载用户自定义模块期间,可以省略 .js 的后缀名。

Node.js 中的模块作用域

在这里插入图片描述

模块作用域的好处就是:防止了全局变量污染的问题。

向外共享模块作用域中的成员

module 对象

在这里插入图片描述

module.exports 对象

在这里插入图片描述

接下来我们用代码来解释一下。

先创建两个自定义模块,一个是自定义模块.js 另一个是 test.js,然后我们 自定义模块.js 文件先不写任何内容,在 test.js 中先去 require 自定义模块.js 中的内容试一下:

在这里插入图片描述

运行效果如下:

在这里插入图片描述

可以看见打印不出任何内容,因为我们在导入另一个模块的时候,我们导入的其实是另一个模块 module 的 exports 属性,默认情况下 exports 属性就是空的,这可以从上一小节讲的 module 对象 中的图里看到。

因此我们其实可以在 自定义模块.js 中对外共享一些本模块中的成员:

在这里插入图片描述

此时我们在运行 test.js 查看现在是否 modules.export 为空了:

在这里插入图片描述

可以看见不为空了,有内容的。

共享成员时的注意点

在这里插入图片描述

exports 对象

在这里插入图片描述

代码验证如下:

console.log(exports)
console.log(module.exports)
console.log(exports === module.exports)

运行效果如下:

在这里插入图片描述

exports 和 module.exports 的使用误区

在这里插入图片描述

Node.js 中的模块化规范

在这里插入图片描述

npm 与包

什么是包

在这里插入图片描述

包的来源

在这里插入图片描述

为什么需要包

在这里插入图片描述

从哪里下载包

在这里插入图片描述

如何下载包

在这里插入图片描述

查看自己电脑上的 npm 版本:

在这里插入图片描述

npm 初体验

在这里插入图片描述

这种传统方法就不演示了,可以看出来很繁琐,因此我们直接使用第三方包来完成一样的事情:

在这里插入图片描述

在项目中安装包的命令

在这里插入图片描述

接下来我们来演示如何用 npm 下载 第三方包,这里我直接使用 WebStorm 的终端进行下载了:

在这里插入图片描述

可以看见此时就已经下载安装好了。

写代码来实现我们的时间格式化操作:

//1、导入需要的包
const moment = require('moment')//2、查阅官方文档明白第三方包要如何使用
const dt = moment().format('YYYY-MM-DD HH:mm:ss')
console.log(dt)

运行效果如下:

在这里插入图片描述

初次安装后都多了哪些文件

在这里插入图片描述

可以检查一下自己的项目:

在这里插入图片描述

注意:程序员不要手动修改 node_modules 或者 package-lock.json 文件中的任何代码,npm 包管理工具会自动维护它们。

安装指定版本的包

在这里插入图片描述

注意:如果我们要切换第三方包的版本并不需要先卸载我们现有版本的包,而是直接下新的即可,新的会覆盖原来旧版本的包嗷。

包的语义化版本规范

在这里插入图片描述

包管理配置文件

在这里插入图片描述

多人协作的问题

在这里插入图片描述

如何记录项目中安装了哪些包

在这里插入图片描述

快速创建 package.json

在这里插入图片描述

dependencies 节点

在这里插入图片描述

一次性安装所有的包

在这里插入图片描述
在这里插入图片描述

卸载包

在这里插入图片描述

devDependencies 节点

在这里插入图片描述

怎么知道哪些第三方包需要被保存到 devDependencies 哪些需要被保存到 dependencies 呢?

这些其实在官方文档都会有说的,查阅官方文档就行。

为什么下包速度慢

在这里插入图片描述

下包速度慢解决:淘宝 NPM 镜像服务器

在这里插入图片描述

切换 NPM 的下包镜像源

在这里插入图片描述

nrm 小工具

在这里插入图片描述

包的分类

使用 npm 包管理工具下载的包,共分为两大类,分别是:项目包和全局包。

在这里插入图片描述

在这里插入图片描述

好用的第三方包:i5ting_toc

在这里插入图片描述

规范的包结构

在这里插入图片描述

package.json 为啥必须要包含 main 包入口的这个属性呢?

这是因为在我们项目中使用 require 导入第三方包的时候其实走的就是这个 main 属性,通过这个 main 属性我们才能正常使用这个包的功能,即它是包的入口。

开发属于自己的包

假设我们现在需要开发的包叫 itheima-tools 包,其需要实现下面的功能:

在这里插入图片描述

那么接下来我们就按照下面的步骤开发我们自己的包:

在这里插入图片描述

实现效果如下:

在这里插入图片描述

然后初始化 package.json :

在这里插入图片描述

如果你使用 WebStorm 进行文件创建的话,可以发现其是自动生成的,只要点击创建就可以了。

不难发现这个 package.json 包其实就是一个 json 配置对象:

在这里插入图片描述

但是我们需要改一下,改成 PPT 中的那样,否则没办法发布到 NPM 的服务器上:

在这里插入图片描述

上面需要解释的几个含义:

main:就是入口文件的位置
keywords:这是被发布到 npm 服务器上时别人可以检索到这个包所使用的关键字有哪些
license:所遵循的开源许可协议,npm 官方推荐使用 ISC,因此我们用这个即可

然后编写我们的包源码:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

将不同的功能进行模块化拆分

在这里插入图片描述

src 是我们的新创建的源码文件夹,拆分的部分将全部放进该文件夹中。

编写包的说明文档

在这里插入图片描述

发布包

主要有以下几个步骤:

在这里插入图片描述

在这里插入图片描述

注意:在运行 npm login 命令之前,必须先把下包的服务器地址切换为 npm 的官方服务器。否则会导致发布包失败!

在这里插入图片描述

删除已发布的包

在这里插入图片描述

模块的加载机制

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

Express.js

在这里插入图片描述

初识 Express.js

Express.js 简介

在这里插入图片描述

进一步理解 Express

在这里插入图片描述

Express 能做什么

在这里插入图片描述

Express 安装

在这里插入图片描述

这里看的课的老师用的 4.17.1 的版本,我看了一下现在官网的最新版本是 4.19.2:

按照包的语义化版本规范,因为是只上升了第二位数的大小,说明相较于 4.17.1 的版本,现在最新的版本也只不过是新增了一些功能并且修复了一点 bug 而已,因此我们直接安装使用最新版即可:

在这里插入图片描述

查看版本:

在这里插入图片描述

Express 创建 web 服务器

在这里插入图片描述

来实现一下:

// 1、导入 Express
const express = require('express')
// 2、创建 web 服务器
const app = express()
// 3、启动 web 服务器
// 调用 app.listen(端口号,启动成功后的回调函数),启动服务器
app.listen(80, ()=>{console.log('express server running at http://127.0.0.1')
})

运行效果如下:

在这里插入图片描述

Express 监听 Get 和 Post 请求

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

示例代码如下:

// 1、导入 Express
const express = require('express')
// 2、创建 web 服务器
const app = express()//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('请求成功')
})// 3、启动 web 服务器
app.listen(80, ()=>{console.log('express server running at http://127.0.0.1')
})

效果如下:

在这里插入图片描述

获取 URL 中携带的查询参数

在这里插入图片描述

示例代码如下:

app.get('/', (req,res)=>{//通过 req.query 可以获取到客户端发送过来的 查询参数//注意:默认情况下,req.query 是一个空对象console.log(req.query)res.send(req.query)
})

运行结果如下:

在这里插入图片描述

此时我们加上查询参数运行结果将变为:

在这里插入图片描述

获取 URL 中的动态参数

在这里插入图片描述

示例代码如下:

//注意:这里的 :id 是一个动态的参数
app.get('/user/:id',(req,res)=>{// req.params 是动态匹配到的 URL 参数,默认是空对象console.log(req.params)res.send(req.params)
})

运行效果如下:

在这里插入图片描述

我们不止可以写一个,可以写多个动态参数:

//注意:这里的 :id 是一个动态的参数
app.get('/user/:id/:name',(req,res)=>{// req.params 是动态匹配到的 URL 参数,默认是空对象console.log(req.params)res.send(req.params)
})

运行效果如下:

在这里插入图片描述

托管静态资源

express.static()

在这里插入图片描述

简单测试一下:

在这里插入图片描述

运行效果如下:

在这里插入图片描述

托管多个静态资源目录

在这里插入图片描述

挂载路径前缀

在这里插入图片描述

调试工具:nodemon 的安装与使用

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

Express 路由

什么是路由

广义上讲,路由就是映射关系。

比如:

在这里插入图片描述

在上图中,路由就是按键与服务之间的映射关系。

Express 中的路由

在这里插入图片描述

实际项目中的示例程序:

在这里插入图片描述

路由的匹配过程

在这里插入图片描述

路由的使用

在这里插入图片描述

这种方式之前就用过很多次了,只要知道有这种用法即可,实际的项目中我们不会采用这么直接的方式,因此不再赘述。

模块化路由

在这里插入图片描述

创建路由模块

在这里插入图片描述

我们新创建一个 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 a new user')
})
//4、向外导出路由对象
module.exports = router
注册路由模块
// 1、导入 Express
const express = require('express')
// 2、创建 web 服务器
const app = express()// 1、导入路由模块
const router = require('./router.js')
// 2、注册路由模块
app.use(router)// 3、启动 web 服务器
app.listen(80, ()=>{console.log('express server running at http://127.0.0.1')
})

运行效果如下:

在这里插入图片描述

可以发现路由模块化后也依然可以正常工作。

app.use() 函数的作用

一句话:该函数的作用就是用来注册全局中间件的(后面就会讲到了)。

为路由模块添加前缀

在这里插入图片描述

Express 中间件

什么是中间件

中间件(Middleware),特指业务流程的中间处理环节。

比如:

在这里插入图片描述

Express 中间件的调用流程

在这里插入图片描述

Express 中间件的格式

在这里插入图片描述

next 函数的作用

在这里插入图片描述

Express 中间件的初体验

在这里插入图片描述

代码示例如下:

const express = require('express')const app = express()// 定义一个最简单的中间件函数
const mw = function (req, res, next){console.log("这是最简单的中间件函数")//把流转关系,转交给下一个中间件或者路由//(有中间件转交给中间件,没中间件就转交给路由)next()
}app.listen(80, () => {console.log('http://localhost')
})

全局生效的中间件

在这里插入图片描述

示例代码如下:

const express = require('express')const app = express()// 定义一个最简单的中间件函数
const mw = function (req, res, next){console.log("这是最简单的中间件函数")//把流转关系,转交给下一个中间件或者路由//(有中间件转交给中间件,没中间件就转交给路由)next()
}//将 mw 注册为全局生效的中间件
app.use(mw)app.get('/',(req,res)=>{console.log('Here is Home Page')res.send('Home page')
})app.get('/user',(req,res)=>{res.send('User page')
})app.listen(80, () => {console.log('http://localhost')
})

运行效果如下:

在这里插入图片描述

可以看见访问浏览器时是成功打印了:

在这里插入图片描述

因为目前我们只定义了一个中间件,因此在 mw 中间件函数执行结束之后因为没有其他中间件了,于是 next() 函数将流转关系转交给了路由模块,所以先打印 “这是最简单的中间件函数” 再打印 “Here is Home Page”。

定义全局中间件的简化形式

在这里插入图片描述

中间件的作用

在这里插入图片描述

示例代码:

const express = require('express')const app = express()// 定义一个最简单的中间件函数
const mw = function (req, res, next){//获取请求到达服务器的时间const time = Date.now()//为 req 对象挂载自定义属性,从而把时间共享给后面的所有路由req.startTime = time//把流转关系,转交给下一个中间件或者路由//(有中间件转交给中间件,没中间件就转交给路由)next()
}//将 mw 注册为全局生效的中间件
app.use(mw)app.get('/',(req,res)=>{res.send('Home page'+req.startTime)
})app.get('/user',(req,res)=>{res.send('User page'+req.startTime)
})app.listen(80, () => {console.log('http://localhost')
})

运行效果:

在这里插入图片描述

定义多个全局中间件

在这里插入图片描述

局部生效的中间件

在这里插入图片描述

定义多个局部中间件

在这里插入图片描述

注意调用顺序是从前往后的,即先执行 mw1 再执行 mw2。

了解中间件使用的5个使用注意事项

在这里插入图片描述

中间件的分类

在这里插入图片描述

应用级别的中间件:

在这里插入图片描述

路由级别的中间件:

在这里插入图片描述

错误级别的中间件:

在这里插入图片描述

注意:错误级别的中间件,必须注册在所有路由之后!

Express 内置的中间件

在这里插入图片描述

express.json() 内置中间件

代码示例:

const express = require('express')
const app = express()//注意:除了错误级别的中间件,其他的中间件,必须在路由之前进行配置
//通过 express.json() 这个中间件,解析表单中的 JSON 格式的数据
app.use(express.json())app.post('/user',(req,res)=>{// 在服务器中可以使用 req.body 这个属性来接收客户端发送过来的请求体数据// 默认情况下,如果不配置解析表单数据的中间件(也就是 express.json()),则 req.body 默认为 undefinedconsole.log(req.body)res.send('ok')
})app.listen(80, ()=>{console.log('http://localhost')
})

运行效果,我们使用 postman 工具来进行测试:

发送 JSON 类型的请求体数据如下:

在这里插入图片描述

此时控制台中的输出如下:

在这里插入图片描述

可以看见请求体数据被完美解析。

express.urlencoded() 内置中间件

示例代码如下:

const express = require('express')
const app = express()//注意:除了错误级别的中间件,其他的中间件,必须在路由之前进行配置
//通过 express.urlencoded() 这个中间件,解析表单中的 JSON 格式的数据
//在这个函数内部我们还要传递一个固定的配置对象 extended ,将其设置为 false
//这是固定的写法,只需要记住,不需要问为什么
app.use(express.urlencoded({ extended: false }))app.post('/book',(req,res)=>{// 在服务器中可以使用 req.body 这个属性来接收客户端发送过来的 url-encoded 格式的数据// 默认情况下,如果不配置解析 url-encoded 表单数据的中间件,则 req.body 默认为空console.log(req.body)res.send('ok')
})app.listen(80, ()=>{console.log('http://localhost')
})

发送数据类型为:

在这里插入图片描述

运行效果为:

在这里插入图片描述

可以看见正常解析了数据。

第三方中间件

在这里插入图片描述

自定义中间件

在这里插入图片描述

实现如下:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

使用 Express 写 API 接口

1、创建基本的服务器:

// app.js 主模块
// 导入 express
const express = require('express')// 创建服务器实例
const app = express()// 调用 app.listen() 方法,指定端口号并启动 web 服务器
app.listen(80,()=>{console.log('Express server is running at http://localhost')
})

2、创建 API 路由模块

// apiRouter.js 路由模块
const express = require('express')const router = express.Router()//在这里挂载对于的路由module.exports = router

然后在 app.js 中导入并注册路由模块:

// app.js 主模块
// 导入 express
const express = require('express')// 创建服务器实例
const app = express()//导入路由模块
const router = require('./apiRouter')
//把路由模块注册到 app 上
app.use('/api', router)// 调用 app.listen() 方法,指定端口号并启动 web 服务器
app.listen(80,()=>{console.log('Express server is running at http://localhost')
})

3、编写 Get 接口

// apiRouter.js 路由模块
const express = require('express')const router = express.Router()//在这里挂载对应的路由
router.get('/get', (req,res)=>{//通过 req.query 获取客户端通过查询字符串,发送到服务器的数据const query = req.query//调用 res.send() 方法,向客户端响应处理的结果res.send({stats: 0,//0 表示处理成功,1 表示处理失败msg: 'Get 请求成功', // 状态描述data: query //需要响应给客户端的数据})
})module.exports = router

运行结果如下:

在这里插入图片描述

4、编写 Post 接口

// apiRouter.js 路由模块
const express = require('express')const router = express.Router()//在这里挂载对应的路由
router.get('/get', (req,res)=>{//通过 req.query 获取客户端通过查询字符串,发送到服务器的数据const query = req.query//调用 res.send() 方法,向客户端响应处理的结果res.send({stats: 0,//0 表示处理成功,1 表示处理失败msg: 'Get 请求成功', // 状态描述data: query //需要响应给客户端的数据})
})router.post('/post', (req,res)=>{//通过 req.body 获取客户端发送到服务器的请求体数据const body = req.body//调用 res.send() 方法,向客户端响应处理的结果res.send({stats: 0,//0 表示处理成功,1 表示处理失败msg: 'Post 请求成功', // 状态描述data: body //需要响应给客户端的数据})
})module.exports = router

要解析表单数据别忘了在导入路由之前先添加配置解析表单数据的中间件:

// app.js 主模块
// 导入 express
const express = require('express')// 创建服务器实例
const app = express()//配置解析表单数据的中间件
app.use(express.urlencoded({ extended: false}))
app.use(express.json())//导入路由模块
const router = require('./apiRouter')
//把路由模块注册到 app 上
app.use('/api', router)// 调用 app.listen() 方法,指定端口号并启动 web 服务器
app.listen(80,()=>{console.log('Express server is running at http://localhost')
})

运行效果如下:

在这里插入图片描述

接口的跨域问题

在这里插入图片描述

接口跨域问题是指在Web开发中,由于浏览器的同源策略(Same-Origin Policy),导致在一个域下的网页无法直接访问另一个域下的资源。"跨域"指的是在浏览器中,当一个页面的脚本请求访问另一个域下的资源时,如果这个资源的域名、协议或端口与当前页面所在的域不一致,就会引发跨域问题。

跨域问题会影响到包括Ajax请求、Web字体加载、嵌入式框架(如iframe)加载等场景。具体来说,如果你在一个网页中使用Ajax请求另一个域下的数据,浏览器会阻止这个请求,因为涉及到跨域。

解决接口跨域问题的方法有很多,包括使用代理服务器、JSONP、CORS(跨域资源共享)等。CORS是一种比较常用的解决方案,它通过在服务器端设置一些响应头,来告诉浏览器允许跨域请求。JSONP则是一种利用

实际开发中,我们推荐使用 CORS 的方法来解决跨域问题。

使用 CORS 中间件解决跨域问题

在这里插入图片描述

第一步:安装

在这里插入图片描述

第二步和第三步:在路由之前先配置并注册 cors 中间件到 app.js 上

// app.js 主模块
// 导入 express
const express = require('express')// 创建服务器实例
const app = express()//配置解析表单数据的中间件
app.use(express.urlencoded({ extended: false}))
app.use(express.json())//在路由之前先配置 cors 中间件解决跨域问题
const cors = require('cors')
//注册 cors 中间件
app.use(cors())//导入路由模块
const router = require('./apiRouter')
//把路由模块注册到 app 上
app.use('/api', router)// 调用 app.listen() 方法,指定端口号并启动 web 服务器
app.listen(80,()=>{console.log('Express server is running at http://localhost')
})

这样就可以解决跨域问题啦。

什么是 CORS

在这里插入图片描述

CORS 的注意事项

在这里插入图片描述

CORS 响应头部 -Access-Control-Allow-Origin

在这里插入图片描述

在这里插入图片描述

CORS 响应头部 -Access-Control-Allow-Headers

在这里插入图片描述

CORS 响应头部 -Access-Control-Allow-Methods

在这里插入图片描述

CORS 请求的分类

在这里插入图片描述

简单请求

在这里插入图片描述

预检请求

在这里插入图片描述

在浏览器与服务器正式通信之前,浏览器会先发送 OPTION 请求进行预检,以获知服务器是否允许该实际请求,所以这一次的 OPTION 请求称为 ”预检请求“ 。服务器成功响应预检请求后,才会发送真正的请求,并且携带真实数据。

简单请求和预检请求之间的区别

在这里插入图片描述

数据库与身份认证

在这里插入图片描述

注意这一章节的学习中省略了 MySQL 相关的基础内容,如果不会的话建议先去系统学一下 MySQL 捏。

这里只讲 Express 中如何操作 MySQL 数据库嗷。

测试的表数据如下:

在这里插入图片描述

在 Express 中操作 MySQL

在项目中操作 MySQL 数据库的步骤:

在这里插入图片描述

安装 mysql 模块:

在这里插入图片描述

配置 mysql 模块:

在这里插入图片描述

示例代码如下:

//mysql-cfg.js 数据库模块
//1、导入 mysql 模块
const mysql = require('mysql')//2、建议与 mysql 数据库的连接关系
const db = mysql.createPool({host: '127.0.0.1', //数据库的 ip 地址user: 'root', //登录数据库的账号password: '123456', //登录数据库的密码database: 'node' //指定要操作哪一个数据库
})

测试一下 mysql 模块是否能正常工作:

//mysql-cfg.js 数据库模块
//1、导入 mysql 模块
const mysql = require('mysql')//2、建议与 mysql 数据库的连接关系
const db = mysql.createPool({host: '127.0.0.1', //数据库的 ip 地址user: 'root', //登录数据库的账号password: '123456', //登录数据库的密码database: 'node' //指定要操作哪一个数据库
})// 测试 mysql 模块能否正常工作
// select 1 这条语句没有任何意义,只是用来检查 mysql 能否正常工作
db.query('select 1',(err, results)=>{// mysql 模块工作期间报错了if(err){return console.log(err.message)}//否则就是能够正常的执行 SQL 语句console.log(results)
})

测试运行结果如下:

在这里插入图片描述

可以看见我们的 mysql 模块是没有问题的。

使用 mysql 模块操作 MySQL 数据库

查询数据

在这里插入图片描述

示例代码如下:

//mysql-cfg.js 数据库模块
//1、导入 mysql 模块
const mysql = require('mysql')//2、建议与 mysql 数据库的连接关系
const db = mysql.createPool({host: '127.0.0.1', //数据库的 ip 地址user: 'root', //登录数据库的账号password: '123456', //登录数据库的密码database: 'node' //指定要操作哪一个数据库
})// 查询 users 表中所有的数据
const str = "select * from user"
db.query(str,(err, results)=>{// mysql 模块工作期间报错了if(err){return console.log(err.message)}//否则就是能够正常的执行 SQL 语句console.log(results)
})

运行结果如下:

在这里插入图片描述

注意:如果执行的是 select 查询语句,则执行的结果是数组。

插入数据

在这里插入图片描述

示例代码:

//mysql-cfg.js 数据库模块
//1、导入 mysql 模块
const mysql = require('mysql')//2、建议与 mysql 数据库的连接关系
const db = mysql.createPool({host: '127.0.0.1', //数据库的 ip 地址user: 'root', //登录数据库的账号password: '123456', //登录数据库的密码database: 'node' //指定要操作哪一个数据库
})// 向 user 表中新增一条数据,其中username的值为 Spider,password 的值为123
const user = {username:'Spider', password:'123'}
//定义待执行的 SQL 语句
const sqlStr = 'insert into user (username, password) values (?, ?)'
//执行 SQL 语句
db.query(sqlStr,[user.username,user.password],(err,results)=>{if(err) return console.log(err.message)// 注意:如果执行的是 insert into 插入语句,则 results 是一个对象// 可以通过 affectedRows 属性,来判断是否插入数据成功if(results.affectedRows === 1) console.log('插入数据成功')
})

插入数据的便捷方式

在这里插入图片描述

示例代码:

//mysql-cfg.js 数据库模块
//1、导入 mysql 模块
const mysql = require('mysql')//2、建议与 mysql 数据库的连接关系
const db = mysql.createPool({host: '127.0.0.1', //数据库的 ip 地址user: 'root', //登录数据库的账号password: '123456', //登录数据库的密码database: 'node' //指定要操作哪一个数据库
})// 向 user 表中新增一条数据,其中username的值为 Spider,password 的值为123
const user = {username:'Spider', password:'123'}
//定义待执行的 SQL 语句
//insert into 表名 set ?
const sqlStr = 'insert into user set ?'
//执行 SQL 语句
// 参数也不需要用数组形式了,直接将原对象进行插入即可(类似于一个 JavaBean)
db.query(sqlStr,user,(err,results)=>{if(err) return console.log(err.message)// 注意:如果执行的是 insert into 插入语句,则 results 是一个对象// 可以通过 affectedRows 属性,来判断是否插入数据成功if(results.affectedRows === 1) console.log('插入数据成功')
})

运行结果如下:

在这里插入图片描述

数据库中也是正常的新增了数据:

在这里插入图片描述

更新数据

在这里插入图片描述

示例代码:

//mysql-cfg.js 数据库模块
//1、导入 mysql 模块
const mysql = require('mysql')//2、建议与 mysql 数据库的连接关系
const db = mysql.createPool({host: '127.0.0.1', //数据库的 ip 地址user: 'root', //登录数据库的账号password: '123456', //登录数据库的密码database: 'node' //指定要操作哪一个数据库
})// 向 user 表中修改一条数据
const user = { id: 3, username:'阿斯顿', password:'123' }
//定义待执行的 SQL 语句
const sqlStr = 'update user set username=?,password=? where id=?'
//执行 SQL 语句
db.query(sqlStr,[user.username,user.password,user.id],(err,results)=>{if(err) return console.log(err.message)// 注意:如果执行的是 update 更新语句,则 results 是一个对象// 可以通过 affectedRows 属性,来判断是否更新数据成功if(results.affectedRows === 1) console.log('更新数据成功')
})

运行结果如下:

在这里插入图片描述

更新数据的便捷方式

在这里插入图片描述

删除数据

在这里插入图片描述

标记删除

在这里插入图片描述

前后端中的身份认证

Web 开发模式

目前主流的 Web 开发模式有两种,分别是:

1、基于服务端渲染的传统 Web 开发模式

2、基于前后端分离的新型 Web 开发模式

基于服务端渲染的传统 Web 开发模式

在这里插入图片描述
在这里插入图片描述

基于前后端分离的新型 Web 开发模式

在这里插入图片描述

在这里插入图片描述

如何选择 Web 开发模式

在这里插入图片描述

身份认证

什么是身份认证?
在这里插入图片描述

为什么需要身份认证

在这里插入图片描述

不同开发模式下的身份认证

在这里插入图片描述

HTTP 协议的无状态性

在这里插入图片描述

如何突破 HTTP 无状态的限制

在这里插入图片描述

什么是 Cookie

在这里插入图片描述

Cookie 在身份认证中的作用

在这里插入图片描述

Cookie 不具有安全性

在这里插入图片描述

注意:千万不要使用 Cookie 存储重要且隐私的数据!比如用户的身份信息、密码等。

提高身份认证的安全性

在这里插入图片描述

Session 的工作原理

在这里插入图片描述

在 Express 中使用 Session 认证

配置 Session

只需要下面几步就可以使用 Session 认证了嗷:

在这里插入图片描述
在这里插入图片描述

配置对象中的 secret 属性是一串字符串,用来加密用的。

接下来我们完成一下这些事情:

安装 express-session 中间件:

在这里插入图片描述

开始配置 express-session 的全局中间件:

// app.js 主模块
// 导入 express
const express = require('express')// 创建服务器实例
const app = express()// 引入session
const session = require('express-session')
// 注册 session
app.use(session({secret: 'hahaha',resave: false,saveUninitialized: true
}))//配置解析表单数据的中间件
app.use(express.urlencoded({ extended: false}))
app.use(express.json())//在路由之前先配置 cors 中间件解决跨域问题
const cors = require('cors')
//注册 cors 中间件
app.use(cors())//导入路由模块
const router = require('./apiRouter')
//把路由模块注册到 app 上
app.use('/api', router)// 调用 app.listen() 方法,指定端口号并启动 web 服务器
app.listen(80,()=>{console.log('Express server is running at http://localhost')
})
向 Session 中存数据

在这里插入图片描述

从 Session 中取数据

在这里插入图片描述

清空 Session

在这里插入图片描述

注意:只是清空了当前客户端的 Session ,这并不会影响到其他客户端的 Session。

因为之前说过 Session 的工作原理,每个 Session 都会对应一个客户端浏览器所自动存收的一个 Cookie,因此相当于各个客户端之间是隔离连接的,互不影响,至于底层是怎么实现的应该是在这个 express-session 第三方包中自动实现的,我们只要懂得怎么使用即可。

了解 Session 认证的局限性

在这里插入图片描述

什么是 JWT

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

JWT 的工作原理

在这里插入图片描述

JWT 的组成部分

在这里插入图片描述

JWT 的三个部分各自代表的含义

在这里插入图片描述

JWT 的使用方式

在这里插入图片描述

注意:千万别忘记了在 token 字符串前加 Bearer 这个字符串!然后后面还要跟一个空格才能再跟 token 字符串!!!

比如我们在 postman 中要带 token 的话,那么形式应该是下面这样:

在这里插入图片描述

在 Express 中使用 JWT

主要有下面几个步骤:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

上图中的第三个参数配置对象里,我们配置了该 Token 的过期时间为 30s,如果要设置成分钟则后缀用 m ,小时的话设置为 h 即可。

在这里插入图片描述

注意:只要配置成功了 express-jwt 这个中间件,就可以把解析出来的用户信息,挂载到 req.user 属性上。

换句话说就是,req 本身是没有 user 属性的,但是只要配置成功了 express-jwt 这个中间件后,req 就有一个 user 属性了,该属性是由该中间件创建的。

而这个 user 对象中包含多少信息是由我们自己决定的,也就是在登录成功之后我们进行加密的用户信息对象信息有多少那么 user 对象中就有多少信息。

比如我们上面的示例中将 username 进行了加密,那么被创建的 user 对象就会只有一个 username 属性。

如果我们的访问请求携带了 token 进行 API 访问的话,其返回值会有下面两个额外的属性:

在这里插入图片描述

iat 和 exp ,不过不用管,这是这个 JWT 第三方工具包用来控制过期时间用的两个属性。

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

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/10877.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

设计模式——模板设计模式(Template Method)

模板设计-base 什么是模板&#xff1f; 举个简单的例子&#xff0c;以AABB的格式&#xff0c;写出一个词语&#xff0c;你可能会想到&#xff0c;明明白白&#xff0c;干干净净等&#xff0c; 这个AABB就是一个模板&#xff0c;对模板心中有了一个清晰的概念之后&#xff0c;…

环境变量(全)

概念 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数 如&#xff1a;我们在编写C/C代码的时候&#xff0c;在链接的时候&#xff0c;从来不知道我们的所链接的动态静态库在哪里&#xff0c;但是照样可以链接成功&#xff0c;生成可执…

今日arXiv最热NLP大模型论文:揭露大语言模型短板,北京大学提出事件推理测试基准

人工智能领域又一里程碑时刻&#xff01;北京大学、北京智源人工智能研究院等机构联合推出大型事件推理评测基准 。这是首个同时在知识和推理层面全面评估大模型事件推理能力的数据集。 总所周知&#xff0c;事件推理需要丰富的事件知识和强大的推理能力&#xff0c;涉及多种推…

consul启动Error_server_rejoin_age_max (168h0m0s) - consider wiping your data dir

consul 启动报错&#xff1a; consul[11880]: 2024-05-12T08:37:51.095-0400 [ERROR] agent: startup error: error"refusing to rejoin cluster because server has been offline for more than the configured server_rejoin_age_max (168h0m0s) - consider wiping you…

【GD32】02-ADC模拟数字转换器

ADC 在电子和通信技术中&#xff0c;ADC&#xff08;模拟数字转换器&#xff09;是一种将模拟信号转换为数字信号的电子设备。这种转换是电子系统中非常关键的一个环节&#xff0c;因为数字信号更易于处理、存储和传输。ADC的工作原理通常包括采样、保持、量化和编码等步骤。采…

http协议 tomcat如何访问资源 servlet理论介绍

tomcat介绍 bin是启动命令&#xff1b; conf是配置&#xff0c;可以修改端口号&#xff1b; lib是依赖的jar包&#xff1b; logs是日志 webapps是重点&#xff0c;在这里新建我们自己的javaWeb项目 tomcat如何访问资源 tomcat通过统一资源定位符&#xff08;URL&#xff09;来…

乡村振兴与农村基础设施建设:加大农村基础设施建设投入,提升农村公共服务水平,改善农民生产生活条件,构建宜居宜业的美丽乡村

一、引言 乡村振兴是我国现代化进程中的重要战略&#xff0c;而农村基础设施建设则是乡村振兴的基石。随着城市化进程的加快&#xff0c;农村基础设施建设滞后的问题日益凸显&#xff0c;成为制约乡村发展的瓶颈。因此&#xff0c;加大农村基础设施建设投入&#xff0c;提升农…

AI大模型探索之路-训练篇21:Llama2微调实战-LoRA技术微调步骤详解

系列篇章&#x1f4a5; AI大模型探索之路-训练篇1&#xff1a;大语言模型微调基础认知 AI大模型探索之路-训练篇2&#xff1a;大语言模型预训练基础认知 AI大模型探索之路-训练篇3&#xff1a;大语言模型全景解读 AI大模型探索之路-训练篇4&#xff1a;大语言模型训练数据集概…

华为OD机试 - 执行任务赚积分 - 动态规划(Java 2024 C卷 100分)

华为OD机试 2024C卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA)真题(A卷+B卷+C卷)》。 刷的越多,抽中的概率越大,每一题都有详细的答题思路、详细的代码注释、样例测试,发现新题目,随时更新,全天CSDN在线答疑。 一、题目描述 现有 N 个任…

Gradle基础学习(六) 认识任务Task

理解Gradle中的任务 Gradle的构建过程基于任务&#xff08;Task&#xff09;的概念&#xff0c;而每个任务都可以包含一个或多个动作&#xff08;Action&#xff09;。 任务是构建中执行的一些独立的工作单元&#xff0c;例如编译类、创建JAR、生成Javadoc或将存档发布到仓库…

4.5网安学习第四阶段第五周回顾(个人学习记录使用)

本周重点 ①部署域环境&#xff08;Win2008&#xff09; ②域组策略 ③域内信息收集 ④(重点)哈希传递攻击PTH ⑤MS14-068 提权漏洞 ⑥黄金票据伪造 ⑦白银票据伪造 ⑧ZeroLogon (CVE-2020-1472) 漏洞复现 本周主要内容 ①部署域环境&#xff08;Win2008&#xff09;…

【算法】滑动窗口——串联所有单词的子串

今天来以“滑动窗口”的思想来详解一道比较困难的题目——串联所有单词的子串&#xff0c;有需要借鉴即可。 目录 1.题目2.下面是示例代码3.总结 1.题目 题目链接&#xff1a;LINK 这道题如果把每个字符串看成一个字母&#xff0c;就是另外一道中等难度的题目&#xff0c;即&…

不同路径| 和 不同路径||

不同路径| 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 问总共有多少条不同的路径&#xf…

大学生体质测试|基于Springboot+vue的大学生体质测试管理系统设计与实现(源码+数据库+文档)

大学生体质测试管理系统 目录 基于Springboot&#xff0b;vue的大学生体质测试管理系统设计与实现 一、前言 二、系统设计 三、系统功能设计 1系统功能模块 2管理员功能模块 3用户功能模块 4教师功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算…

C++笔试强训day20

目录 1.经此一役小红所向无敌 2.连续子数组最大和 3.非对称之美 1.经此一役小红所向无敌 链接 简单模拟即可。 需要注意的是&#xff1a; 除完之后有无余数&#xff0c;若有&#xff0c;则还可以再挨一次打。 #include <iostream> using namespace std; #define in…

设计模式——结构型模式——代理模式(静态代理、动态代理:JDK、CGLIB)

目录 代理模式 代理模式简介 代理模式的分类 代理模式组成 代理模式的优缺点 静态代理 背景前置 编写代码 JDK动态代理 编写代码 使用Arthas分析JDK动态代理底层原理 CGLIB动态代理 编写代码 三种代理的对比 代理模式使用场景 代理模式 代理模式简介 代理模式属…

Mybatis操作数据库的两种方式:Mapper代理模式

1.Mapper代理模式的特点 程序员没有写接口的子实现——直接获取数据库的数据 因为Mybatis定义了一套规则&#xff0c;对方法进行了实现&#xff0c;程序员只要遵循这套方法就可以直接使用 2.如何实现Mapper代理模式 步骤&#xff1a; 1.创建一个dao接口&#xff0c;在接口…

java项目之英语知识应用网站源码(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的英语知识应用网站。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 英语知识应用网站的主要…

【免费】AME最新Adobe Media Encoder电脑软件安装包2024-2018支持WIN和MAC

Adobe MediaEncoder「Me」2024是一款功能强大的转码和媒体处理软件&#xff0c;它不仅能轻松应对各种媒体文件的编码和导出需求&#xff0c;还支持多种视频格式和分辨率&#xff0c;让你的视频处理变得更加高效。此外&#xff0c;该软件界面简洁明了&#xff0c;操作简便&#…

【一步一步了解Java系列】:了解Java与C语言的运算符的“大同小异”

看到这句话的时候证明&#xff1a;此刻你我都在努力~ 加油陌生人~ 个人主页&#xff1a; Gu Gu Study ​​ 专栏&#xff1a;一步一步了解Java 喜欢的一句话&#xff1a; 常常会回顾努力的自己&#xff0c;所以要为自己的努…