【全栈第三课】通过ChatGPT快速入门NodeJS

news2024/11/16 1:44:29

前言

往期全栈课程:
Vue从入门到精通
微信小程序从入门到精通

Node.js基础

简介

Node.js是什么?

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。Node.js 使用了一个事件驱动非阻塞式 I/O的模型,使其轻量又高效。Node.js 的包管理工具 npm 是全球最大的开源库生态系统。

Node.js 不是一门语言,也不是 JavaScript 的框架,也不是像Nginx一样的Web服务器 ,Node.js 是 JavaScript 在服务器端的运行环境(平台)。

Node.js的组成

在 Node.js 里运行 JavaScript,跟在 Chrome 里运行 JavaScript 有什么不同?

二者采用的是同样的 JS 引擎。在 Node.js 里写 JS,和在前端写 JS,几乎没有不同。在写法上的区别在于:Node.js 没有浏览器、页面标签相关的 API(不能操作BOM对象和DOM对象),但是新增了一些 Node.js 相关的 API。通俗来说,对于开发者而言,在前端写 JS 是用于控制浏览器;而 Node.js 环境写 JS 可以控制整个计算机。

我们知道,JavaScript 的组成分为三个部分:

  • ECMAScript:描述了JS的语法和基本对象
  • DOM(document object model):DOM 是文档对象模型,处理网页内容的方法和接口。是W3C 的标准;
  • BOM(browser object model);BOM 是浏览器对象模型,提供与浏览器交互的方法和接口。各个浏览器厂商根据 DOM在各自浏览器上的实现;

ECMAScript 是 JS 的语法;DOM 和 BOM 浏览器端为 JS 提供的 API。

而 Node.js 的组成分为:

  • ECMAScript。ECMAScript 的所有语法在 Node 环境中都可以使用。
  • Node 环境提供的一些附加 API(包括文件、网络等相关的 API)。

如下图所示:

image-20221102140543274

知名度较高的Node.js开源项目

image-20221102140856507

  • express:Node.js 中著名的 web 服务框架。

  • Koa:下一代的 Node.js 的 Web 服务框架。所谓的“下一代”是相对于 Express 而言的。

  • Egg:2016 年,阿里巴巴研发了知名的 Egg.js 开源项目,号称企业级 Web 服务框架。Egg.js 是基于 Koa 开发的。

  • mocha:是现在最流行的 JavaScript 测试框架,在浏览器和 Node 环境都可以使用。

  • PM2:node 多进程管理。

  • jade:非常优秀的模板引擎,不仅限于 js 语言。

  • CoffeeScript:用简洁的方式展示 JavaScript 优秀的部分。

  • Atom:编辑器。

  • VS Code:最酷炫的编辑器。

  • socket.io:实时通信框架。

Node.js的特点

  • 异步、非阻塞 IO 模型
  • 事件循环
  • 单线程
  • 总结:轻量和高效

Node.js 的性能和效率非常高。

传统的 Java 语言是一个请求开启一个线程,当请求处理完毕后就关闭这个线程。而 Node.js 则完全没有采用这种模型,它本质上就是一个单线程。

你可能会疑问:一个线程如何服务于大量的请求、如何处理高并发的呢?这是因为,Node.js 采用的是异步的、非阻塞的模型。

这里所谓的“单线程”,指的是 Node 的主线程只有一个。为了确保主线程不被阻塞,主线程是用于接收客户端请求。但不会处理具体的任务。而 Node 的背后还有一个线程池,线程池会处理长时间运行的任务(比如 IO 操作、网络操作)。线程池里的任务是通过队列和事件循环的机制来执行。

环境安装

通过 Node.js 安装包产生的问题

  • 安装新版本时,需要覆盖旧版本;而且以前版本安装的很多全局工具包,需要重新安装。
  • 无法回滚到之前的旧版本。
  • 无法在多个版本之间切换(很多时候,不同的项目需要使用特定版本。或者,我想临时尝鲜一下新版本的特性)

因此不推荐使用安装包的形式安装,Win推荐使用NVM,Mac使用n

安装教程如下:

mac:https://juejin.cn/post/7065701236925792293

win:https://juejin.cn/post/6844903861308637192

image-20230706105910828

真好用!!!

包管理工具

由于 Node 是一套轻内核的平台,虽然提供了一系列的内置模块,但是不足以满足开发者的需求,于是乎出现了包(package)的概念: 与核心模块类似,就是将一些预先设计好的功能或者说 API 封装到一个文件夹,提供给开发者使用。

Node 本身并没有太多的功能性 API,所以市面上涌现出大量的第三方人员开发出来的 Package。

npm

NPM:Node Package Manager。官方链接: https://www.npmjs.com/

Node.js 发展到现在,已经形成了一个非常庞大的生态圈。包的生态圈一旦繁荣起来,就必须有工具去来管理这些包。

NPM 的常用命令

npm init
npm install 包名 –g  (uninstall,update)
npm install 包名 --save-dev (uninstall,update)
npm list -g (不加-g,列举当前目录下的安装包)
npm info 包名(详细信息) npm info 包名 version(获取最新版本)
npm install md5@1(安装指定版本)
npm outdated(  检查包是否已经过时)


	"dependencies": {    "md5": "^2.1.0"  }  ^ 表示 如果 直接npm install 将会 安md5
    2.*.*  	最新版本

	"dependencies": {    "md5": "~2.1.0"  }  ~ 表示 如果 直接npm install 将会 安装md5 2.1.*  最新版本

	"dependencies": {    "md5": "*"  }  * 表示 如果 直接npm install 将会 安装 md5  最新版本

nrm

和npm一样都是包管理工具,喜欢那个用哪个

yarn

和npm一样都是包管理工具,喜欢那个用哪个

https://yarn.bootcss.com/,推荐这个

对比npm:
	速度超快: Yarn 缓存了每个下载过的包,所以再次使用时无需重复下载。 同时利用并行下载以最大化资源利用率,因此安装速度更快。
    超级安全: 在执行代码之前,Yarn 会通过算法校验每个安装包的完整性。

开始新项目
	yarn init 
添加依赖包
	yarn add [package] 
	yarn add [package]@[version] 
	yarn add [package] --dev 
升级依赖包
	 yarn upgrade [package]@[version] 
移除依赖包
	 yarn remove [package]
	 
安装项目的全部依赖
	 yarn install 

cnpm

和npm一样都是包管理工具,喜欢那个用哪个

pnpm

使用文档如下:https://www.pnpm.cn/motivation

CommonJS

前言

网站越来越复杂,js代码、js文件也越来越多,会遇到一些问题

  • 文件依赖
  • 全局污染、命名冲突

程序模块化包括:

  • 日期模块
  • 数学计算模块
  • 日志模块
  • 登陆认证模块
  • 报表展示模块等。

所有这些模块共同组成了程序软件系统。

一次编写,多次使用,才是提高效率的核心。

模块化规范

模块化规范的引入

假设我们引入模块化,首先可能会想到的思路是:在一个文件中引入多个js文件。如下:

<body>
    <script src="zepto.js"></script>
    <script src="fastClick.js"></script>
    <script src="util/login.js"></script>
    <script src="util/base.js"></script>
    <script src="util/city.js"></script>
</body>

但是这样做会带来很多问题:

  • 请求过多:引入十个js文件,就有十次http请求。
  • 依赖模糊:不同的js文件可能会相互依赖,如果改其中的一个文件,另外一个文件可能会报错。

以上两点,最终导致:难以维护

于是,这就引入了模块化规范。

CommonJS 的基本语法

在 CommonJS 中,每个文件都可以当作一个模块:

  • 在服务器端:模块的加载是运行时同步加载的。
  • 在浏览器端: 模块需要提前编译打包处理。首先,既然同步的,很容易引起阻塞;其次,浏览器不认识require语法,因此,需要提前编译打包。

模块的暴露和引入

Node.js 中只有模块级作用域,两个模块之间的变量、方法,默认是互不冲突,互不影响,这样就导致一个问题:模块 A 要怎样使用模块B中的变量&方法呢?这就需要通过 exports 关键字来实现。

Node.js中,每个模块都有一个 exports 接口对象,我们可以把公共的变量、方法挂载到这个接口对象中,其他的模块才可以使用。

接下来详细讲一讲模块的暴露、模块的引入。

exports

exports对象用来导出当前模块的公共方法或属性。别的模块通过 require 函数调用当前模块时,得到的就是当前模块的 exports 对象。

// 相当于是:给 exports 对象添加属性
exports.xxx = value

这个 value 可以是任意的数据类型。

注意:暴露的关键词是exports,不是export。其实,这里的 exports 类似于 ES6 中的 export 的用法,都是用来导出一个指定名字的对象。

const name = 'zs'

const foo = function(value){
    return value * 2
}

exports.day01_name = name
exports.day01_foo = foo

module.exports

module.exports用来导出一个默认对象,没有指定对象名。

语法格式:

// 方式一:导出整个 exports 对象
module.exports = value;

// 方式二:给 exports 对象添加属性
module.exports.xxx = value;

这个 value 可以是任意的数据类型。

代码举例:

// 方式1
module.exports = {
    name: '我是 module1',
    foo(){
        console.log(this.name);
    }
}

// 我们不能再继续写 module.exports = value2。因为重新赋值,会把 exports 对象 之前的赋值覆盖掉。

// 方式2
const age = 28;
module.exports.age = age;

module.exports 还可以修改模块的原始导出对象。比如当前模块原本导出的是一个对象,我们可以通过 module.exports 修改为导出一个函数。如下:

module.exports = function () {
    console.log('hello world')
}

区别

最重要的区别:

  • 使用exports时,只能单个设置属性 exports.a = a;
  • 使用module.exports时,既单个设置属性 module.exports.a,也可以整个赋值 module.exports = obj

其他要点:

  • Node中每个模块的最后,都会执行 return: module.exports
  • Node中每个模块都会把 module.exports指向的对象赋值给一个变量 exports,也就是说 exports = module.exports
  • module.exports = XXX,表示当前模块导出一个单一成员,结果就是XXX。
  • 如果需要导出多个成员,则必须使用 exports.add = XXX; exports.foo = XXX。或者使用 module.exports.add = XXX; module.export.foo = XXX

require

require函数用来在一个模块中引入另外一个模块。传入模块名,返回模块导出对象。

语法格式

const module1 = require('模块名');

解释:

  • 内置模块:require的是包名
  • 下载的第三方模块:require的是包名
  • 自定义模块:require的是文件路径。文件路径既可以用绝对路径,也可以用相对路径。后缀名.js可以省略。

代码举例

const m1 = require('./main.js');

const module2 = require('./main');

const module3 = require('Demo/src/main.js');

m1.method()

require()函数的两个作用

  • 执行导入的模块中的代码。
  • 返回导入模块中的接口对象。

内置模块

前置知识点

箭头函数

// 传统函数
function add(a, b) {
  return a + b;
}

// 箭头函数
const add = (a, b) => a + b;

回调函数

回调函数常用于异步操作和事件处理

  • 当异步操作完成后,可以使用回调函数进行操作。
  • 当事件发生时可以使用回调函数进行操作处理一些逻辑

回调函数的应用

readableStream.on('data', (chunk) => {
  console.log('Data:', chunk);
});

你可能知道.on是一个方法然后括号里面传入了两个参数,一个参数是data,一个参数是被()=>{}修饰的

那么这个被()=>{}修饰的部分就是回调函数,回调函数一般是将回调函数做为参数传递给另一个函数,那么为了方便就可以用上面提到的箭头函数来传递。这样是不是很方便呢,也不用想给回调函数起个什么名字了哈哈。

在前端开发中回调函数和箭头函数非常常见,一定要理解不然都看不懂这代码啥意思。

http模块

要使用 HTTP 服务器和客户端,则必须 require('http')

const http  = require('http')

// 创建本地服务器来从其他接收数据
const server = http.createServer((req,res) => {
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({
        data: 'Hello World!'
      }));
})
server.listen(8000);

结果展示

image-20230707103448113

jsonp

JSON 是一种数据格式,而 JSONP 是一种用于跨域数据请求的技术。JSONP 利用动态创建 <script> 标签的方式来获取跨域数据,但它也存在一些安全风险。在现代的 Web 开发中,由于浏览器支持跨域资源共享(CORS)等技术,JSONP 的使用已经相对较少,更多地使用 JSON 和 Ajax 进行数据交互。

模拟get

var http = require('http')
var https = require('https')

// 1、接口 2、跨域
const server = http.createServer((request, response) => {
  var url = request.url.substr(1)

  var data = ''

  response.writeHeader(200, {
    'content-type': 'application/json;charset=utf-8',
    'Access-Control-Allow-Origin': '*'
  })

  https.get(`https://m.lagou.com/listmore.json${url}`, (res) => {

    res.on('data', (chunk) => {
      data += chunk
    })

    res.on('end', () => {
      response.end(JSON.stringify({
        ret: true,
        data
      }))
    })
  })

})

server.listen(8080, () => {
  console.log('localhost:8080')
})

效果如下:

image-20230707171549597

在上述示例中,我们使用 https.request() 方法创建了一个请求对象,指定了请求的参数和路径,包括查询参数 page=2。我们向 reqres.in/api/users 路径发送了一个 GET 请求。

当收到响应时,我们监听 response 对象的 data 事件来获取响应数据。在 end 事件中,我们处理完整的响应数据。

请注意,上述示例中使用的是 HTTPS 请求,端口号默认为 443。如果你希望使用 HTTP 请求,你可以将 options 中的 port 设置为 80,并使用 http 模块替代 https 模块。

模拟post

const https = require('https');

// POST 请求的选项
const options = {
  hostname: 'reqres.in', // API 的主机名
  port: 443, // API 的端口号
  path: '/api/users', // API 的路径
  method: 'POST', // 请求方法
  headers: {
    'Content-Type': 'application/json', // 请求的内容类型
  },
};

// 创建请求对象
const request = https.request(options, (response) => {
  let data = '';

  // 接收响应数据
  response.on('data', (chunk) => {
    data += chunk;
  });

  // 响应结束时处理数据
  response.on('end', () => {
    console.log('Response:', data);
  });
});

// 请求数据
const postData = JSON.stringify({ name: 'John Doe', job: 'Developer' }); // 要发送的数据
request.write(postData);

// 发送请求
request.end();

请求效果如下:

image-20230707171327677

在上述示例中,我们使用 https.request() 方法创建一个请求对象,指定了请求的参数和头部信息。我们向 reqres.in/api/users 路径发送了一个 POST 请求。我们使用 JSON 格式的数据对象 { name: 'John Doe', job: 'Developer' } 作为请求主体,并通过 request.write() 方法将其写入请求。

当收到响应时,我们监听 response 对象的 data 事件来获取响应数据。在 end 事件中,我们处理完整的响应数据。

请注意,上述示例使用的是 HTTPS 请求,端口号为 443。如果你希望使用 HTTP 请求,你可以将 options 中的 port 设置为 80,并使用 http 模块替代 https 模块。

url模块

parse

const url = require('url')
const urlString = 'https://www.google.com/'
const parsedStr = url.parse(urlString)
console.log(parsedStr)

效果如下:

看结果知道是用来解析url的

注意:url.parse返回的是一个Url对象

image-20230707104116723

format

const url = require('url')
const urlObject = {
  protocol: 'https:',
  slashes: true,
  auth: null,
  host: 'www.baidu.com:443',
  port: '443',
  hostname: 'www.baidu.com',
  hash: '#tag=110',
  search: '?id=8&name=mouse',
  query: { id: '8', name: 'mouse' },
  pathname: '/ad/index.html',
  path: '/ad/index.html?id=8&name=mouse'
}
const parsedObj = url.format(urlObject)
console.log(parsedObj)

效果如下:

看来是用来格式化URL的

image-20230707104513217

resolve

const url = require('url')


var a = url.resolve('/one/two/three', 'four') 

var b = url.resolve('http://example.com/', '/one')

var c = url.resolve('http://example.com/one', '/two')

console.log(a + "," + b + "," + c)

拼接url的,效果如下:

image-20230707105538082

querystring模块

parse和stringify

image-20230707105941647

escape/unescape

可以看出一个是将特殊字符进行转义,一个是对转义后的特殊字符进行解析

转义的好处是可以防止SQL注入

image-20230707111100282

escapeunescape 函数是 JavaScript 中的字符串转义函数,它们可以用于防止 SQL 注入攻击。然而,需要注意的是,这两个函数在最新的 ECMAScript 标准中已被废弃,因为它们并不是完全安全可靠的转义方式。相反,现代的开发实践推荐使用预编译语句等技术来防止 SQL 注入。

预编译是一种执行之前先定义好SQL语句模版,其中包含占位符,而不是直接插入用户提供的数据。然后将用户输入的数据作为参数传递给预编译语句,数据库连接库会负责将数据安全地插入到查询中,避免了SQL注入的风险。

event模块

const EventEmitter = require('events');

// 创建自定义事件发射器
class MyEmitter extends EventEmitter {}

// 创建事件发射器实例
const myEmitter = new MyEmitter();

// 注册事件监听器
myEmitter.on('myEvent', (arg) => {
  console.log('Event received:', arg);
});

// 触发事件
myEmitter.emit('myEvent', 'Hello, world!');

在上述示例中,我们创建了一个自定义的事件发射器 MyEmitter,通过继承 EventEmitter 类。然后,我们创建了 MyEmitter 的实例 myEmitter。接下来,我们使用 on() 方法注册了一个监听器,监听名为 myEvent 的事件,并定义了事件发生时的回调函数。最后,我们使用 emit() 方法触发了 myEvent 事件,并传递了一个参数 'Hello, world!'

当触发 myEvent 事件时,注册的监听器会执行相应的回调函数,并输出事件的参数。

events 模块的使用让事件驱动的编程更加简洁和灵活。它被广泛应用于 Node.js 中处理异步操作、网络请求、事件处理等场景,以及许多第三方模块和库中。

fs文件操作模块

Node.js 的 fs(File System)模块是一个内置模块,用于处理文件系统操作。它提供了一组方法,用于读取、写入、更新和删除文件,以及处理文件和目录的相关操作。

const fs = require('fs');

//写入
fs.writeFile('file.txt', 'Hello, world!', (err) => {
  if (err) {
    console.error(err);
    return;
  }
  console.log('File written successfully!');
});

// 读取文件
fs.readFile('file.txt', 'utf8', (err, data) => {
  if (err) {
    console.error(err);
    return;
  }
  console.log(data);
});

// 判断文件是否存在
if (fs.existsSync('file.txt')) {
  console.log('File exists');
} else {
  console.log('File does not exist');
}

异步方法采用回调函数作为参数,在操作完成时被调用。这样可以在等待操作完成时,继续执行其他任务,提高程序的并发性和响应性。

例如,异步读取文件的方法是 fs.readFile(),它接受一个回调函数作为参数,当文件读取完成时会调用该回调函数,并传递读取到的数据。

stream流模块

const fs = require('fs');

// 创建可读流
const readableStream = fs.createReadStream('file.txt', 'utf8');

// 创建可写流
const writableStream = fs.createWriteStream('output.txt', 'utf8');

// 将可读流的数据写入可写流
readableStream.pipe(writableStream);

// 监听可读流的 'data' 事件
readableStream.on('data', (chunk) => {
  console.log('Data:', chunk);
});

// 监听可写流的 'finish' 事件
writableStream.on('finish', () => {
  console.log('Write complete.');
});

在示例中,readableStream.on('data', callback)writableStream.on('finish', callback) 是两个事件监听的示例。on() 方法用于注册事件监听器,并指定要监听的事件名称和相应的回调函数。

'data' 是监听事件的名称,它是可读流 readableStream 发出的事件。当可读流有新的数据块可用时,会触发 'data' 事件。通过注册监听器来捕获 'data' 事件,可以在每次有新数据时执行相应的回调函数。

类似地,'finish' 事件是可写流 writableStream 发出的事件。当所有数据都被写入可写流后,会触发 'finish' 事件。通过注册监听器来捕获 'finish' 事件,可以在写入完成时执行相应的回调函数。

zlib模块

const zlib = require('zlib');
const data = 'Hello, world!';

zlib.gzip(data, (err, compressedData) => {
  if (err) {
    console.error(err);
    return;
  }
  console.log('Compressed data:', compressedData);
});

data 是要压缩的原始数据,而 compressedData 是压缩后的数据。

crypto模块

crypto 模块是 Node.js 的内置模块之一,提供了加密和解密的功能。它通过提供一组加密算法和相关的操作函数,用于处理数据的加密、解密、签名、哈希等安全操作。

const crypto = require('crypto');
const data = 'Hello, world!';

//创建了一个哈希对象 hash,使用的哈希算法是 SHA-256。
const hash = crypto.createHash('sha256');
hash.update(data);

//执行哈希计算并获取哈希值。digest() 方法用于计算哈希对象的摘要。它接受一个参数来指定输出的格式,例如 'hex' 表示以十六进制字符串的形式输出。调用 digest('hex') 方法后,它返回计算得到的哈希值,并将其赋值给变量 hashedData。
const hashedData = hash.digest('hex');
console.log('Hashed data:', hashedData);

路由

基础

var fs = require("fs")
var path = require("path")

function render(res, path) {
    res.writeHead(200, { "Content-Type": "text/html;charset=utf8" })
    res.write(fs.readFileSync(path, "utf8"))
    res.end()
}


const route = {
    "/login": (req, res) => {
        render(res, "./static/login.html")
    },

    "/home": (req, res) => {
        render(res, "./static/home.html")
    },
    "/404": (req, res) => {
        res.writeHead(404, { "Content-Type": "text/html;charset=utf8" })
        res.write(fs.readFileSync("./static/404.html", "utf8"))
    }
}

获取参数

get请求

    "/api/login":(req,res)=>{
        const myURL = new URL(req.url, 'http://127.0.0.1:3000');
        console.log(myURL.searchParams.get("username"))   
        render(res,`{ok:1}`)
    }

post请求

"/api/login": (req, res) => {
        var post = '';
        // 通过req的data事件监听函数,每当接受到请求体的数据,就累加到post变量中
        req.on('data', function (chunk) {
            post += chunk;
        });

        // 在end事件触发后,通过querystring.parse将post解析为真正的POST请求格式,然后向客户端返回。
        req.on('end', function () {
            post = JSON.parse(post);
            render(res, `{ok:1}`)
        });
    }

静态资源处理

function readStaticFile(req, res) {
    const myURL = new URL(req.url, 'http://127.0.0.1:3000')
    var filePathname = path.join(__dirname, "/static", myURL.pathname);

    if (fs.existsSync(filePathname)) {
        // console.log(1111)
        res.writeHead(200, { "Content-Type": `${mime.getType(myURL.pathname.split(".")[1])};charset=utf8` })
        res.write(fs.readFileSync(filePathname, "utf8"))
        res.end()
        return true
    } else {
        return false
    }
}

Express

image-20230708142711781

安装

yarn init
yarn add express

路由

Express 提供了 app.get()app.post()app.put()app.delete() 等方法用于定义路由。你可以根据 HTTP 请求方法和 URL 路径,将请求映射到相应的处理函数上。

匹配路径的时候可以上正则表达式

下面是一个基本的路由示例:

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

app.get('/', (req, res) => {
  res.send('Hello, world!');
});

app.post('/users', (req, res) => {
  // 处理创建用户的逻辑
});

app.put('/users/:id', (req, res) => {
  // 处理更新用户的逻辑
});

app.delete('/users/:id', (req, res) => {
  // 处理删除用户的逻辑
});

app.listen(3000, () => {
  console.log('Server started on port 3000');
});

image-20230708143315149

中间件

Express 中间件允许你在请求和响应之间执行一些额外的逻辑。中间件函数可以用来处理请求、修改请求或响应对象、进行身份验证、记录日志等。你可以使用 app.use() 或特定的 HTTP 方法来注册中间件。

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

// 自定义中间件
const middleware1 = (req, res, next) => {
  console.log('Middleware 1');
  next(); // 调用 next() 将请求传递给下一个中间件或路由处理函数
};

const middleware2 = (req, res, next) => {
  console.log('Middleware 2');
  next(); // 调用 next() 将请求传递给下一个中间件或路由处理函数
};

// 注册中间件
app.use(middleware1);
app.use(middleware2);

// 路由处理函数
app.get('/', (req, res) => {
  res.send('Hello, world!');
});

app.listen(3000, () => {
  console.log('Server started on port 3000');
});

在上述示例中,我们定义了两个中间件函数 middleware1middleware2,它们分别在控制台打印一些信息,并调用 next() 将请求传递给下一个中间件或路由处理函数。这样,当我们访问根路径 / 时,请求将依次通过两个中间件,并最终到达路由处理函数,返回响应。

中间件的应用场景包括但不限于:身份验证、日志记录、错误处理、请求预处理等。它们可以对请求进行处理、修改请求或响应对象,并决定请求的控制流程。中间件提供了一种可扩展的机制,用于在请求和响应之间执行额外的逻辑。

获取请求参数

Express 提供了多种方式来获取请求参数,包括 URL 参数、查询参数、请求体参数等。你可以通过 req.paramsreq.queryreq.body 等属性来访问这些参数。

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

app.get('/users/:id', (req, res) => {
  const userId = req.params.id; // 获取 URL 参数
  console.log(userId)
  const queryParams = req.query; // 获取查询参数
  // 处理逻辑
});

app.post('/users', (req, res) => {
  const userData = req.body; // 获取请求体参数
  // 处理逻辑
});

app.listen(3000, () => {
  console.log('Server started on port 3000');
});

托管静态文件

Express 提供了 express.static() 方法来托管静态文件,例如 CSS、JavaScript、图像等。你只需将静态文件所在的目录作为参数传递给 express.static(),然后通过访问对应的 URL 路径即可获取静态文件。

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

app.use(express.static('public')); // 托管 public 目录下的静态文件

app.get('/', (req, res) => {
  res.send('Hello, world!');
});

app.listen(3000, () => {
  console.log('Server started on port 3000');
});

image-20230708150655251

服务端渲染(模板引擎)

Express 可以与各种模板引擎配合使用,实现服务端渲染的功能。你可以选择适合你的项目的模板引擎,如 EJS、Pug、Handlebars 等,并将其与 Express 集成,通过模板引擎渲染动态内容并生成 HTML。

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

// 设置 EJS 作为模板引擎
app.set('view engine', 'ejs');

// 路由处理函数
app.get('/', (req, res) => {
  const data = {
    title: 'My Server-side Rendered Page',
    message: 'Hello, world!',
  };
  res.render('index', data); // 渲染名为 "index" 的模板,并传递数据
});

app.listen(3000, () => {
  console.log('Server started on port 3000');
});

接下来,在同级目录下创建一个名为 views 的文件夹,并在其中创建一个名为 index.ejs 的文件。在 index.ejs 文件中,我们可以使用 EJS 模板引擎的语法来嵌入动态数据。

<!DOCTYPE html>
<html>
<head>
  <title><%= title %></title>
</head>
<body>
  <h1><%= message %></h1>
</body>
</html>

在上述示例中,我们创建了一个根路径的路由处理函数,使用 res.render() 方法渲染了一个名为 index 的模板,并传递了一个包含动态数据的对象。这里的动态数据包括 titlemessage。在模板中,我们使用 <%= %> 语法来输出动态数据。

当我们启动服务器并访问 http://localhost:3000 时,Express 会根据我们的路由处理函数生成动态的 HTML 页面,并将其发送给客户端进行展示。此时,服务器已经在响应中将动态数据注入到 HTML 页面中,完成了服务端渲染的过程。

MongoDB

这里我使用docker的方式来安装运行。

docker pull mongo:4

docker run -p 27017:27017 --name mongo \
-v /mydata/mongo/db:/data/db \
-d mongo:4

使用Navicat来做可视化操作

这里做一个简单的查询,我们可以知道MongoDB更适合和Node结合使用,因为他存储的数据格式是BSON格式的和JSON比较像

image-20230708152743903

CRUD示例

运行的mongodb版本要和nodejs中安装的mongodb包的依赖版本一致

image-20230708154434519

安装依赖:

yarn add mongodb@4.2.2  

CRUD测试:

const { MongoClient } = require('mongodb');

// MongoDB 连接 URI
const uri = 'mongodb://localhost:27017';

// 数据库名称和集合名称
const dbName = 'leadnews-history';
const collectionName = 'ap_user_search';
// 连接 MongoDB
MongoClient.connect(uri, (err, client) => {
  if (err) {
    console.error('Failed to connect to MongoDB:', err);
    return;
  }

  console.log('Connected to MongoDB');

  const db = client.db(dbName);
  const collection = db.collection(collectionName);

  // 创建文档(Create)
  const document = { name: 'John', age: 25 };
  collection.insertOne(document, (err, result) => {
    if (err) {
      console.error('Failed to insert document:', err);
    } else {
      console.log('Document inserted:', result.insertedId);
    }

    // 读取文档(Read)
    collection.find().toArray((err, documents) => {
      if (err) {
        console.error('Failed to find documents:', err);
      } else {
        console.log('Documents found:', documents);
      }

      // 更新文档(Update)
      const filter = { name: 'John' };
      const update = { $set: { age: 30 } };
      collection.updateOne(filter, update, (err, result) => {
        if (err) {
          console.error('Failed to update document:', err);
        } else {
          console.log('Document updated:', result.modifiedCount);
        }

        // 删除文档(Delete)
        const deleteFilter = { name: 'John' };
        collection.deleteOne(deleteFilter, (err, result) => {
          if (err) {
            console.error('Failed to delete document:', err);
          } else {
            console.log('Document deleted:', result.deletedCount);
          }

          // 关闭连接
          client.close();
        });
      });
    });
  });
});

接口规范与业务分层

RESTful

RESTful(Representational State Transfer)是一种软件架构风格,用于设计网络应用程序的通信方式。它是一种基于 HTTP 协议的设计模式,旨在创建可扩展、灵活和易于维护的 Web 服务。

使用 RESTful 架构,可以设计出易于理解、可扩展和可维护的 Web 服务。以下是 RESTful 架构的一些关键特点和示例:

  • 使用 HTTP 方法来表示对资源的操作:
    • GET:获取资源的表示。
    • POST:创建新资源。
    • PUT:更新资源。
    • DELETE:删除资源。
  • 使用 URI(Uniform Resource Identifier)来标识资源:
    • /users:表示用户资源。
    • /products:表示产品资源。
  • 使用状态码(Status Code)来表示请求结果:
    • 200:成功的请求。
    • 201:已成功创建资源。
    • 404:未找到资源。
    • 500:服务器内部错误。
  • 使用响应的内容类型(Content-Type)来指示返回的数据格式:
    • application/json:返回 JSON 格式的数据。
    • application/xml:返回 XML 格式的数据。
  • 使用超链接(Hyperlinks)来表示资源之间的关系:
    • 使用链接来实现导航、发现和操作资源。

通过遵循 RESTful 架构的原则,可以设计出符合标准、易于理解和易于扩展的 Web 服务。RESTful 架构通常用于构建基于 Web 的 API(Application Programming Interface),支持客户端和服务器之间的数据交互和操作。

需要注意的是,RESTful 架构是一种设计模式和原则,并不是具体的技术或实现。在实际开发中,可以使用不同的技术和框架来实现 RESTful Web 服务,例如使用 Node.js、Express、Django、Spring 等。

URI 是用于唯一标识实体的名称,而 URL 则是用于定位实体的具体位置或资源的地址。

比如你要找一个人名为张三的人,那么URI就是张三,URL可以理解为张三的具体位置比如身份证上的地址

MVC

MVC(Model-View-Controller)是一种常用的软件架构模式,用于组织和设计应用程序的结构。它将应用程序分为三个主要组件:模型(Model)、视图(View)和控制器(Controller),每个组件负责不同的任务。

下面是 MVC 架构中各个组件的角色和职责:

  1. 模型(Model)
    • 模型表示应用程序的数据和业务逻辑。
    • 它负责处理数据的存储、读取、验证和更新。
    • 模型通常是应用程序的核心,它不依赖于视图或控制器,独立地管理数据和业务逻辑。
  2. 视图(View)
    • 视图是用户界面的表示。
    • 它负责将模型中的数据以可视化的方式呈现给用户。
    • 视图通常是被动的,不处理业务逻辑,只负责展示数据。
  3. 控制器(Controller)
    • 控制器充当模型和视图之间的中间人,负责处理用户的输入和操作。
    • 它接收用户的请求,并根据请求调用适当的模型来处理数据和逻辑。
    • 控制器还负责将模型的数据更新反映到视图上。

MVC 架构的优点包括:

  • 分离关注点:MVC 将应用程序的不同方面(数据、显示、控制逻辑)分离,使代码更易于维护和测试。
  • 可扩展性:由于模块化和分层的设计,MVC 架构允许开发人员独立地修改和扩展各个组件。
  • 代码复用:模型和视图可以在不同的应用程序场景中重用,提高了开发效率。
  • 可测试性:MVC 架构使单元测试和集成测试更容易进行,因为各个组件的职责清晰明确。

需要注意的是,MVC 是一种架构模式,而不是具体的技术或框架。许多编程语言和框架都支持 MVC 架构,例如,ASP.NET MVC、Ruby on Rails、Spring MVC 等。

Node.js 也可以使用 MVC 架构模式来组织和设计应用程序的结构。尽管 Node.js 本身并没有内置的 MVC 框架,但你可以使用许多第三方模块和框架来实现 MVC 架构。

  1. Express.js:Express.js 是一个流行的轻量级 Node.js Web 框架,它提供了灵活的路由、中间件和视图模板等功能,可以很好地支持 MVC 架构的开发。
  2. Koa:Koa 是由 Express.js 团队创建的下一代 Node.js Web 框架,它采用了更现代的异步函数(async/await)风格,同样可以用于构建 MVC 应用程序。

登录鉴权

cookie和session

Cookie 作为客户端存储会话标识符的机制,而 Session 则是服务器端存储会话信息的机制。它们配合使用,确保用户身份的验证和会话状态的维持。

token

客户端发起请求,后端校验没问题的话使用jwt工具类生成token返回给客户端

用户下次登录会携带token,后端使用拦截器或过滤器对token进行校验

文件上传管理

Multer 是一个 node.js 中间件,用于处理 multipart/form-data 类型的表单数据,它主要用于上传文件。

安装:

yarn add multer

测试:

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

// 创建 Express 应用
const app = express();

// 配置 multer 中间件
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    // 指定上传文件的保存目录
    cb(null, 'uploads/');
  },
  filename: (req, file, cb) => {
    // 指定上传文件的文件名
    cb(null, file.originalname);
  }
});
const upload = multer({ storage });

// 处理文件上传的 POST 请求
app.post('/upload', upload.single('file'), (req, res) => {
  // 上传文件的处理逻辑
  // req.file 包含了上传的文件信息
  res.send('文件上传成功');
});

// 启动服务器
app.listen(3000, () => {
  console.log('服务器已启动,监听端口 3000');
});

在上述代码中,我们定义了 storage 对象,其中包含了 destinationfilename 属性,它们都是函数。这些函数在执行时,接收三个参数:req(请求对象)、file(上传的文件对象)和 cb(回调函数)。

cb 函数需要在适当的时机被调用,以通知 multer 文件上传的状态和结果。通过调用 cb 函数,我们可以将错误对象或者指定的值传递给 multer,以便它能够继续处理文件上传过程。

const upload = multer({ storage }) 的意思是创建一个 multer 实例,并将配置对象 storage 传递给它。这样可以创建一个处理文件上传的中间件,我们可以在路由处理程序中使用 upload 中间件来处理文件上传的请求。

image-20230708164623672

Koa2

Koa2 是一个基于 Node.js 的 Web 框架,它提供了一套优雅的中间件(middleware)机制,用于处理 Web 请求和响应。

1.安装 Koa2 :
yarn add koa

2.创建 Koa2 应用:
const Koa = require('koa');
const app = new Koa();

3.编写中间件:
Koa2 使用中间件机制来处理请求和响应。
中间件是一个函数,它可以访问请求对象和响应对象,并执行一些操作。
Koa2 中间件通过 app.use() 方法注册。
以下是一个简单的示例,展示了一个中间件的使用:
app.use(async (ctx, next) => {
  // 执行一些操作
  // ...
  // 调用下一个中间件
  await next();
});

4.处理路由:
Koa2 不内置路由功能,可以使用第三方模块(如 koa-router)来处理路由。
安装 koa-router 模块:
yarn add koa-router

使用 koa-router 创建和处理路由:
const Router = require('koa-router');
const router = new Router();
// 定义路由
router.get('/', async (ctx) => {
  ctx.body = 'Hello, Koa!';
});
// 注册路由中间件
app.use(router.routes());

5.启动服务器:
使用 app.listen() 方法来启动服务器,并监听指定的端口:
const port = 3000;
app.listen(port, () => {
  console.log(`Server running on port ${port}`);
});

疑问1:在 Koa2 中,中间件函数通常会接收两个参数:ctxnext

  • ctx(Context):ctx 是一个上下文对象,它封装了请求和响应的相关信息。通过 ctx,你可以访问请求的头部、参数、URL 等信息,并设置响应的状态码、头部、内容等。ctx 提供了许多属性和方法来操作请求和响应。
  • nextnext 是一个函数,用于调用下一个中间件函数。当一个中间件完成它的任务后,可以通过调用 next() 来将控制权移交给下一个中间件函数。如果不调用 next(),后续的中间件将不会执行。
  • 在中间件函数中,asyncawait 是用于处理异步操作的关键字。通过将中间件函数声明为 async,可以在其中使用 await 来等待异步操作的完成。

疑问2:await意思是让异步变成同步了吗?

实际上,await 并不会将异步操作变成同步操作。它只是用于在异步操作执行完成之前,暂停函数的执行,并等待异步操作的结果。

需要注意的是,只有在 async 函数内部才能使用 await 关键字,而且 async 函数本身也是异步的,它返回一个 Promise 对象,因此调用 async 函数时需要使用 await 或者处理返回的 Promise 对象。

疑问3:promise是什么东西?

Promise 是 JavaScript 中用于处理异步操作的一种机制,它提供了一种更优雅和可靠的方式来处理异步任务的结果。

在传统的回调函数模式中,异步操作的结果通常通过回调函数传递。这种方式可能导致回调地狱(callback hell)的问题,代码可读性较差,逻辑复杂。而 Promise 提供了一种链式调用的方式,使得异步操作的处理更加清晰和可维护。

疑问4:回调地狱什么意思

回调地狱(Callback Hell)指的是在异步编程中,多层嵌套的回调函数形成的一种代码结构,导致代码可读性差、难以理解和维护的问题。

当有多个异步操作需要依次执行时,往往会出现回调函数嵌套的情况。每个异步操作的回调函数又会包含另一个异步操作,这样就形成了嵌套的回调函数结构,导致代码缩进层级过深,难以跟踪和理解。

例如,以下是一个简化的回调地狱示例:

asyncOperation1(function(result1) {
  asyncOperation2(result1, function(result2) {
    asyncOperation3(result2, function(result3) {
      // ... 更多的回调嵌套
    });
  });
});

这种回调地狱的代码结构很难阅读和维护,因为代码逻辑被分散在多个回调函数中,而且代码缩进深,增加了理解的难度。此外,错误处理也变得复杂,很难在合适的位置捕获和处理错误。

疑问5:通过将中间件函数声明为 async,可以在其中使用 await 来等待异步操作的完成。但是很多地方没有使用await啊,它怎么处理异步操作结束后的结果呢?

当中间件函数中没有使用 await 关键字时,它仍然是一个异步函数,它会返回一个 Promise 对象。在 Koa2 中,中间件函数可以返回一个 Promise 对象,用于处理异步操作的结果。如果没有使用 await,则返回的 Promise 对象会立即被解析,不会等待异步操作的完成。

你可以通过在中间件函数中使用 .then().catch() 方法来处理 Promise 对象的结果。

例如,以下是一个示例代码:

app.use((ctx, next) => {
  // 异步操作
  const promise = someAsyncFunction();

  promise.then((result) => {
    // 处理异步操作成功的结果
    ctx.body = result;
    // 调用下一个中间件
    return next();
  }).catch((error) => {
    // 处理异步操作失败的结果
    console.error(error);
    // 响应错误状态码
    ctx.status = 500;
  });
});

在上述示例中,someAsyncFunction() 返回一个 Promise 对象。我们通过调用 .then() 方法来处理异步操作成功的结果,通过调用 .catch() 方法来处理异步操作失败的结果。

.then() 方法中,我们可以设置相应的响应体(ctx.body),并通过调用 next() 来调用下一个中间件。在 .catch() 方法中,我们可以处理错误情况,并设置相应的响应状态码。

即使没有使用 await,仍然可以通过 Promise 的方法链式调用来处理异步操作的结果。这样可以保持代码的可读性,并且依然能够处理异步操作的成功和失败情况。

Mysql

身为后端开发人员,mysql我可太熟悉了,这里简单介绍下node操作Mysql的过程。

const mysql = require('mysql2');

// 创建数据库连接
const connection = mysql.createConnection({
  host: '127.0.0.1',
  user: 'root',
  password: '123456',
  database: 'guli',
});

// 连接数据库
connection.connect((err) => {
  if (err) {
    console.error('Failed to connect to MySQL:', err);
    return;
  }
  console.log('Connected to MySQL');
});

// 创建数据
const createData = (data) => {
  const sql = 'INSERT INTO nodejs_test (name, age) VALUES (?, ?)';
  const values = [data.name, data.age];

  connection.query(sql, values, (err, result) => {
    if (err) {
      console.error('Failed to create data:', err);
      return;
    }
    console.log('Data created:', result);
  });
};

// 读取数据
const readData = () => {
  const sql = 'SELECT * FROM nodejs_test';

  connection.query(sql, (err, results) => {
    if (err) {
      console.error('Failed to read data:', err);
      return;
    }
    console.log('Data read:', results);
  });
};

// 更新数据
const updateData = (id, data) => {
  const sql = 'UPDATE nodejs_test SET name = ?, age = ? WHERE id = ?';
  const values = [data.name, data.age, id];

  connection.query(sql, values, (err, result) => {
    if (err) {
      console.error('Failed to update data:', err);
      return;
    }
    console.log('Data updated:', result);
  });
};

// 删除数据
const deleteData = (id) => {
  const sql = 'DELETE FROM nodejs_test WHERE id = ?';
  const values = [id];

  connection.query(sql, values, (err, result) => {
    if (err) {
      console.error('Failed to delete data:', err);
      return;
    }
    console.log('Data deleted:', result);
  });
};

// 调用相应的函数执行 CRUD 操作
createData({ name: 'zs', age: '22' });
readData();
updateData(1, { name: 'zs', age: '23' });
deleteData(1);

// 断开数据库连接
connection.end((err) => {
  if (err) {
    console.error('Failed to disconnect from MySQL:', err);
    return;
  }
  console.log('Disconnected from MySQL');
});

Socket编程

WebSocket 服务器端代码:

javascriptCopy code
const WebSocket = require('ws');

// 创建 WebSocket 服务器
const wss = new WebSocket.Server({ port: 8080 });

// 监听连接事件
wss.on('connection', (ws) => {
  console.log('Client connected');

  // 监听消息事件
  ws.on('message', (message) => {
    console.log('Received message from client:', message);
  });

  // 监听关闭事件
  ws.on('close', () => {
    console.log('Client disconnected');
  });
});

WebSocket 客户端代码:

javascriptCopy code
const WebSocket = require('ws');

// 创建 WebSocket 客户端连接
const socket = new WebSocket('ws://localhost:8080');

// 监听连接事件
socket.onopen = () => {
  console.log('Connected to server');
  
  // 发送消息到服务器
  socket.send('Hello from client');
};

// 监听消息事件
socket.onmessage = (event) => {
  console.log('Received message from server:', event.data);
};

// 监听关闭事件
socket.onclose = () => {
  console.log('Disconnected from server');
};

在上述代码中,我们使用 ws 模块创建了一个 WebSocket 服务器,并监听在端口 8080。当客户端连接到服务器时,会触发 connection 事件,在事件处理程序中监听客户端的消息和关闭事件。

客户端通过创建一个 WebSocket 客户端连接,连接到服务器的 WebSocket 端口。在连接建立后,客户端发送一条消息到服务器,并监听服务器发送的消息和关闭事件。

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

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

相关文章

迎接高考的倒计时网页(❤️好看好用❤️)HTML+CSS+JS

✨博主&#xff1a;命运之光 &#x1f338;专栏&#xff1a;Python星辰秘典 &#x1f433;专栏&#xff1a;web开发&#xff08;简单好用又好看&#xff09; ❤️专栏&#xff1a;Java经典程序设计 ☀️博主的其他文章&#xff1a;点击进入博主的主页 前言&#xff1a;欢迎踏入…

并发编程_jmm部分

1. JMM 理解 前提&#xff1a;并发编程有3大问题&#xff0c;可见性、有序性、原子性。 导致可见性的原因是缓存&#xff0c;有序性的原因是 编译器优化。解决方法就是直接禁用缓存和编译器优化&#xff0c;导致程序性能堪忧。 因此合理的方案就是按需禁用缓存和编译器优化。 …

MySQL数据库——单表查询练习

一、练习素材 创建表 CREATE TABLE emp (empno int(4) NOT NULL,ename varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,job varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,mgr int(4) NULL DEFAULT NULL,hireda…

遗传算法核心理解,python代码

遗传算法的核心&#xff0c;就在于&#xff0c;把待求的变量转化成二进制串&#xff0c;二进制串就像dna&#xff0c;可以对它的其中某几位进行交换&#xff0c;变异等操作&#xff0c;然后再转换回十进制&#xff0c;带入目标函数&#xff0c;计算适应度&#xff0c;保留适应度…

【lambda函数】lambda()函数

lambda&#xff08;&#xff09; lambda&#xff08;&#xff09;语法捕捉列表mutable lambda 底层原理函数对象与lambda表达式 lambda&#xff08;&#xff09;语法 lambda表达式书写格式&#xff1a; [capture-list] (parameters) mutable -> return-type{ statement }咱…

【数据结构】排序:插入排序与希尔排序详解

本章开始就要分享一些常用的排序方法&#xff0c;我们的日常生活中很多地方都要使用排序&#xff0c;比如电商平台可以按照你的需求进行排序&#xff0c;或者是你想了解大学的综合排名时 我们之前也学到过一些简单的排序比如冒泡排序&#xff0c;虽然他在时间复杂度上可以说是依…

归并排序(思路+代码)

变量&#xff1a; left、right、privot、temp[]、leftIndex、k 思路&#xff1a; 代码&#xff1a; import java.util.Arrays;public class Queue8 {public static void main(String[] args) {int[] arr {8, 9, 1, 7, 2, 3, 5, 4, 6, 0};sort(arr,0,arr.length-1);System.ou…

AST-抽象语法树

js加密解混淆首先想到的是AST语法树&#xff0c;那么什么是AST呢&#xff0c;学习AST过程的一些笔记 1.AST是JS执行的第一步是读取 js 文件中的字符流&#xff0c;然后通过词法分析生成令牌流Tokens&#xff0c;之后再通过语法分析生成 AST&#xff08;Abstract Syntax Tree&a…

3D 旋转木马

在工作中我们常用到3D装换和3D位移 主要知识点 3D位移&#xff1a;transale3d(x,y,z)3D旋转&#xff1a;rotate3d(x,y,z)透视&#xff1a;perspective3D呈现 transfrom-style 1、 transale3d translform: translform:translateX(100px):仅仅是在x轴上移动translform:transl…

[NOI2014] 随机数生成器(模拟+贪心)

题面 [NOI2014] 随机数生成器 - 洛谷 题解 缝合题 第一部分&#xff0c;直接模拟题目操作生成二维数组即可&#xff0c;复杂度O(n*mQ) 第二部分&#xff0c;是一个比较经典的字典序贪心 首先肯定需要将最小的数放到路径上&#xff0c;这样可选的剩下的数就被限制在了最小数…

Redis 管道

问题由来&#xff1a;如何优化频繁命令往返造成的性能瓶颈&#xff1f; Redis是一种基于客户端-服务端模型以及请求/响应协议的TCP服务。 一个请求会遵循以下步骤&#xff1a; 1、客户端向服务端发送命令分四步(发送命令→命令排队→命令执行→返回结果)&#xff0c;并监听S…

Codeforces Round 883 (Div. 3) A~G

比赛链接&#xff1a;Dashboard - Codeforces Round 883 (Div. 3) - Codeforces 目录 A. Rudolph and Cut the Rope B. Rudolph and Tic-Tac-Toe C. Rudolf and the Another Competition D. Rudolph and Christmas Tree E. Rudolf and Snowflakes F. Rudolph and Mimic…

JavaWeb项目(包含SSM项目)部署到Linux云服务器

目录 一、云服务器环境部署 1、安装JDK 查看JDK的命令为&#xff1a; 安装JDK命令&#xff1a; 2、安装Tomcat 2.1 安装步骤 2.2 验证Tomcat是否启动成功 3、安装MySQL 二、部署 Web 项目到 Linux 2.1 在云服务器中数据库建库建表 2.2 修改部署项目连接数据库密码 …

Qt(Day2)

实现登录框中&#xff0c;当登录成功时&#xff0c;关闭登录界面&#xff0c;并跳转到其他界面&#xff1a;

Go实现在线词典翻译(三种翻译接口,结合sync)

火山翻译 首先介绍用火山翻译英译汉。 package mainimport ("bufio""bytes""encoding/json""fmt""io""log""net/http""os""strings""unicode" )type DictRequestHS st…

第四章:角色和菜单管理功能【基于Servlet+JSP的图书管理系统】

角色和菜单功能 一、角色功能 接下来我们可以完成角色管理的增删改查操作 1. Bean对象 创建sys_role对应的实体对象SysRole Data public class SysRole {private Integer id;private String name;private String notes;private Date createTime; }2. Dao层 现在我们就可以在D…

JVM(Java虚拟机)详解

目录 一、JVM内存区域划分 1. 什么是内存区域划分以及为啥要进行区域划分 2. JVM内存区域划分详解 3. 堆区详解&#xff1a; 4. 给一段代码&#xff0c;问某个变量是在那个区域上&#xff1f; 二、JVM类加载机制 1.类加载的过程 2. 类加载的时机 3. 双亲委派模型&#xff08…

下班前几分钟,我彻底玩懂了tmux

目录 1. tmux简介2. Session3. Window4. Pane5. 自定义tmux配置6. 在shell脚本中操纵tmuxReferences 1. tmux简介 tmux&#xff08;terminal multiplexer&#xff09;是一个非常强大的工具&#xff0c;主要有以下几点功能&#xff1a; 终端复用&#xff1a; tmux 使你能够在一…

Linux分布式应用 Zabbix监控配置[添加主机 自定义监控内容 邮件报警 自动发现/注册 代理服务器 高可用集群]

-------------------- 添加 zabbix 客户端主机 -------------------- 关闭防火墙 systemctl disable --now firewalld setenforce 0 hostnamectl set-hostname zbx-agent01 服务端和客户端都配置时间同步 yum install -y ntpdate ntpdate -u ntp.aliyun.com 服务端和客户端都设…

基于simulink跟踪火车站对象检测遗弃物体(附源码)

一、前言 此示例演示如何跟踪火车站的对象并确定哪些对象保持静止。公共场所的遗弃物品会引起当局的关注&#xff0c;因为它们可能会构成安全风险。算法&#xff08;例如本例中使用的算法&#xff09;可用于通过将他们的注意力引导到潜在的感兴趣区域来协助监控实时监控视频的…