关于使用天地图、leaflet、ENVI、Vue工具实现 前端地图上覆盖上处理的农业地块图层任务
1.项目框架搭建
项目地址:Webgis: 一个关于webgis、天地图、Leaflet、Vue、数据库的学习框架。
①git到本地,vscode打开。
② 配置后端
搜索下载MySQL插件(前提:电脑中装有MySQL才可应用)。
连接数据库。
配置基本信息(如:ip、port、账号、密码)。
保存,连接(如下图:连接成功)。
下图:
1.api:定义接口,启动数据库服务。
2.config:数据库配置文件。
3.models:数据库遥感数据表。
首先配置连接信息(如)。
创建conda环境,再安装必要依赖。
点击运行,创建表,提示连接成功。
③配置遥感图层处理脚本
配置环境(其中 osgeo比较麻烦,单独给出),修改文件路径,运行脚本。
conda install -c conda-forge gdal
参考:osgeo python安装入门实例_osgeo库安装-CSDN博客
配置读取路径(个人问题),点击运行脚本。
遥感处理文件夹下生成out_geotiff文件夹、前端的public下也生成out_geotiff文件夹。
脚本具体实现,看后续...
④配置前端
配置环境,安装必要依赖(不是conda环境)。
运行(npm run serve),看到前端页面。
2.项目框架代码学习
①前端
导入基本地图
<template><div id="baseMap" style="height: 100vh; width: 100%; "></div>
</template><script>
//地图
import { onMounted, ref } from "vue";
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import 'leaflet.chinatmsproviders';
import 'leaflet-geotiff';
import '@/utils/leaflet-geotiff-plotty.js';export default {setup() {// 地图初始化const MapKey = "4be8e59596e4cee92183d2a61d77ce0c";// const MapKey = "d70045af77b5a8c2fac6a69b80ffdd7a";const map = ref(null);const layerVisibility = ref([false, false, false]);const allLayers = ref([]); // 存储所有加载的遥感图层const layerGroup = ref(L.layerGroup()).value; // 使用 layerGroup 管理图层onMounted(() => {// 初始化地图map.value = L.map("baseMap", {center: L.latLng(45.757000, 126.642000),//哈尔滨// center: L.latLng(45.75075431739313, 127.5517068330741),//宾县//center: L.latLng(46.05075431739313,126.8517068330741),//呼兰区//center: L.latLng(55.23545507478532, 10.106575515900523),//田块分割//center: L.latLng(29.676840, -95.369222),zoom: 8,zoomControl: true,attributionControl: false,});// 加载天地图基础图层let satelliteTileLayer = L.layerGroup([L.tileLayer.chinaProvider('TianDiTu.Satellite.Map', { key: MapKey }),L.tileLayer.chinaProvider('TianDiTu.Satellite.Annotion', { key: MapKey })]);// 加载遥感图层satelliteTileLayer.addTo(map.value);layerGroup.addTo(map.value); // 将 layerGroup 添加到地图});return {map,layerGroup,layerVisibility, // 添加到返回对象中allLayers,};}
};
</script>
测试页面:
测试代码:
<template><div class="container"><div><h1>WebGIS Test</h1></div><div style="margin-bottom: 20px;"><!-- 农田遥感指数图层选择框 --><el-col :span="3.5" v-for="type in ['NDVI', 'WET', 'NDBSI']" :key="type"><el-button style="width: 130px;" @click="toggleLayer(type, 'qixingnongchang')">{{ type }}</el-button></el-col><!-- 隐藏所有图层 --><el-col :span="2.5"><el-button style="width: 120px;" @click="hideAllLayers">隐藏所有图层</el-button></el-col></div><div id="baseMap" style="height: 500px; width: 50%; "></div></div>
</template><script>
import { onMounted, ref } from "vue";
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import 'leaflet.chinatmsproviders';
import 'leaflet-geotiff';
import '@/assets/leaflet-geotiff-plotty.js';
import axios from "axios";
export default {data() {return {activeName: 'third',currentTime: '',data: [], // 用于存储从 API 获取的返回遥感数据activeLayers: [],};},methods: {// 根据 activeName 获取对应日期getDateByActiveName() {const dateMap = {first: "2024-05-03",second: "2024-06-04",third: "2024-07-14",fourth: "2024-08-31",fifth: "2024-09-24",sixth: "2024-10-26",};console.log("1.获取对应日期", dateMap[this.activeName]);return dateMap[this.activeName] || null;},//展示图层async toggleLayer(type, FieldName) {//layerKey:图层名称console.log("type:", type, "FieldName:", FieldName);const layerKey = `${this.getDateByActiveName()}_${type}_${FieldName}`; // 使用 date、type 和 FieldName 组合作为唯一标识console.log("2.layerKey: ", layerKey)// 如果图层已经显示,则隐藏,否则加载并显示if (this.layerVisibility[layerKey]) {console.log('3.隐藏图层:', layerKey);this.hideLayer(layerKey); // 隐藏图层} else {console.log('3.显示图层:', layerKey);// 将当前激活的图层标识符 layerKey 添加到 activeLayers 数组中。this.activeLayers.push(layerKey); // 将图层标记为活跃/*** await 是用于等待一个 Promise 对象完成的关键字。它只能在 async 函数内部使用。当执行到这一行代码时,程序会暂停执行,直到 fetchData 函数执行完成并返回结果。* fetchData 是一个异步函数,其主要功能是向服务器发送请求以获取遥感数据,并将这些数据加载为 GeoTIFF 图层以在地图上进行显示。*/await this.fetchData(type, FieldName); // 加载并显示图层}},/*** * @param type 遥感指数类型* @param FieldName * 首先获取当前的日期,然后使用 Axios 库向指定的 API 发送一个 POST 请求,包含必要的过滤条件(例如日期、类型和字段名)。* 通过 API 返回的数据将被处理,并转换为地图可显示的图层。* 图层加载完成后,将图层添加到 layerGroup 中,并设置图层可见性。*/async fetchData(type, FieldName) {const date1 = this.getDateByActiveName();console.log("4.对应日期为:", date1);const filters = { Date: date1, type: type, FieldName: FieldName, };try {// 通过向指定的 API 发送 POST 请求来获取遥感数据。const response = await axios.post('http://127.0.0.1:5002/api/remote_sensing', filters);// 将 API 返回的数据存储在 data 数组中this.data = response.data;console.log('5.Data fetched:', response.data);// 遍历数据并加载为 GeoTIFF 图层/*** 1遍历数据数组:this.data.forEach((layerData) => { 使用forEach方法遍历this.data数组。this.data包含从API获取的遥感数据,而layerData是当前遍历到的每一个数据项。* * 2遍历每一项数据,获取其FileNameUrl、SouthWestLatitude、SouthWestLongitude、NorthEastLatitude、NorthEastLongitude、Max、Min等属性。* FileNameUrl: GeoTIFF文件的URL地址,用于加载图层。* Max和Min: 用于显示图层数据的最小值和最大值。* * 3定义边界坐标:创建一个bounds数组来定义图层的地理范围。其中,西南角和东北角的经纬度分别被转换为浮点数(使用parseFloat),以确保它们是数值型数据。这是重要的一步,因为地图需要准确的地理坐标来渲染。*/this.data.forEach((layerData) => {const { FileNameUrl, SouthWestLatitude, SouthWestLongitude, NorthEastLatitude, NorthEastLongitude, Max, Min } = layerData;const bounds = [[parseFloat(SouthWestLatitude), parseFloat(SouthWestLongitude)],[parseFloat(NorthEastLatitude), parseFloat(NorthEastLongitude)],];/*** bounds 属性指定了图层的地理范围,即这个图层在地图上显示的区域。* renderer 属性指定了图层的渲染方式。这里使用了 plotty 渲染器,它可以将遥感数据转换为可视化的图像。* L.LeafletGeotiff.plotty 是一个 Leaflet 插件,用于将 GeoTIFF 数据转换为可视化的图层。* options 对象包含了图层的边界、渲染器和透明度。* opacity 属性指定了图层的透明度。*/const options = {bounds: bounds,renderer: L.LeafletGeotiff.plotty({displayMin: parseFloat(Min),displayMax: parseFloat(Max),colorScale: "viridis",noDataValue: -1,}),opacity: 1,};/*** 1创建 GeoTIFF 图层:使用 L.leafletGeotiff 方法创建了一个 GeoTIFF 图层。FileNameUrl 是图层数据的 URL(指向一个 GeoTIFF 文件),而 options 是一个配置对象,包含了边界、渲染器和透明度等信息。* 2将图层添加到 layerGroup 中:使用 addLayer 方法将图层添加到 layerGroup 中。* 3allLayers 数组: 存储图层和类型:将图层和类型存储在 allLayers 数组中。* 4设置图层可见性:将图层的可见性设置为 true。*/// 创建 GeoTIFF 图层const geoTiffLayer = L.leafletGeotiff(FileNameUrl, options);console.log('6.FileNameUrl:', FileNameUrl, 'bounds:', bounds, 'options:', options);console.log('6.geoTiffLayer:', geoTiffLayer);this.layerGroup.addLayer(geoTiffLayer); // 添加图层到 layerGroupconsole.log('6.layerGroup:', this.layerGroup);const layerKey = `${this.getDateByActiveName()}_${type}_${FieldName}`; // 使用 date0、type 和 number 组合作为唯一标识this.allLayers.push({ layer: geoTiffLayer, type: layerKey }); // 存储图层和类型console.log('6.allLayers:', this.allLayers);this.layerVisibility[type] = true;/*** Q:为什么FileNameUrl是 output_geotiff\20240714_RemoteSensingIndex\20240714_qixingnongchang_NDVI_geotiff.tif,但是可以访问到public文件夹?* A:因为FileNameUrl是API返回的路径,而public文件夹是后端服务的静态资源目录,两者是两个不同的概念。API返回的路径是相对于后端服务的,而public文件夹是相对于前端页面的。因此,当API返回的路径指向public文件夹中的文件时,前端页面可以通过该路径访问到该文件。* 后端返回数据:* result* [{'id': 23, 'Createtime': '2024-11-27 11:10:02', *'FileName': '20240714_qixingnongchang_NDVI_geotiff.tif', *'FileNameUrl': 'output_geotiff\\20240714_RemoteSensingIndex\\20240714_qixingnongchang_NDVI_geotiff.tif', *'type': 'NDVI', 'SouthWestLatitude': 47.0486, 'SouthWestLongitude': 132.631, 'NorthEastLatitude': 47.2315, 'NorthEastLongitude': 133.183, 'Max': 0.908199, 'Min': 0.000760456, 'Mean': 0.738675, 'Date': '2024-07-14', 'FieldName': 'qixingnongchang'}] * * 前端页面访问路径:http://127.0.0.1:5000/public/output_geotiff/20240714_RemoteSensingIndex/20240714_qixingnongchang_NDVI_geotiff.tif*//*** 设置中心点和缩放级别:使用 setView 方法设置中心点和缩放级别。这里使用了经纬度和缩放级别的平均值来设置中心点和缩放级别。* 这里的经纬度和缩放级别的计算方法是:* 1. 计算中心点的经纬度:使用 SouthWestLatitude、SouthWestLongitude、NorthEastLatitude、NorthEastLongitude 四个属性的平均值来计算中心点的经纬度。* 2. 计算缩放级别:根据中心点的经纬度和边界坐标的距离来计算缩放级别。如果边界坐标的距离小于 0.1 公里,则使用 11 级,否则使用 13 级。*/const x = (parseFloat(SouthWestLatitude) + parseFloat(NorthEastLatitude)) / 2;const y = (parseFloat(SouthWestLongitude) + parseFloat(NorthEastLongitude)) / 2;const z = (parseFloat(NorthEastLatitude) - parseFloat(SouthWestLatitude));this.map.setView(L.latLng(x, y), z > 0.1 ? 11 : 13);console.log(`时期:${date1},显示图层: ${type},名称:${FieldName}`);this.layerVisibility[layerKey] = true; // 更新图层可见状态});} catch (error) {console.error('Error fetching data:', error);}},// 隐藏图层hideLayer(layerKey) {//const layerKey = `${this.getDateByActiveName()}_${type}_${FieldName}`; // 使用 date0、type 和 number 组合作为唯一标识// 遍历 allLayers 数组,找到匹配的图层并隐藏this.allLayers = this.allLayers.filter(({ layer, type: layerType }) => {console.log(layerKey)// 如果图层类型和 layerKey 匹配,则隐藏图层并返回 false,否则返回 trueif (layerType === layerKey) {this.layerGroup.removeLayer(layer);this.layerVisibility[layerKey] = false;return false;}return true;});},// 隐藏所有图层hideAllLayers() {// 遍历 allLayers 数组,隐藏所有图层this.allLayers.forEach(({ layer }) => {// 隐藏每个图层:this.layerGroup.removeLayer(layer);});this.allLayers = [];Object.keys(this.layerVisibility).forEach((key) => {this.layerVisibility[key] = false;});console.log("已隐藏所有图层");},},setup() {// 地图初始化// const MapKey = "4be8e59596e4cee92183d2a61d77ce0c";const MapKey = "d70045af77b5a8c2fac6a69b80ffdd7a";const map = ref(null);const layerVisibility = ref([false, false, false]);const allLayers = ref([]); // 存储所有加载的遥感图层const layerGroup = ref(L.layerGroup()).value; // 使用 layerGroup 管理图层onMounted(() => {// 初始化地图map.value = L.map("baseMap", {center: L.latLng(45.757000, 126.642000),//哈尔滨// center: L.latLng(45.75075431739313, 127.5517068330741),//宾县//center: L.latLng(46.05075431739313,126.8517068330741),//呼兰区//center: L.latLng(55.23545507478532, 10.106575515900523),//田块分割//center: L.latLng(29.676840, -95.369222),zoom: 8,zoomControl: true,attributionControl: false,});// 加载天地图基础图层let satelliteTileLayer = L.layerGroup([L.tileLayer.chinaProvider('TianDiTu.Satellite.Map', { key: MapKey }),L.tileLayer.chinaProvider('TianDiTu.Satellite.Annotion', { key: MapKey })]);// 加载遥感图层satelliteTileLayer.addTo(map.value);layerGroup.addTo(map.value); // 将 layerGroup 添加到地图});return {map,layerGroup,layerVisibility, // 添加到返回对象中allLayers,};}
};
</script><style scoped>
.container {display: flex;flex-direction: column;/* 垂直布局 */justify-content: center;/* 垂直居中 */align-items: center;/* 水平居中 */height: 100vh;/* 使容器占满整个视口高度 */
}
</style>
②遥感图处理脚本
相关文章:

关于使用天地图、leaflet、ENVI、Vue工具实现 前端地图上覆盖上处理的农业地块图层任务
1.项目框架搭建 项目地址:Webgis: 一个关于webgis、天地图、Leaflet、Vue、数据库的学习框架。 ①git到本地,vscode打开。 ② 配置后端 搜索下载MySQL插件(前提:电脑中装有MySQL才可应用)。 连接数据库。 配置基本…...

基于yolov4深度学习网络的排队人数统计系统matlab仿真,带GUI界面
目录 1.算法仿真效果 2.算法涉及理论知识概要 3.MATLAB核心程序 4.完整算法代码文件获得 1.算法仿真效果 matlab2022a仿真结果如下(完整代码运行后无水印): 仿真操作步骤可参考程序配套的操作视频。 2.算法涉及理论知识概要 在现代社会…...

用 React 编写一个笔记应用程序
这篇文章会教大家用 React 编写一个笔记应用程序。用户可以创建、编辑、和切换 Markdown 笔记。 1. nanoid nanoid 是一个轻量级和安全的唯一字符串ID生成器,常用于JavaScript环境中生成随机、唯一的字符串ID,如数据库主键、会话ID、文件名等场景。 …...

如何离线安装dockerio
如何离线安装dockerio 一、下载Docker离线安装包二、上传离线安装包三、解压安装包四、复制文件到系统目录五、配置Docker服务六、设置文件权限并重新加载配置七、启动Docker服务八、设置开机自启动九、验证安装Docker是一个开源的容器化平台,用于开发、发布和运行应用程序。离…...

LocalDateTime序列化(跟redis有关)
使用过 没成功,序列化后是[2024 11 10 17 22 20]差不多是这样, 反序列化后就是: [ 2024 11 10.... ] 可能是我漏了什么 这是序列化后的: 反序列化后: 方法(加序列化和反序列化注解)&…...
【redis】如何跑
在 Windows 上配置 Redis 需要一些额外的步骤,因为 Redis 官方并没有为 Windows 提供原生支持。不过,可以通过以下方法来安装和配置 Redis。 方法一:使用 Windows 版 Redis(非官方版本) 下载 Redis for Windows Redis…...

Scala学习记录,全文单词统计
package test32 import java.io.PrintWriter import scala.io.Source //知识点 // 字符串.split("分隔符":把字符串用指定的分隔符,拆分成多个部分,保存在数组中) object test {def main(args: Array[String]): Unit {//从文件1.t…...

【MyBatis】验证多级缓存及 Cache Aside 模式的应用
文章目录 前言1. 多级缓存的概念1.1 CPU 多级缓存1.2 MyBatis 多级缓存 2. MyBatis 本地缓存3. MyBatis 全局缓存3.1 MyBatis 全局缓存过期算法3.2 CacheAside 模式 后记MyBatis 提供了缓存切口, 采用 Redis 会引入什么问题?万一遇到需强一致场景&#x…...

学习ASP.NET Core的身份认证(基于Session的身份认证3)
开源博客项目Blog中提供了另一种访问控制方式,其基于自定义类及函数的特性类控制访问权限。本文学习并测试开源博客项目Blog的访问控制方式,测试程序中直接复用开源博客项目Blog中的相关类及接口定义,并在其上调整判断逻辑。 首先是接口A…...
速盾:高防 CDN 可以配置客户端请求超时配置?
在高防 CDN(Content Delivery Network,内容分发网络)的运行管理中,客户端请求超时配置是一项重要的功能设定,它对于优化网络资源分配、保障服务质量以及维护系统稳定性有着关键意义。 一、客户端请求超时配置的概念 …...

DRM(数字权限管理技术)防截屏录屏----ffmpeg安装
提示:ffmpeg安装 文章目录 [TOC](文章目录) 前言一、下载二、配置环境变量三、运行ffmpeg四、文档总结 前言 FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的…...

使用PyQt5开发一个GUI程序的实例演示
一、安装Python 下载安装到这个目录 G:\Python38-32 安装完成有这些工具,后面备用: G:\Python38-32\Scripts\pyrcc5.exe G:\Python38-32\Scripts\pyuic5.exe 二、PyQt环境配置 pip install PyQt5 pip install pyqt5-tools 建议使用国内源,…...
【VUE3】【Naive UI】<NCard> 标签
【Vue3】【Naive UI】 标签 title 属性bordered 属性header-style 和 body-style 属性footer 属性actions 属性hoverable 属性loading 属性size 属性type 属性cover 和 avatar 属性description 属性style 属性 【VUE3】【Naive UI】<NCard> 标签 【VUE3】…...
选择排序之大根堆
大根堆:树的根节点大于左右子树的结点值,这样就能保证每次从树根取的是最大值 灵魂在于HeadAdjust函数,以某节点为树根通过下落调整为大根堆, 建树思想 就是,从最后一个非终端结点开始调整以该结点为根的子树&#x…...

AI的魔力:如何为开源软件注入智慧,开启无限可能
“AI的魔力:如何为开源软件注入智慧,开启无限可能” 引言: 在科技发展的浪潮中,开源软件生态一直扮演着推动创新与共享的重要角色。从Linux到Python,开源项目赋予了开发者全球协作的机会,推动了技术的飞速…...
如何在 VPS 上使用 Git 设置自动部署
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 介绍 要了解 Git 的基本知识以及如何安装,请参考介绍教程。 本文将教你如何在部署应用程序时使用 Git。虽然有许多使用 Gi…...

Linux下的三种 IO 复用
目录 一、Select 1、函数 API 2、使用限制 3、使用 Demo 二、Poll 三、epoll 0、 实现原理 1、函数 API 2、简单代码模板 3、LT/ET 使用过程 (1)LT 水平触发 (2)ET边沿触发 4、使用 Demo 四、参考链接 一、Select 在…...

通过 SSH 进行WordPress网站的高级服务器管理
我在管理hostease的服务器时,时常需要通过SSH登录服务器进行修改。而在网站管理中,SSH不仅是一个基础工具,更是高级用户用来精细化管理和优化服务器的重要工具。通过SSH,你可以深入监控服务器的性能、精细管理系统资源,…...
速盾高防cdn支持移动端独立缓存
随着移动互联网的快速发展,移动端网页访问量也越来越大。然而,移动端的网络环境相对不稳定,用户体验可能会受到影响。因此,使用高防CDN来加速移动端网页访问,成为越来越多网站运营者的首选。 速盾高防CDN是一种分布式…...

PMP–一、二、三模、冲刺–分类–8.质量管理
文章目录 技巧五、质量管理 一模8.质量管理--质量管理计划--质量管理计划包括项目采用的质量标准,到底有没有满足质量需求,看质量标准即可。6、 [单选] 自项目开始以来,作为项目经理同事的职能经理一直公开反对该项目,在讨论项目里…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...

1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...