当前位置: 首页 > news >正文

Node.js入门

Node.js入门

html,css,js 30年了

nodejs环境 09年出现 15年

nodejs为我们解决了2个方面的问题:

  • 锦上添花】让我们前端工程师拥有了后端开发能力(开接口,访问数据库) - 大公司BFF(50+)
  • 【✔️】前端工程化(Webpack,vit)

Node.js基本概念

Node.js中文官网

什么是Node.js

作用:

使用 Node.js 编写后端程序 / 支持前端工程化

  • 后端程序:提供接口和数据,网页资源等

  • 前端工程化:对代码压缩,转译,整合(使用各种工具,提升效率)

Node.js 为何能执行 JS?

首先:浏览器能执行 JS 代码,依靠的是内核中的 V8 引擎(C++ 程序)

其次:Node.js 是基于 Chrome V8 引擎进行封装(运行环境)

区别:都支持 ECMAScript 标准语法,Node.js 有独立的 API

注意:Node.js 环境没有 DOM 和 BOM 等

Node.js 安装

nvm

nvm是一个nodejs版本管理工具,它可以在我们电脑中安装多个node版本,并且可以随意切换版本

nvm官网:nvm文档手册 - nvm是一个nodejs版本管理工具 - nvm中文官网

要求:使用nvm安装node 16.19.0(指定版本:为了兼容后期学习的项目)

# ✨安装node 16.19.0版本
nvm install 16.19.0# ✨查看node版本列表(带*号的表示当前使用的版本)
nvm ls# ✨切换node版本
nvm use 16.19.0

成功验证:打开 cmd 终端,输入 node -v 命令查看版本号如果有显示,则代表安装成功

使用 Node.js

修改终端默认执行程序

为了防止某些电脑默认使用的是PowerShell执行js报错,我们需要调整一下如下设置为`Command Prompt`

需求:使用nodejs执行一个js文件,使用console.log()打印三个五角星

步骤:

  1. 新建 index.js 文件,编写打印代码和 for 循环打印 3 个 五角星
  2. 命令:在 VSCode 集成终端中(ctrl+shift+` 打开),输入 node index.js,回车即可执行,并查看结果

注意:node 文件路径

console.log('Hello, World')
for (let i = 0; i < 3; i++) {console.log('☆')
}

Node.js 执行目标 JS 文件,需要使用 node index.js 命令来执行(我们可以借助 VSCode 集成终端使用,好处:可以快速切换到目标 JS 文件所在终端目录,利用相对路径找到要执行的目标 JS 文件

准备node项目

在vs code中编写node代码,默认是没有提示的,通过如下步骤创建一个可以有语法提示的node项目,方便接下来的学习。减轻学习负担

  1. 创建一个空白文件夹 ,例如:mynode
  2. 使用vs code打开 mynode文件夹
  3. 按ctrl + shift + `打开终端
  4. 在终端中输入:npm install @types/node 后在此项目中编写nodejs代码就有提示了

注意:由于npm的镜像源在国外,需要切到国内才速度快

切换命令:npm set registry=https://repo.huaweicloud.com/repository/npm/

fs模块-读写文件

  1. 模块:类似插件,封装了方法和属性供我们使用
  1. fs 模块:是Node.js的内置模块,封装了与本机文件系统进行交互的,方法和属性
  1. fs 模块使用语法如下:

加载 fs 模块,得到 fs 对象

const fs = require('fs')

写入文件内容语法:

fs.writeFile('文件路径', '写入内容', err => {// 写入后的回调函数
})

读取文件内容的语法:

fs.readFile('文件路径', (err, data) => {// 读取后的回调函数// data 是文件内容的 Buffer 数据流
})
  1. 需求:向 test.txt 文件写入内容并读取打印
/*** 目标:使用 fs 模块,读写文件内容* 语法:* 1. 引入 fs 模块* 2. 调用 writeFile 写入内容* 3. 调用 readFile  读取内容*/
// 1. 引入 fs 模块
const fs = require('fs')
// 2. 调用 writeFile 写入内容
// 注意:建议写入字符串内容,会覆盖目标文件所有内容
fs.writeFile('./text.txt', '欢迎使用 fs 模块读写文件内容', err => {if (err) console.log(err)else console.log('写入成功')
})
// 3. 调用 readFile  读取内容
fs.readFile('./text.txt', (err, data) => {if (err) console.log(err)else console.log(data.toString()) // 把 Buffer 数据流转成字符串类型
})

path模块-路径处理

  1. 为什么在 Node.js 待执行的 JS 代码中要用绝对路径:

Node.js 执行 JS 代码时,代码中的路径都是以终端所在文件夹出发查找相对路径,而不是以我们认为的从代码本身出发,会遇到问题,所以在 Node.js 要执行的代码中,访问其他文件,建议使用绝对路径

  1. 新建 03 文件夹编写待执行的 JS 代码,访问外层相对路径下的文件,然后在最外层终端路径来执行目标文件,造成问题

  1. 问题原因:就是从代码文件夹出发,使用../text.txt解析路径,找不到目标文件,报错了!
  1. 解决方案:使用模块内置变量 __dirname配合 path.join() 来得到绝对路径使用
const fs = require('fs')
console.log(__dirname) // D:\备课代码\2_node_3天\Node_代码\Day01_Node.js入门\代码\03// 1. 加载 path 模块
const path = require('path')
// 2. 使用 path.join() 来拼接路径
const pathStr = path.join(__dirname, '..', 'text.txt')
console.log(pathStr)fs.readFile(pathStr, (err, data) => {if (err) console.log(err)else console.log(data.toString())
})
  1. 再次执行查看问题就被修复了!以后在 Node.js 要执行的 JS 代码中访问其他文件的路径,都建议使用绝度路径

案例-压缩前端html

目标:压缩前端代码,让浏览器加载网页更快(体验前端工程化)

前端工程化:对代码压缩,转译,整合,测试,自动部署等等

需求:把public\index.html中 回车符(\r)和换行符(\n)去掉,写入到新 dist\index.html 中

步骤:

  1. 使用fs.readFile读取public\index.html中的内容
  2. 正则替换index.html中字符串 /[\r\n]/g
  3. 将替换后的新内容写入到新dist\index.html中 完成代码压缩
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>时钟案例</title><style>html,body {margin: 0;padding: 0;height: 100%;background-image: linear-gradient(to bottom right, red, gold);}.box {width: 400px;height: 250px;background-color: rgba(255, 255, 255, 0.6);border-radius: 6px;position: absolute;left: 50%;top: 40%;transform: translate(-50%, -50%);box-shadow: 1px 1px 10px #fff;text-shadow: 0px 1px 30px white;display: flex;justify-content: space-around;align-items: center;font-size: 70px;user-select: none;padding: 0 20px;-webkit-box-reflect: below 0px -webkit-gradient(linear, left top, left bottom, from(transparent), color-stop(0%, transparent), to(rgba(250, 250, 250, .2)));}</style>
</head>
<body><div class="box"><div id="HH">00</div><div>:</div><div id="mm">00</div><div>:</div><div id="ss">00</div></div>
</body>
</html>
/* 职责:将 public/index.html压缩代码:
1.使用fs.readFile读取public\index.html中的内容
2.正则替换index.html中字符串/rn]/g
3.将替换后的新内容写入到新dist\index.html中完成代码压缩
*/const { readFile,writeFile } = require("fs");
const path = require("path");// 1. 读取未压缩的index.html内容
let indexPath = path.join(__dirname, 'public/index.html')readFile(indexPath, (err, data) => {if (err) {console.log(err);} else {// console.log(data.toString())let unzipHtml = data.toString()// 2.正则替换index.html中字符串/rn]/gconst reg = /[\r\n]/gconst zipHtml = unzipHtml.replace(reg, '')// console.log(zipHtml)// 3.将替换后的新内容写入到新dist\index.html中完成代码压缩let targetPath = path.join(__dirname, 'dist/index.html')writeFile(targetPath,zipHtml,(err)=>{if(err){console.log(err);                }else{console.log('写入成功');}})}
})

案例-压缩前端JS

需求:把准备好的 JS 文件代码的回车符,换行符,打印语句去掉,并插入到之前 html 内容之后

步骤:

  1. 读取 public/index.js 内容
  2. 使用正则替换内容字符串里的\r \n 和console.log('xxx')
    1. /[\r\n]/g
    2. /console.log\('.+?'\);/g
  1. 拼接 html 内容写入到 dist/index.html 内
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>时钟案例</title><style>html,body {margin: 0;padding: 0;height: 100%;background-image: linear-gradient(to bottom right, red, gold);}.box {width: 400px;height: 250px;background-color: rgba(255, 255, 255, 0.6);border-radius: 6px;position: absolute;left: 50%;top: 40%;transform: translate(-50%, -50%);box-shadow: 1px 1px 10px #fff;text-shadow: 0px 1px 30px white;display: flex;justify-content: space-around;align-items: center;font-size: 70px;user-select: none;padding: 0 20px;-webkit-box-reflect: below 0px -webkit-gradient(linear, left top, left bottom, from(transparent), color-stop(0%, transparent), to(rgba(250, 250, 250, .2)));}</style>
</head>
<body><div class="box"><div id="HH">00</div><div>:</div><div id="mm">00</div><div>:</div><div id="ss">00</div></div>
</body>
</html>
window.addEventListener('load', function () {console.log('测试-网页加载完成了');clock();setInterval(clock, 1000);
});
function clock() {console.log('测试-时钟函数调用了');let dt = new Date();let HH = dt.getHours();let mm = dt.getMinutes();let ss = dt.getSeconds();console.log(dt, HH, mm, ss);document.querySelector('#HH').innerHTML = padZero(HH);document.querySelector('#mm').innerHTML = padZero(mm);document.querySelector('#ss').innerHTML = padZero(ss);
};
function padZero(n) {console.log('时间测试');return n > 9 ? n : '0' + n;
}
/*** 目标二:压缩 js 里代码,并整合到 html 中一起运行*  2.1 读取 public/index.js 内容*  2.2 使用正则替换内容字符串里的,回车符\r 换行符\n 打印语句console.log('xxx');*  2.3 确认后,拼接 html 内容写入到 dist/index.html 内*/
const fs = require('fs')
const path = require('path')
fs.readFile(path.join(__dirname, 'public', 'index.html'), (err, data) => {const htmlStr = data.toString()const resultStr = htmlStr.replace(/[\r\n]/g, '')// 2.1 读取 public/index.js 内容fs.readFile(path.join(__dirname, 'public', 'index.js'), (err, data) => {const jsStr = data.toString()// 2.2 使用正则替换内容字符串里的,回车符\r 换行符\n 打印语句console.log('xxx');const jsResultStr = jsStr.replace(/[\r\n]/g, '').replace(/console.log\('.+?'\);/g, '')const result = `<script>${jsResultStr}</script>`console.log(result)// 2.3 确认后,拼接 html 内容写入到 dist/index.html 内fs.writeFile(path.join(__dirname, 'dist', 'index.html'), resultStr + result, err => {if (err) console.log(err)else console.log('压缩成功')})})})

http模块-创建Web服务

什么是Web服务?

Web 服务:是一种通过网络进行通信和交换数据的技术

  • 大白话:一个程序,用来提供网上信息浏览功能

我们前端可以使用 Node.js来构建一个 Web 服务来与客户端进行数据交换

【前置知识】端口号

http://8.138.119.204:8081/#/screen

http://8.138.119.204:80

创建3000端口的Web服务

基于 Node.js 环境,使用内置 http 模块,创建 Web 服务程序

需求:引入 http 模块,使用相关语法,创建 Web 服务程序,响应返回给请求方一句提示 ‘hello,world’

步骤:

  1. 引入 http 模块,创建 Web 服务对象
  2. 监听 request 请求事件,对本次请求,做一些响应处理
  3. 启动 Web 服务监听对应端口号
  4. 运行本服务在终端进程中,用浏览器发起请求 http://localhost:3000/

注意:

  1. 本机的域名叫做 localhost 或者 127.0.0.1
  2. 一个端口只能有一个服务监听,如果前一个服务器未关闭,则第二次启动会报错
/*** 目标:使用 http 模块,创建 Web 服务* Web服务:一个程序,用于提供网上信息浏览服务* 步骤:*  1. 引入 http 模块,创建 Web 服务对象*  2. 监听 request 事件,对本次请求,做一些响应处理*  3. 启动 Web 服务监听对应端口号*  4. 运行本服务在终端,用浏览器访问 http://localhost:3000/ 发起请求(localhost 是本机域名)* 注意:终端里启动了服务,如果想要终止按 ctrl c 停止即可*/
// 1. 引入 http 模块,创建 Web 服务对象
const http = require('http')
const server = http.createServer()
// 2. 监听 request 事件,对本次请求,做一些响应处理
server.on('request', (req, res) => {res.end('hello, world') // 一次请求只能对应一次响应
})
// 3. 启动 Web 服务监听对应端口号
server.listen(3000, () => {console.log('Web 服务启动了')
})

Web服务-支持中文字符

让 Web 服务,返回中文字符,浏览器正确解析加载

步骤:给 Web 服务程序添加响应头,设置内容类型和正确的编码格式,重启 Web 服务测试访问即可

res.setHeader('Content-Type', 'text/html;charset=utf-8')
  1. 编码:编码是信息从一种形式或格式转换为另一种形式的过程,指的把文字在计算机里的二进制数据,用什么形式展示出来

案例-省份列表接口

  1. 需求:基于 Web 服务,开发提供省份列表数据的接口,了解下后端的代码工作过程

  1. 步骤:
    1. 基于 http 模块,创建 Web 服务
    1. 使用 req.url 获取请求资源路径,并读取 province.json 理论省份数据返回给请求方
    1. 其他路径,暂时返回不存在的提示
    1. 运行 Web 服务,用浏览器发起请求测试,看是否可以获取到省份列表数据
  1. 代码如下:
["北京","天津","河北省","山西省","内蒙古自治区","辽宁省","吉林省","黑龙江省","上海","江苏省","浙江省","安徽省","福建省","江西省","山东省","河南省","湖北省","湖南省","广东省","广西壮族自治区","海南省","重庆","四川省","贵州省","云南省","西藏自治区","陕西省","甘肃省","青海省","宁夏回族自治区","新疆维吾尔自治区","台湾","香港特别行政区","澳门特别行政区"
]
/* 这个web服务提供的服务有:1. 当浏览器或者axios发送了 http://localhost:3000/api/province请求,就响应省份的json数据给客户端拆解流程:1. 准备一个json文件2. 准备一个web服务(http)3. request事件里面做出响应-> fs.readFile读取准备的json文件数据-> 设置响应头Content-Type-> res.end()响应
*/const { readFile } = require('fs')
const http = require('http')
const path = require('path')const server = http.createServer()server.on('request', (req, res) => {// 1. 如何判断客户端请求上来的路径地址是什么?// req.url存储的是请求的url的路径+参数//    console.log(req.url)if (req.url == '/api/province') {// 2. 读取json文件内容响应readFile(path.join(__dirname,'/data/province.json'),(err,data)=>{if(err){res.end('接口500')}else{let jsonStr = data.toString()res.setHeader('Content-Type','application/json')res.end(jsonStr)}})}else{res.end('资源没有找到404')}   
})server.listen(3000, () => {console.log('web服务已经启动,请使用http://localhost:3000来访问');
})

案例-城市列表接口

  1. 需求:基于刚刚的 Web 服务,开发提供城市列表数据的接口,了解下后端代码的工作过程

前置知识:字符串.startsWith() 和querystring模块

  1. 步骤:
    1. 判断 req.url 资源路径+查询字符串,路径前缀匹配 /api/city
    1. 借助 querystring 模块的方法,格式化查询字符串
    1. 读取 city.json 城市数据,匹配省份名字下属城市列表
    1. 返回城市列表,启动 Web 服务测试
  1. 代码如下:
{"北京": ["北京市"],"天津": ["天津市"],"河北省": ["石家庄市","唐山市","秦皇岛市","邯郸市","邢台市","保定市","张家口市","承德市","沧州市","廊坊市","衡水市"],"山西省": ["太原市","大同市","阳泉市","长治市","晋城市","朔州市","晋中市","运城市","忻州市","临汾市","吕梁市"],"内蒙古自治区": ["呼和浩特市","包头市","乌海市","赤峰市","通辽市","鄂尔多斯市","呼伦贝尔市","巴彦淖尔市","乌兰察布市","兴安盟","锡林郭勒盟","阿拉善盟"],"辽宁省": ["沈阳市","大连市","鞍山市","抚顺市","本溪市","丹东市","锦州市","营口市","阜新市","辽阳市","盘锦市","铁岭市","朝阳市","葫芦岛市"],"吉林省": ["长春市","吉林市","四平市","辽源市","通化市","白山市","松原市","白城市","延边朝鲜族自治州"],"黑龙江省": ["哈尔滨市","齐齐哈尔市","鸡西市","鹤岗市","双鸭山市","大庆市","伊春市","佳木斯市","七台河市","牡丹江市","黑河市","绥化市","大兴安岭地区"],"上海": ["上海市"],"江苏省": ["南京市","无锡市","徐州市","常州市","苏州市","南通市","连云港市","淮安市","盐城市","扬州市","镇江市","泰州市","宿迁市"],"浙江省": ["杭州市","宁波市","温州市","嘉兴市","湖州市","绍兴市","金华市","衢州市","舟山市","台州市","丽水市"],"安徽省": ["合肥市","芜湖市","蚌埠市","淮南市","马鞍山市","淮北市","铜陵市","安庆市","黄山市","滁州市","阜阳市","宿州市","巢湖市","六安市","亳州市","池州市","宣城市"],"福建省": ["福州市","厦门市","莆田市","三明市","泉州市","漳州市","南平市","龙岩市","宁德市"],"江西省": ["南昌市","景德镇市","萍乡市","九江市","新余市","鹰潭市","赣州市","吉安市","宜春市","抚州市","上饶市"],"山东省": ["济南市","青岛市","淄博市","枣庄市","东营市","烟台市","潍坊市","济宁市","泰安市","威海市","日照市","莱芜市","临沂市","德州市","聊城市","滨州市","菏泽市"],"河南省": ["郑州市","开封市","洛阳市","平顶山市","安阳市","鹤壁市","新乡市","焦作市","濮阳市","许昌市","漯河市","三门峡市","南阳市","商丘市","信阳市","周口市","驻马店市"],"湖北省": ["武汉市","黄石市","十堰市","宜昌市","襄阳市","鄂州市","荆门市","孝感市","荆州市","黄冈市","咸宁市","随州市","恩施土家族苗族自治州"],"湖南省": ["长沙市","株洲市","湘潭市","衡阳市","邵阳市","岳阳市","常德市","张家界市","益阳市","郴州市","永州市","怀化市","娄底市","湘西土家族苗族自治州"],"广东省": ["广州市","韶关市","深圳市","珠海市","汕头市","佛山市","江门市","湛江市","茂名市","肇庆市","惠州市","梅州市","汕尾市","河源市","阳江市","清远市","东莞市","中山市","潮州市","揭阳市","云浮市"],"广西壮族自治区": ["南宁市","柳州市","桂林市","梧州市","北海市","防城港市","钦州市","贵港市","玉林市","百色市","贺州市","河池市","来宾市","崇左市"],"海南省": ["海口市", "三亚市", "三沙市"],"重庆": ["重庆市"],"四川省": ["成都市","自贡市","攀枝花市","泸州市","德阳市","绵阳市","广元市","遂宁市","内江市","乐山市","南充市","眉山市","宜宾市","广安市","达州市","雅安市","巴中市","资阳市","阿坝藏族羌族自治州","甘孜藏族自治州","凉山彝族自治州"],"贵州省": ["贵阳市","六盘水市","遵义市","安顺市","铜仁市","黔西南布依族苗族自治州","毕节市","黔东南苗族侗族自治州","黔南布依族苗族自治州"],"云南省": ["昆明市","曲靖市","玉溪市","保山市","昭通市","丽江市","普洱市","临沧市","楚雄彝族自治州","红河哈尼族彝族自治州","文山壮族苗族自治州","西双版纳傣族自治州","大理白族自治州","德宏傣族景颇族自治州","怒江傈僳族自治州","迪庆藏族自治州"],"西藏自治区": ["拉萨市","昌都地区","山南地区","日喀则地区","那曲地区","阿里地区","林芝地区"],"陕西省": ["西安市","铜川市","宝鸡市","咸阳市","渭南市","延安市","汉中市","榆林市","安康市","商洛市"],"甘肃省": ["兰州市","嘉峪关市","金昌市","白银市","天水市","武威市","张掖市","平凉市","酒泉市","庆阳市","定西市","陇南市","临夏回族自治州","甘南藏族自治州"],"青海省": ["西宁市","海东市","海北藏族自治州","黄南藏族自治州","海南藏族自治州","果洛藏族自治州","玉树藏族自治州","海西蒙古族藏族自治州"],"宁夏回族自治区": ["银川市", "石嘴山市", "吴忠市", "固原市", "中卫市"],"新疆维吾尔自治区": ["乌鲁木齐市","克拉玛依市","吐鲁番地区","哈密地区","昌吉回族自治州","博尔塔拉蒙古自治州","巴音郭楞蒙古自治州","阿克苏地区","克孜勒苏柯尔克孜自治州","喀什地区","和田地区","伊犁哈萨克自治州","塔城地区","阿勒泰地区"],"台湾省": ["台北市","高雄市","台南市","台中市","金门县","南投县","基隆市","新竹市","嘉义市","新北市","宜兰县","新竹县","桃园县","苗栗县","彰化县","嘉义县","云林县","屏东县","台东县","花莲县","澎湖县","连江县"],"香港特别行政区": ["香港岛", "九龙", "新界"],"澳门特别行政区": ["澳门半岛", "离岛"]
}
/* 这个web服务提供的服务有:1. 当浏览器或者axios发送了 http://localhost:3000/api/province请求,就响应省份的json数据给客户端拆解流程:1. 准备一个json文件2. 准备一个web服务(http)3. request事件里面做出响应-> fs.readFile读取准备的json文件数据-> 设置响应头Content-Type-> res.end()响应
*/const { readFile } = require('fs')
const http = require('http')
const path = require('path')
const qs = require('querystring')const server = http.createServer()server.on('request', (req, res) => {// 1. 如何判断客户端请求上来的路径地址是什么?// req.url存储的是请求的url的路径+参数//    console.log(req.url)if (req.url == '/api/province') {// 2. 读取json文件内容响应readFile(path.join(__dirname, '/data/province.json'), (err, data) => {if (err) {res.end('接口500')} else {let jsonStr = data.toString()res.setHeader('Content-Type', 'application/json')res.end(jsonStr)}})}else if (req.url.startsWith('/api/city')) {// 城市数据的提供// 1. 获取请求pname的值// req.url  // /api/city?pname=辽宁省let queryString = req.url.split('?')[1]  //pname=辽宁省const queryObj = qs.parse(queryString)  // {pname:'辽宁省'}// console.log(queryObj.pname);// 2. 根据pname的值从city.json中获取指定的省份的城市响应readFile(path.join(__dirname, 'data/city.json'), (err, data) => {if (err) {res.end('500 server error')} else {// 字符串const cityJsonString = data.toString()// 必须将cityJsonString 转换js对象const cityObj = JSON.parse(cityJsonString)let cityArr = cityObj[queryObj.pname] // ['广州市','深圳市','''']res.setHeader('Content-Type', 'application/json;')res.end(JSON.stringify(cityArr))}})}else {res.end('资源没有找到404')}
})server.listen(3000, () => {console.log('web服务已经启动,请使用http://localhost:3000来访问');
})

案例-浏览时钟

  1. 需求:基于 Web 服务,开发提供网页资源的功能,了解下后端的代码工作过程

  1. 步骤:
    1. 基于 http 模块,创建 Web 服务
    1. 使用 req.url 获取请求资源路径为 /index.html 的时候,读取 index.html 文件内容字符串返回给请求方
    1. 其他路径,暂时返回不存在的提示
    1. 运行 Web 服务,用浏览器发起http://localhost:3000/index.html请求查看结果是否为倒计时页面
  1. 代码如下:
<!DOCTYPE html><html lang="en"><head>  <meta charset="UTF-8">  <meta name="viewport" content="width=device-width, initial-scale=1.0">  <meta http-equiv="X-UA-Compatible" content="ie=edge">  <title>时钟案例</title>  <style>    html,    body {      margin: 0;      padding: 0;      height: 100%;      background-image: linear-gradient(to bottom right, red, gold);    }    .box {      width: 400px;      height: 250px;      background-color: rgba(255, 255, 255, 0.6);      border-radius: 6px;      position: absolute;      left: 50%;      top: 40%;      transform: translate(-50%, -50%);      box-shadow: 1px 1px 10px #fff;      text-shadow: 0px 1px 30px white;      display: flex;      justify-content: space-around;      align-items: center;      font-size: 70px;      user-select: none;      padding: 0 20px;      -webkit-box-reflect: below 0px -webkit-gradient(linear, left top, left bottom, from(transparent), color-stop(0%, transparent), to(rgba(250, 250, 250, .2)));    }  </style></head><body>  <div class="box">    <div id="HH">00</div>    <div>:</div>    <div id="mm">00</div>    <div>:</div>    <div id="ss">00</div>  </div></body></html><script>window.addEventListener('load', function () {    clock();  setInterval(clock, 1000);});function clock() {    let dt = new Date();  let HH = dt.getHours();  let mm = dt.getMinutes();  let ss = dt.getSeconds();  console.log(dt, HH, mm, ss);  document.querySelector('#HH').innerHTML = padZero(HH);  document.querySelector('#mm').innerHTML = padZero(mm);  document.querySelector('#ss').innerHTML = padZero(ss);};function padZero(n) {    return n > 9 ? n : '0' + n;}</script>
/*** 目标:编写 web 服务,监听请求的是 /index.html 路径的时候,返回 dist/index.html 时钟案例页面内容* 步骤:*  1. 基于 http 模块,创建 Web 服务*  2. 使用 req.url 获取请求资源路径,并读取 index.html 里字符串内容返回给请求方*  3. 其他路径,暂时返回不存在提示*  4. 运行 Web 服务,用浏览器发起请求*/
const fs = require('fs')
const path = require('path')
// 1. 基于 http 模块,创建 Web 服务
const http = require('http')
const server = http.createServer()
server.on('request', (req, res) => {// 2. 使用 req.url 获取请求资源路径,并读取 index.html 里字符串内容返回给请求方if (req.url === '/index.html') {fs.readFile(path.join(__dirname, 'dist/index.html'), (err, data) => {res.setHeader('Content-Type', 'text/html;charset=utf-8')res.end(data.toString())})} else {// 3. 其他路径,暂时返回不存在提示res.setHeader('Content-Type', 'text/html;charset=utf-8')res.end('你要访问的资源路径不存在')}
})
server.listen(8080, () => {console.log('Web 服务启动了')
})

今日作业(必完成)

tlias上发布

知识回顾

  1. node基本概念
    1. node是什么?-> node是一个执行js的环境
    2. node和浏览器有和相同点以及区别?
      1. 相同点:① node和浏览器都支持ECMAScript的标准语法 ② 都是V8引擎来解析js的
      2. 不同点:① node不支持DOM和BOM操作的 ② node本身提供的fs,path,http,request等这些模块浏览器是没有的
    1. node给前端做了哪些赋能?
      1. 可以让前端工程师做后端接口的开发(可以操作数据库,并且可以开启服务器 -> Web服务)
      2. 工程化(将来可以开发大型项目,让代码有良好的组织结构,维护很方便)
  1. 如何安装和配置node环境(提示)
    1. nvm来管理多个node版本之间的切换的
    2. 直接下载node安装包,双击安装
    3. 在开发目录中执行npm install @types/node 就能具备node环境的提示功能
  1. 内置模块
    1. 引入一个node模块使用的关键字 require()
    2. fs -> 读写文件
      1. fs.readFile (异步方法)
      2. fs.writeFile (异步方法)
    1. path -> join()方法主要是用来拼接绝对路径
      1. __dirname -> 获取当前js文件所在的绝对路径
  1. http模块
    1. 基本网络知识
      1. 域名(IP)
      2. 端口
        1. 作用:是操作系统用来对外通讯的,需要我们编写web服务来监听这个端口,从而实现对外通讯
        2. 范围: 0 - 65535 ,总端口是是65536个
      1. 资源路径
      2. 查询参数
      3. http协议
        1. http请求协议 (约束客户端通过什么数据格式向服务器发送数据)
          1. 请求行
          2. 请求头
          3. 空白行
          4. 请求体
        1. http响应协议(约束服务器向客户端发送什么数据)
          1. 响应行
          2. 响应头 Content-Type -> 作用:告诉浏览器通过什么格式来解析我发给你的数据
            1. text/html
            2. application/json
          1. 空白行
          2. 响应体
    1. http模块的相关代码
      1. 开启一个web服务的核心步骤
const http = require('http')
const server = http.createServer()
server.on('request',(req,res)=>{
// 1. 如何向响应体中增加数据并结束响应res.end('响应体的数据')// 2. 如何设置响应头//key:  Content-Type// value: text/html    application/json// 告诉浏览器解析utf8格式的字符,需要使用 charset=utf-8res.setHeader('key','value')})server.listen(端口,()=>{// 成功开启web服务以后会自动执行这个回调函数
})

相关文章:

Node.js入门

Node.js入门 html,css,js 30年了 nodejs环境 09年出现 15年 nodejs为我们解决了2个方面的问题&#xff1a; 【锦上添花】让我们前端工程师拥有了后端开发能力&#xff08;开接口&#xff0c;访问数据库&#xff09; - 大公司BFF&#xff08;50&#xff09;【✔️】前端工程…...

使用CubeMX新建EXTI外部中断工程——不使用回调函数

具体的使用CubeMX新建工程的步骤看这里&#xff1a;STM32CubeMX学习笔记&#xff08;3&#xff09;——EXTI(外部中断)接口使用_cubemx exti-CSDN博客 之前一直都是在看野火的视频没有亲手使用CubeMX生成工程&#xff0c;而且野火给的例程代码框架和自动生成的框架也不一样&…...

Verilog的整数除法

1、可变系数除法实现----利用除法的本质 timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 2025/04/15 13:45:39 // Design Name: // Module Name: divide_1 // Project Name: // Target Devices: // Tool Versions: // Description: // // Depe…...

win32汇编环境,网络编程入门之十九

;win32汇编环境,网络编程入门之十九 ;在这一编程里&#xff0c;我们学习一下如何使用gethostbyname函数&#xff0c;也顺便学一下如何将C定义的函数在WIN32汇编环境中使用 ;先看一下官方解释&#xff1a;从主机数据库中检索与主机名对应的主机信息。 ;它的原理是从你的电脑DNS中…...

Java学习手册:Java线程安全与同步机制

在Java并发编程中&#xff0c;线程安全和同步机制是确保程序正确性和数据一致性的关键。当多个线程同时访问共享资源时&#xff0c;如果不加以控制&#xff0c;可能会导致数据不一致、竞态条件等问题。本文将深入探讨Java中的线程安全问题以及解决这些问题的同步机制。 线程安…...

在生信分析中,从生物学数据库中下载的序列存放在哪里?要不要建立一个小型数据库,或者存放在Gitee上?

李升伟 整理 在Galaxy平台中使用时&#xff0c;从NCBI等生物学数据库下载的DNA序列的存储位置和管理方式需要根据具体的工作流程和需求进行调整。以下是详细的分步说明和建议&#xff1a; 一、Galaxy中DNA序列的默认存储位置 在Galaxy的“历史记录”&#xff08;History&…...

Python异步编程入门:Async/Await实战详解

引言 在当今高并发的应用场景下&#xff0c;传统的同步编程模式逐渐暴露出性能瓶颈。Python通过asyncio模块和async/await语法为开发者提供了原生的异步编程支持。本文将手把手带你理解异步编程的核心概念&#xff0c;并通过实际代码案例演示如何用异步爬虫提升10倍效率&#…...

cmd 终端输出乱码问题 |Visual Studio 控制台输出中文乱码解决

在网上下载&#xff0c;或者移植别人的代码到自己的电脑&#xff0c;使用VS运行后&#xff0c;控制台输出中文可能出现乱码。这是因为源代码的编码格式和控制台的编码格式不一致。 文章目录 查看源代码文件编码格式查看输出控制台编码格式修改编码格式修改终端代码页 补充总结 …...

【算法】椭圆曲线签名(ECDSA)

&#x1f914;什么是椭圆曲线签名&#xff08;ECDSA&#xff09;&#xff1f; 椭圆曲线签名算法&#xff08;Elliptic Curve Digital Signature Algorithm&#xff0c;简称 ECDSA&#xff09;是一种基于 椭圆曲线密码学 的数字签名算法。它主要用于加密货币&#xff08;如 Bit…...

Linux下使用MTK的SP_Flash_tool刷机工具

MTK的SP_Flash_tool刷机工具安装流程如下&#xff1a; 1、解压SP_Flash_Tool_Linux_v5.1336.00.100_Customer.zip unzip SP_Flash_Tool_exe_Linux_64Bit_v5.1520.00.100.zip 2、首先安装 libusb-dev 这个包&#xff1a; sudo apt-get install libusb-dev 3、安装成功之后…...

FRP内网穿透代理两个web页面(多端口内网穿透)

内网机器代理两个web页面出来 下载frp 选择0.51.2版本下载&#xff0c;高版本测试为成功 frp下载地址 部署frp server端&#xff08;公网部署&#xff09; #上传到opt rootsdgs-server07:/opt# ll frp_0.51.2_linux_amd64.tar.gz -rw-r--r-- 1 root root 11981480 Apr 15 1…...

Jenkins插件下载慢解决办法

jenkins设置插件使用国内镜像_jenkins 国内镜像-CSDN博客 国内源 以下是一些常用的国内 Jenkins 插件更新源地址&#xff1a; 清华大学&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json华为开源镜像站&#xff1a;https://mirrors.huawei…...

【Unity笔记】Unity开发笔记:ScriptableObject实现高效游戏配置管理(含源码解析)

在Unity开发中&#xff0c;高效管理游戏配置数据是提升开发效率的关键。本文分享如何使用ScriptableObject构建可编辑的键值对存储系统&#xff0c;并实现运行时动态读取。 一、为什么选择ScriptableObject&#xff1f; 1.1 ScriptableObject的核心优势 独立资源&#xff1a;…...

FPAG IP核调用小练习

一、调用步骤 1、打开Quartus 右上角搜索ROM&#xff0c;如图所示 2、点击后会弹出如图所示 其中文件路径需要选择你自己的 3、点击OK弹出如图所示 图中红色改为12与1024 4、然后一直点NEXT&#xff0c;直到下图 这里要选择后缀为 .mif的文件 5、用C语言生成 .mif文件 //…...

vue动画

1、动画实现 &#xff08;1&#xff09;、操作css的transition或animation &#xff08;2&#xff09;、在插入、更新或移除DOM元素时&#xff0c;在合适的时候给元素添加样式类名 &#xff08;3&#xff09;、过渡的相关类名&#xff1a; xxx-enter-active: 进入的时候激活…...

大数据学习(106)-hivesql函数

&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一…...

AI日报 - 2025年04月16日

&#x1f31f; 今日概览(60秒速览) ▎&#x1f916; 模型井喷 | OpenAI (o3/o4-mini, GPT-4.1), Meta (Llama 4 Scout/Maverick), Z.ai (GLM-4家族), Cohere (Embed 4), Google (DolphinGemma) 等发布新模型&#xff0c;多模态、长文本、高效推理成焦点。 ▎&#x1f4bc; 商业…...

C# 经纬度坐标的精度及WGS84(谷歌)、GCJ02(高德)、BD09(百度)坐标相互转换(含高精度转换)

1. 概述 WGS-84坐标系&#xff08;World Geodetic System一1984 Coordinate System&#xff09;是一种国际上采用的地心坐标系&#xff0c;GCJ-02是由中国国家测绘局&#xff08;G表示Guojia国家&#xff0c;C表示Cehui测绘&#xff0c;J表示Ju局&#xff09;制订的地理信息系…...

案例:陌陌聊天数据分析

背景分析&#xff1a; 陌陌作为聊天平台每天都会有大量的用户在线&#xff0c;会出现大量的聊天数据&#xff0c;通过对 聊天数据的统计分析 &#xff0c;可以更好的 对用户构建精准的 用户画像 &#xff0c;为用户提供更好的服务以及实现 高 ROI 的平台运营推广&#xff…...

关闭谷歌浏览器(Google Chrome)的自动更新可以通过以下方法实现。具体操作步骤取决于你的操作系统。

关闭谷歌浏览器&#xff08;Google Chrome&#xff09;的自动更新可以通过以下方法实现。具体操作步骤取决于你的操作系统。 1. 在 Windows 上关闭 Chrome 自动更新2. 在 macOS 上关闭 Chrome 自动更新3. 在 Linux 上关闭 Chrome 自动更新4. 注意事项1. 在 Windows 上关闭 Chro…...

进程(完)

今天我们就补充一个小的知识点,查看进程树命令,来结束我们对linux进程的学习,那么话不多说,来看. 查看进程树 pstree 基本语法&#xff1a; pstree [选项] 优点&#xff1a;可以更加直观的来查看进程信息 常用选项&#xff1a; -p&#xff1a;显示进程的pid -u&#xff…...

(劳特巴赫调试器学习笔记)四、Practice脚本.cmm文件编写

Lauterbach调试器 文章目录 Lauterbach调试器一、什么是Practice脚本文件二、cmm脚本使用示例总结 一、什么是Practice脚本文件 官方文档解释&#xff1a; 因为Practice脚本以cmm为后缀&#xff0c;所以大多数人叫它cmm脚本。 以tricore为例&#xff0c;在安装目录下&#xff…...

并行流parallelStream.map().collect()

一、使用场景 先贴代码 public static void main(String[] args) {List<String> stringList new ArrayList<>();List<Integer> integerList new ArrayList<>();int num 10000;for (int i 0;i<num;i){stringList.add(String.valueOf(i));}stri…...

2025最新版flink2.0.0安装教程(保姆级)

Flink支持多种安装模式。 local&#xff08;本地&#xff09;——本地模式 standalone——独立模式&#xff0c;Flink自带集群&#xff0c;开发测试环境使用 standaloneHA—独立集群高可用模式&#xff0c;Flink自带集群&#xff0c;开发测试环境使用 yarn——计算资源统一…...

软件测试小讲

​ 大家好&#xff0c;我是程序员小羊&#xff01; 前言&#xff1a; 在 Web 项目开发中&#xff0c;全面的测试是保证系统稳定性、功能完整性和良好用户体验的关键。下面是一个详细的 Web 项目测试点列表&#xff0c;涵盖了不同方面的测试&#xff1a; 1. 功能测试 确保应用…...

DP35 【模板】二维前缀和 ---- 前缀和

目录 一&#xff1a;题目 二&#xff1a;算法原理 三&#xff1a;代码实现 一&#xff1a;题目 题目链接&#xff1a;【模板】二维前缀和_牛客题霸_牛客网 二&#xff1a;算法原理 三&#xff1a;代码实现 #include <iostream> #include <vector> using name…...

C语言——分支语句

在现实生活中&#xff0c;我们经常会遇到作出选择和判断的时候&#xff0c;在C语言中也同样要面临作出选择和判断的时候&#xff0c;所以今天&#xff0c;就让我们一起来了解一下&#xff0c;C语言是如何作出选择判断的。 目录 1.何为语句&#xff1f; 2.if语句 2.1 if语句的…...

使用Docker安装Jenkins

1、准备 2、安装 详见&#xff1a; https://www.jenkins.io/doc/book/installing/ https://www.jenkins.io/zh/doc/book/installing/ https://www.jenkins-zh.cn/tutorial/get-started/install/ # 方式1&#xff1a; # 详见&#xff1a;https://www.jenkins.io/doc/book/inst…...

东方博宜OJ ——2395 - 部分背包问题

贪心入门 ————2395 - 部分背包问题 2395 - 部分背包问题题目描述输入输出样例问题分析贪心算法思路代码实现总结 2395 - 部分背包问题 题目描述 阿里巴巴走进了装满宝藏的藏宝洞。藏宝洞里面有 N (N < 100)堆金币&#xff0c;第i堆金币的总重量和总价值分别是mi,vi (l …...

【期中准备特辑】计组,电路,信号

计组 以点带面地复习书中内容&#xff01; 指令体系结构&#xff08;ISA&#xff09;是计算机硬件和软件的分界面 世界上第一台电子计算机是 ENIAC&#xff08;埃尼阿克&#xff09; 第一代计算机采用电子管作为主要器件&#xff1b;第二代计算机采用晶体管&#xff1b;第三代…...

经典算法 判断一个图是不是树

判断一个图是不是树 问题描述 给一个以0 0结尾的整数对列表&#xff0c;除0 0外的每两个整数表示一条连接了这两个节点的边。假设节点编号不超过100000大于0。你只要判断由这些节点和边构成的图是不是树。是输出YES&#xff0c;不是输出NO。 输入样例1 6 8 5 3 5 2 6 4 5…...

力扣 283 移动零的两种高效解法详解

目录 方法一&#xff1a;两次遍历法 方法二&#xff1a;单次遍历交换法 两种方法对比 在解决数组中的零移动到末尾的问题时&#xff0c;我们需要保持非零元素的顺序&#xff0c;并原地修改数组。以下是两种高效的解法及其详细分析。 方法一&#xff1a;两次遍历法 思路分析…...

代码随想录第18天:二叉树

一、修剪二叉树&#xff08;Leetcode 669&#xff09; 递归法 class Solution:def trimBST(self, root: TreeNode, low: int, high: int) -> TreeNode:# 如果当前节点为空&#xff0c;直接返回空节点&#xff08;递归终止条件&#xff09;if root is None:return None# 如果…...

KMP算法核心笔记:前后缀本质与nextval实现

KMP算法核心笔记&#xff1a;前后缀本质与nextval实现 核心疑问&#xff1a;为什么用「前后缀」而非「最大子串」&#xff1f; 1. 结构唯一性 前后缀限定在字符串首尾区域&#xff0c;最大子串可位于任意位置只有前后缀能保证滑动后的有效对齐 2. 移动确定性 文本&#xf…...

Breeze 40A FOC 电调:Vfast 观测器技术赋能无人机精准动力控制

核心技术特性 1. 全新Vfast 观测器技术 基于先进矢量控制算法&#xff08;FOC 驱动&#xff09;&#xff0c;实现电机状态实时精准观测&#xff0c;适配性优于传统 FOC 方案&#xff0c;兼容主流无人机动力配置。高效算法设计&#xff0c;输出功率与力效超越多数方波电调&…...

如何处理ONLYOFFICE文档服务器与Java Web应用间的安全认证和授权

如何处理ONLYOFFICE文档服务器与Java Web应用间的安全认证和授权&#xff1f; 处理 ONLYOFFICE 文档服务器与 Java Web 应用之间的安全认证和授权&#xff0c;通常涉及以下几个关键步骤和技术&#xff1a; 1. JWT (JSON Web Token) 认证 启用 JWT&#xff1a; ONLYOFFICE 文档…...

手机上的PDF精简版:随时随地享受阅读

在移动互联网时代&#xff0c;随时随地阅读电子书和文档已经成为许多人的习惯。无论是学习、工作还是娱乐&#xff0c;一款好用的PDF阅读器都是必不可少的工具。今天&#xff0c;我们要介绍的 思读PDF精简版&#xff0c;就是这样一款简洁而强大的PDF阅读工具&#xff0c;能够让…...

XCTF-web(一)

view_source F12ctrluctrlshiftiURL前添加&#xff1a;view-source:curl http://192.168.1.1robots 根据题目提示&#xff0c;查看一下robots.txt /flag_ls_h3re.php backup /index.php.bak ┌──(kali㉿kali)-[~] └─$ cat index.php.bak <html> <…...

字节跳动开源 Godel-Rescheduler:适用于云原生系统的全局最优重调度框架

背景 在云原生调度中&#xff0c;一次调度往往无法解决所有问题&#xff0c;需要配合重调度来优化资源分配和任务摆放。传统的重调度框架主要集中在识别异常节点或任务&#xff0c;并通过迁移或删除来解决。然而&#xff0c;这些框架往往只能解决局部问题&#xff0c;无法提供…...

贪心算法day9(合并区间)

1.合并区间 56. 合并区间 - 力扣&#xff08;LeetCode&#xff09; 对于这种区间问题&#xff0c;我们应该先排序根据排序的结果总结一些规律&#xff0c;进而的得出解决该问题的策略。 class Solution {public static int[][] merge(int[][] intervals) {//第一步进行左端点…...

插件化设计,打造个性化音乐体验!

打工人们你们好&#xff01;这里是摸鱼 特供版~ 今天给大家带来一款超酷的音乐播放器——MusicFree&#xff0c;它不仅功能强大&#xff0c;还支持插件化设计&#xff0c;让你的音乐体验更加个性化&#xff01; 推荐指数&#xff1a;★★★★★ 1. 插件化设计 功能强大&#…...

深入解析分类模型评估指标:ROC曲线、AUC值、F1分数与分类报告

标题&#xff1a;深入解析分类模型评估指标&#xff1a;ROC曲线、AUC值、F1分数与分类报告 摘要&#xff1a; 在机器学习中&#xff0c;评估分类模型的性能是至关重要的一步。本文详细介绍了四个核心评估指标&#xff1a;ROC曲线、AUC值、F1分数和分类报告。通过对比这些指标…...

2025第16届蓝桥杯省赛之研究生组F题01串求解

2025第16届蓝桥杯省赛之研究生组F题01串求解 一、题目概述二、解题思路2.1题目分析2.2解题思路 三、求解代码3.1求解步骤3.1.1求解x所在的二进制位数区间3.1.2求解总位数为cnt的含1数3.1.3求解cnt1~x之间的含1数 3.2完整代码3.3代码验证 四、小结 一、题目概述 给定一个由0,1,…...

【2-10】E1与T1

前言 之前我们简单介绍了人类从电话线思维到如今的数据报分组交换思维过渡时期的各种技术产物&#xff0c;今天我们重点介绍 E1/T1技术。 文章目录 前言1. 产生背景2. T13. E14. SONET4.1 OC-14.2 OC-3 及其它 5. SDH5.1. STM-1 6. SONET VS SDH后记修改记录 1. 产生背景 E1/…...

2025 年蓝桥杯 Java B 组真题解析分享

今年是我第二次参加蓝桥杯软件类Java B组的比赛&#xff0c;虽然赛前做了不少准备&#xff0c;但真正坐在考场上时&#xff0c;还是有种熟悉又紧张的感觉。蓝桥杯的题目一向以“基础创新”著称&#xff0c;今年也不例外&#xff0c;每道题都考验着我们对算法的理解、代码实现能…...

IMX6ULL2025年最新部署方案2在Ubuntu24.04上编译通过Qt5.12.9且部署到IMX6ULL正点原子开发板上

IMX6ULL2025年最新部署方案2:在Ubuntu24.04上编译通过Qt5.12.9且部署到IMX6ULL正点原子开发板上 前言 ​ 本篇方案部署是笔者这几天除了打蓝桥杯以外&#xff0c;笔者在研究的东西&#xff0c;现在写道这里的时候&#xff0c;笔者已经成功的在Ubuntu24.04上&#xff0c;使用默…...

通过微信APPID获取小程序名称

进入微信公众平台&#xff0c;登录自己的小程序后台管理端&#xff0c;在“账号设置”中找到“第三方设置” 在“第三方设置”页面中&#xff0c;将页面拉到最下面&#xff0c;即可通过appid获取到这个小程序的名称信息...

混合开发部署实战:PyInstaller + .NET 8 + Docker全链路配置

文章目录 一、PyInstaller打包Python环境1. 基础打包&#xff08;Linux环境&#xff09;2. 高级配置3. 验证打包结果 二、.NET 8与Python的集成模式1. 进程调用&#xff08;推荐方案&#xff09;2. REST API通信 三、Docker多阶段构建配置1. 完整Dockerfile示例2. 关键配置解析…...

使用 Sass 打造动态星空背景效果

在前端开发中&#xff0c;视觉效果越来越受到重视。本文将通过一个生动的示例&#xff0c;讲解如何利用 Sass 构建一个具有动态星空滚动效果的背景页面&#xff0c;同时也系统介绍 Sass 的核心功能与实践技巧。 一、Sass 的作用 Sass&#xff08;Syntactically Awesome Style …...

低空经济有哪些GIS相关岗位?

在低空经济中&#xff0c;GIS&#xff08;地理信息系统&#xff09;技术发挥着重要作用。GIS开发工程师负责开发、维护和优化与低空经济相关的GIS系统&#xff0c;如无人机起降场布局、空域管理、气象监测等。一般会参与二、三维GIS项目数据处理与前端开发&#xff0c;以及相关…...