Node.js |(六)express框架 | 尚硅谷2023版Node.js零基础视频教程
学习视频:尚硅谷2023版Node.js零基础视频教程,nodejs新手到高手
文章目录
- 📚express使用
- 🐇初体验
- 🐇express路由
- ⭐️路由的使用
- ⭐️获取请求参数
- ⭐️获取路由参数
- 🔥练习:根据路由参数响应歌手信息
- 🐇express响应设置
- 🐇express中间件
- ⭐️定义全局中间件
- ⭐️定义路由中间件
- ⭐️静态资源中间件
- 🔥静态资源中间件练习:局域网内访问网页❓
- 🐇 获取请求体数据 body-parser
- 🐇express防盗链
- 🔥防盗链实践
- 📚路由模块化Router
- 🐇介绍
- 🐇使用
- 📚EJS模板引擎
- 🐇介绍
- 🐇列表渲染
- 🐇条件渲染
- 🐇express中使用ejs
- 📚应用程序生成器express-generator
📚express使用
🐇初体验
- express 是一个基于 Node.js 平台的极简、灵活的 WEB 应用开发框架,官方网址
- 简单来说,express 是一个封装好的工具包,封装了很多功能,便于我们开发 WEB 应用(HTTP 服务)
-
express 本身是一个 npm 包,所以可以通过 npm 安装
npm init npm i express
-
初体验
//1. 导入 express const express = require('express'); //2. 创建应用对象 const app = express(); //3. 创建路由规则 app.get('/home', (req, res) => {res.end('hello express server'); }); //4. 监听端口 启动服务 app.listen(3000, () =>{console.log('服务已经启动, 端口监听为 3000...'); });
🐇express路由
官方定义: 路由确定了应用程序如何响应客户端对特定端点的请求。
⭐️路由的使用
-
一个路由的组成由
请求方法
,路径
和回调函数
组成。 -
express中提供了一系列方法,使用路由,使用格式如下:
app.<method>(path,callback)
-
res.end和res.send的区别
//导入 express const express = require('express'); //创建应用对象 const app = express(); //创建 get 路由 app.get('/home', (req, res) => {res.send('网站首页'); }); //首页路由 app.get('/', (req,res) => {res.send('我才是真正的首页'); }); //创建 post 路由 app.post('/login', (req, res) => {res.send('登录成功'); }); //匹配所有的请求方法 app.all('/search', (req, res) => {res.send('1 秒钟为您找到相关结果约 100,000,000 个'); }); //自定义 404 路由 app.all("*", (req, res) => {res.send('<h1>404 Not Found</h1>') }); //监听端口 启动服务 app.listen(3000, () =>{console.log('服务已经启动, 端口监听为 3000'); });
-
以下是上述代码运行后直接输网址得到的返回。
-
针对login部分,上边那得不到想要的是因为指定了post
⭐️获取请求参数
- express 框架封装了一些 API 来方便获取请求报文中的数据,并且兼容原生 HTTP 模块的获取方式。
//导入 express const express = require('express'); //创建应用对象 const app = express(); //获取请求的路由规则 app.get('/request', (req, res) => {//1. 获取报文的方式与原生 HTTP 获取方式是兼容的console.log(req.method);console.log(req.url);console.log(req.httpVersion);console.log(req.headers);//2. express 独有的获取报文的方式//获取查询字符串console.log(req.query); // 『相对重要』//获取ipconsole.log(req.ip)// 获取指定的请求头console.log(req.get('host'));res.send('请求报文的获取'); }); //启动服务 app.listen(3000, () => {console.log('启动成功....') })
⭐️获取路由参数
- 路由参数指的是 URL 路径中的参数(数据)
//导入 express const express = require('express');//创建应用对象 const app = express();//创建路由 app.get('/:id.html', (req, res) => {//获取 URL 路由参数res.send('商品详情, 商品 id 为' + req.params.id); });//监听端口, 启动服务 app.listen(3000, () => {console.log('服务已经启动, 端口 3000 正在监听中....') })
🔥练习:根据路由参数响应歌手信息
//导入 express
const express = require('express');
//导入 json 文件(中括号解构,返回数组)
const {singers} = require('./singers.json');
//创建应用对象
const app = express();//创建路由
app.get('/singer/:id.html', (req, res) => {//获取路由参数let {id} = req.params;//在数组中寻找对应 id 的数据let result = singers.find(item => {if(item.id === Number(id)){return true;}});//判断if(!result){res.statusCode = 404;res.send(`<h1>404 Not Found</h1>`)return;}res.send(`<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title></head><body><h2>${result.singer_name}</h2><img src='${result.singer_pic}' /></body></html>`);
});//监听端口, 启动服务
app.listen(3000, () => {console.log('服务已经启动, 端口 3000 正在监听中....')
})
🐇express响应设置
-
express 框架封装了一些 API 来方便给客户端响应数据,并且兼容原生 HTTP 模块的获取方式
//获取请求的路由规则 app.get("/response", (req, res) => { //1. express 中设置响应的方式兼容 HTTP 模块的方式 res.statusCode = 404; res.statusMessage = 'xxx'; res.setHeader('abc','xyz'); res.write('响应体'); res.end('xxx'); //2. express 的响应方法 res.status(500); //设置响应状态码 res.set('xxx','yyy');//设置响应头 res.send('中文响应不乱码');//设置响应体 //连贯操作 res.status(404).set('xxx','yyy').send('你好朋友') //3. 其他响应 res.redirect('http://atguigu.com')//重定向 res.download('./package.json');//下载响应 res.json();//响应 JSON res.sendFile(__dirname + '/home.html') //响应文件内容 });
🐇express中间件
- 中间件(Middleware)本质是一个回调函数。中间件函数可以像路由回调一样访问请求对象(request)和响应对象(response)。
- 中间件的作用 就是 使用函数封装公共操作,简化代码。
- 类型:全局中间件和路由中间件。
⭐️定义全局中间件
-
声明中间件函数
let recordMiddleware = function(request,response,next){//实现功能代码//.....//执行next函数(当如果希望执行完中间件函数之后,仍然继续执行路由中的回调函数,必须调用next)next(); }
-
应用中间件:
app.use(recordMiddleware);
-
声明时直接传递
app.use(function (request, response, next) {console.log('定义第一个中间件');next(); })
-
express 允许使用 app.use() 定义多个全局中间件
app.use(function (request, response, next) {console.log('定义第一个中间件');next(); }) app.use(function (request, response, next) {console.log('定义第二个中间件');next(); })
/*** 记录每个请求的 url 与 IP 地址*/
//导入 express
const express = require('express');
const fs = require('fs');
const path = require('path');//创建应用对象
const app = express();//声明中间件函数(在这里就是起一个函数声明形成模板,不用在每个app里写记录语句)
//把公共代码放这里(这样每次请求都能被记录)
function recordMiddleware(req, res, next){//获取 url 和 iplet {url, ip} = req;//将信息保存在文件中 access.logfs.appendFileSync(path.resolve(__dirname, './access.log'), `${url} ${ip}\r\n`);//调用 next,让它去调用后续的路由函数next();
}//使用中间件函数
app.use(recordMiddleware);//创建路由
app.get('/home', (req, res) => {res.send('前台首页');
});app.get('/admin', (req, res) => {res.send('后台首页');
});app.all('*',(req, res) => {res.send('<h1>404 Not Found</h1>')
})//监听端口, 启动服务
app.listen(3000, () => {console.log('服务已经启动, 端口 3000 正在监听中....')
})
⭐️定义路由中间件
-
如果只需要对某一些路由进行功能封装 ,则就需要路由中间件。
-
调用格式如下:
app.get('/路径',`中间件函数`,(request,response)=>{ }); app.get('/路径',`中间件函数1`,`中间件函数2`,(request,response)=>{ });
/*** 针对 /admin /setting 的请求, 要求 URL 携带 code=521 参数, 如未携带提示『暗号错误』 *///导入 express
const express = require('express');//创建应用对象
const app = express();//创建路由
app.get('/home', (req, res) => {res.send('前台首页');
});//声明中间件
let checkCodeMiddleware = (req, res, next) => {//判断 URL 中是否 code 参数等于 521if(req.query.code === '521'){// 满足条件就调用next();}else{res.send('暗号错误');}
}//后台
app.get('/admin', checkCodeMiddleware, (req, res) => {res.send('后台首页');
});//后台设置
app.get('/setting', checkCodeMiddleware, (req, res) => {res.send('设置页面');
});app.all('*',(req, res) => {res.send('<h1>404 Not Found</h1>')
})//监听端口, 启动服务
app.listen(3000, () => {console.log('服务已经启动, 端口 3000 正在监听中....')
})
⭐️静态资源中间件
-
express 内置处理静态资源(css,图片等)的中间件
//引入express框架 const express = require('express'); //创建服务对象 const app = express(); //静态资源中间件的设置,将当前文件夹下的public目录作为网站的根目录 app.use(express.static('./public')); //当然这个目录中都是一些静态资源 //如果访问的内容经常变化,还是需要设置路由 //但是,在这里有一个问题,如果public目录下有index.html文件,单独也有index.html的路由, //则谁书写在前,优先执行谁 app.get('/index.html',(request,response)=>{respsonse.send('首页'); }); //监听端口 app.listen(3000,()=>{console.log('3000 端口启动....'); });
//导入 express
const express = require('express');//创建应用对象
const app = express();//创建路由
app.get('/', (req, res) => {res.send('我才是首页~~~');
});//静态资源中间件设置
app.use(express.static(__dirname + '/public'));//监听端口, 启动服务
app.listen(3000, () => {console.log('服务已经启动, 端口 3000 正在监听中....')
})
🔥静态资源中间件练习:局域网内访问网页❓
喵喵大王立大功
- 首先
npm init
- 其次
npm i express
- 创建server.js
const express = require('express'); const app = express();// 设置静态资源中间件 app.use(express.static(__dirname + '/todolist'));app.listen(3000,() =>{console.log('服务已经启动,端口3000正在监听中......') })
node .\server.js
- 查看ip地址:cmd ——>
ipconfig
- 可实现局域网内访问喵喵大王立大功的网页(呜三个舍友只有一个可以呜呜)
- 解决办法:ISS管理界面修改
🐇 获取请求体数据 body-parser
-
第一步:安装
npm i body-parser
-
第二步:导入 body-parser 包
const bodyParser = require('body-parser');
-
第三步:获取中间件函数
//处理 querystring 格式的请求体 let urlParser = bodyParser.urlencoded({extended:false})); //处理 JSON 格式的请求体 let jsonParser = bodyParser.json();
-
第四步:设置路由中间件,然后使用 request.body 来获取请求体数据
app.post('/login', urlParser, (request,response)=>{//获取请求体数据//console.log(request.body);//用户名console.log(request.body.username);//密码console.log(request.body.userpass);response.send('获取请求体数据'); });
- 应用:记得先装包
/*** 按照要求搭建 HTTP 服务* * GET /login 显示表单网页* POST /login 获取表单中的『用户名』和『密码』*/
//导入 express
const express = require('express');
const bodyParser = require('body-parser')//创建应用对象
const app = express();//解析 JSON 格式的请求体的中间件
// const jsonParser = bodyParser.json()//解析 querystring 格式请求体的中间件
const urlencodedParser = bodyParser.urlencoded({ extended: false })//创建路由规则
app.get('/login', (req, res) => {// res.send('表单页面')//响应 HTML 文件内容res.sendFile(__dirname + '/11_form.html');
});//post 规则
app.post('/login', urlencodedParser, (req, res) => {//获取 用户名 和 密码console.log(req.body);res.send('获取用户的数据')
});//启动服务
app.listen(3000, () => {console.log('server is running...');
})
🐇express防盗链
- 不允许外部网页调用图片。
🔥防盗链实践
- 关键:关注
referer
请求头。 - 功能:只允许127.0.0.1访问
//导入 express const express = require('express');//创建应用对象 const app = express();//声明中间件 app.use((req, res, next) => {//检测请求头中的 referer 是否为 127.0.0.1//获取 refererlet referer = req.get('referer');if(referer){//实例化let url = new URL(referer);//获取 hostnamelet hostname = url.hostname;//判断if(hostname !== '127.0.0.1'){//响应 404 res.status(404).send('<h1>404 Not Found</h1>');return;}}next(); });//静态资源中间件设置 app.use(express.static(__dirname + '/public'));//监听端口, 启动服务 app.listen(3000, () => {console.log('服务已经启动, 端口 3000 正在监听中....') })
📚路由模块化Router
🐇介绍
- express 中的 Router 是一个完整的中间件和路由系统,可以看做是一个小型的 app 对象。
- Router 作用:对路由进行模块化,更好的管理路由。
- 主文件代码量减少,管理更方便,就类似css,js外部分离。
🐇使用
- 创建独立的js文件(homeRouter.js)
//1. 导入 express const express = require('express'); //2. 创建路由器对象 const router = express.Router(); //3. 在 router 对象身上添加路由 router.get('/', (req, res) => { res.send('首页'); }) router.get('/cart', (req, res) => { res.send('购物车'); }); //4. 暴露 module.exports = router;
- 主文件
const express = require('express'); const app = express(); //5.引入子路由文件 const homeRouter = require('./routes/homeRouter'); //6.设置和使用中间件 app.use(homeRouter); app.listen(3000,()=>{console.log('3000 端口启动....'); })
📚EJS模板引擎
🐇介绍
- 模板引擎是分离用户界面和业务数据的一种通用型技术(但现在用的没那么多了)。
- EJS 是一个高效的 Javascript 的模板引擎,官网,中文站
- 下载安装:
npm i ejs --save
- 示例
//1.引入ejs const ejs = require('ejs'); //2.定义数据 let person = ['张三','李四','王二麻子']; //3.ejs解析模板返回结构 //<%= %> 是ejs解析内容的标记,作用是输出当前表达式的执行结构 let html = ejs.render(‘<%= person.join(",") %>’, {person:person}); //4.输出结果 console.log(html);
- 执行js代码:
<% code %>
- 输出转义的数据到模板上:
<%= code %>
- 输出非转义的数据到模板上:
<%- code %>
🐇列表渲染
//原生 JS
let str = '<ul>';
xiyou.forEach(item => {str += `<li>${item}</li>`;
})
//闭合 ul
str += '</ul>';
console.log(str);
<ul><% xiyou.forEach(item => { %><li><%= item %></li><% }) %>
</ul>
🐇条件渲染
// 原生 JS
if(isLogin){console.log('<span>欢迎回来</span>')
}else{console.log('<button>登录</button> <button>注册</button>');
}
<% if(isLogin){ %>
<span>欢迎回来</span>
<% }else{ %>
<button>登录</button> <button>注册</button>
<% } %>
🐇express中使用ejs
//导入 express
const express = require('express');
//导入 path
const path = require('path');
//创建应用对象
const app = express();
//1. 设置模板引擎
app.set('view engine', 'ejs');// pug twing
//2. 设置模板文件存放位置 模板文件: 具有模板语法内容的文件
app.set('views', path.resolve(__dirname, './views'));//创建路由
app.get('/home', (req, res) => {//3. render 响应// res.render('模板的文件名', '数据');//声明变量let title = '尚硅谷 - 让天下没有难学的技术';res.render('home', {title});//4. 创建模板文件
});//监听端口, 启动服务
app.listen(3000, () => {console.log('服务已经启动, 端口 3000 正在监听中....')
})
📚应用程序生成器express-generator
- 可以快速创建一个应用的骨架
- 首先全局安装
npm install -g express-generator
- 创建骨架:
express -e <文件夹>
- 然后需要安装依赖
npm i
- 运行
npm start
- 该有都有,补充什么,在对应内容添加即可。
相关文章:

Node.js |(六)express框架 | 尚硅谷2023版Node.js零基础视频教程
学习视频:尚硅谷2023版Node.js零基础视频教程,nodejs新手到高手 文章目录 📚express使用🐇初体验🐇express路由⭐️路由的使用⭐️获取请求参数⭐️获取路由参数🔥练习:根据路由参数响应歌手信息…...

包教包会:Mysql主从复制搭建
笑小枫的专属目录 一、无聊的理论知识1. 主从复制原理2. 主从复制的工作过程3. MySQL四种同步方式 二、docker下安装、启动mysql1. 安装主库2. 安装从库 三、配置Master(主)四、配置Slave(从)五、链接Master(主)和Slave(从)六、主从复制排错1. 错误:error connectin…...
Subset Selection
白话解释:https://www.geeksforgeeks.org/feature-subset-selection-process/ 貌似有一种比较常见的方法,称为多元逐步回归有3种筛选自变量的方法 (1)向前法:n个因变量情况,慢慢增加因变量到方程中&#x…...
【测开求职】面试题:计算机网络 精简版整理
本篇文章整理的是在秋招过程中遇到的计算机网络高频面试题,应付部分中小厂的测试开发工程师面试完全没有问题,如果时间充足的话,建议再看一下笔者的另外一篇文章:【测开求职】面试题:计算机网络 详细版整理,会让你对整个计算机网络有足够全面深刻的理解,亲测应付各个大厂…...
设计模式-代理模式(delegate)
什么是代理? 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能. 这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方…...
MongoDB 安装与配置
MongoDB 安装与配置 MongoDB 是一个高性能、开源的 NoSQL 数据库,它提供了丰富的查询功能和高可用性。本文将详细讲解 MongoDB 的安装与配置过程。 1. MongoDB 安装 1.1 Windows 平台安装 下载 MongoDB 安装包 访问 MongoDB 官方下载页面(https://w…...

rabbitMq创建交换机,以及路由键绑定队列教程
创建交换机: 创建队列: 创建路由,绑定到交换机:...
odoo16前端框架源码阅读——ormService.js
odoo16前端框架源码阅读——ormService.js 路径:addons\web\static\src\core\orm_service.js 简单翻译一下代码中的注释: ORM服务是js代码和python的ORM层通信的标准方法。 然后讲了One2many and Many2many特使的指令格式,每个指令都是3元…...
详谈滑动窗口算法与KMP算法区别以及二者在什么场景下使用
什么是滑动窗口算法 滑动窗口算法是一种用于解决数组(或字符串)中子数组(或子字符串)问题的算法。该算法通过维护一个固定大小的窗口(通常是两个指针),该窗口在数组上滑动,以寻找符…...

k8s、数据存储
数据存储的概念 容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题。首先,当容器崩溃时,kubelet 会重启它,但是容器中的文件将丢失——容器以干净的状态(镜像最初的状态)…...

Vue生命周期全解析:从工厂岗位到任务执行,一览无遗!
🎬 江城开朗的豌豆:个人主页 🔥 个人专栏 :《 VUE 》 《 javaScript 》 📝 个人网站 :《 江城开朗的豌豆🫛 》 ⛺️ 生活的理想,就是为了理想的生活 ! 目录 ⭐ 专栏简介 📘 文章引言 一、生…...

常见产品结构四大类型 优劣势比较
一般,我们通过产品架构来构建用户体验,这样可以提供更清晰的导航和组织、优化用户流程和交互、增强产品的可扩展性和可维护性,提升用户的满意度和忠诚度。如果没有明确的产品结构,可能会导致功能冗余或功能缺失、交互流程混乱等问…...

如何优雅的开发?试试这个低代码项目
一、前言 众所周知,开发一个大型的企业级系统,公司往往需要大量的人力做支持后盾,如需要需求分析师、数据库管理员、前台美工、后台程序员、测试人员等。 在快速发展中的企业里,尤其是中小企业,都是一个萝卜多个坑&…...
个人开发常用idea插件
idea重装后必须要配置的几项: Maven: File-->Settings-->Maven字体: IDE字体设置:File-->Settings-->Appearance,设置成Consolas,Size:18代码字体设置:File-->Setti…...

如何使用ArcGIS Pro制作个性三维地形图
制作三维地图制作的多了,想着能不能换个“口味”,恰好看见制作六边形蜂窝图,灵光一闪,想着将二者结合,将平滑的三维地形图改成柱状图,从结果来看还可以,这里将制作方法分享给大家,希…...
支撑企业数字化经营,《2023指标平台白皮书》正式发布
导语 随着宏观经济步入新常态和市场不确定性加剧,我国企业的经营环境正在发生深刻变化。为了更好地应对挑战,企业需转向高质量发展,通过精细化管理等手段优化业务结构、提高运营效率和创新能力。在数字经济时代,借助数字化手段实现…...
【Linux】Linux的两种连接文件方法(ln | 符号链接和硬链接)
在一次线上配置文件时,不小心将配置文件config.py放在了错误的地方,而目前项目已经运行,又不能重新配置启动项目,那么如何将其他地方的文件放在当前配置目录来使用,并实现其他地方文件改动,配置目录下文件也…...

vue 点击滑动到页面指定位置(点击下滑滚动)的功能
需求 点击页面上的 文字 滑动到页面指定位置 三种方法 document.getElementById(show).scrollIntoView() // 默认滚动至节点置顶document.getElementById(show).scrollIntoView(false) // 默认滚动至节点显示document.getElementById(show).scrollIntoView({ behavior: &quo…...
LCD婴儿电子秤pcba/芯片方案设计
一、LCD婴儿秤方案技术规格 1.额定量程:20Kg 2.分度值:D10g、0.02LB 3.最小秤量:20G. 4.单位:KG/LB/LB:OZ 5.归零范围:满量程 6.低压侦…...

2023年开发语言和数据库排行
2023年开发语言和数据库排行 一、开发语言相关1. Python1.1 Python优点1.2 Python缺点1.3 Python应用领域 2. C 语言2.1 C 语言优点2.2 C 语言缺点2.3 C语言应用领域 3. Java3.1 Java 优点3.2 Java缺点3.3 Java应用场景 4. C4.1 C 优点4.2 C 缺点4.3 C 应用场景 5. C#5.1 C# 优…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...

关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...

ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...

回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...

MySQL 知识小结(一)
一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能
1. 开发环境准备 安装DevEco Studio 3.1: 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK 项目配置: // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...
区块链技术概述
区块链技术是一种去中心化、分布式账本技术,通过密码学、共识机制和智能合约等核心组件,实现数据不可篡改、透明可追溯的系统。 一、核心技术 1. 去中心化 特点:数据存储在网络中的多个节点(计算机),而非…...
ubuntu22.04 安装docker 和docker-compose
首先你要确保没有docker环境或者使用命令删掉docker sudo apt-get remove docker docker-engine docker.io containerd runc安装docker 更新软件环境 sudo apt update sudo apt upgrade下载docker依赖和GPG 密钥 # 依赖 apt-get install ca-certificates curl gnupg lsb-rel…...

python可视化:俄乌战争时间线关键节点与深层原因
俄乌战争时间线可视化分析:关键节点与深层原因 俄乌战争是21世纪欧洲最具影响力的地缘政治冲突之一,自2022年2月爆发以来已持续超过3年。 本文将通过Python可视化工具,系统分析这场战争的时间线、关键节点及其背后的深层原因,全面…...