5.1 加载矢量图层(ogr,gpx)

news2024/9/9 6:41:14

文章目录

  • 前言
  • 加载矢量(vector)图层
    • ogr
      • Shapefile
        • QGis导入.shp文件
        • 代码导入
      • gpx
        • QGis导入GPX文件
        • 代码导入
      • gpkg
        • QGis导入GPKG文件
        • 代码导入
      • geojson
        • QGis导入GeoJson文件
        • 代码导入
      • gml
        • QGis导入GML
        • 代码导入
      • kml/kmz
        • QGis导入Kml
        • 代码导入
      • dxf/dwg
        • QGis导入dxf
        • 代码导入
      • Coverage
        • QGis导入Coverage矢量数据
        • 代码导入
      • ogr参数总结
    • gpx
      • QGis导入gpx
      • 代码导入
  • 总结

前言

本章讲述使用qgis c++ Api加载各种类型的矢量地图数据显示。

  • 说明:文章中的示例代码均来自开源项目qgis_cpp_api_apps

加载矢量(vector)图层

在QGIS中,图层并不保存数据的实体,而是引用各种类型的数据源,并利用图层样式等属性渲染数据。

  • QgsVectorLayer代表矢量图层,首先看一下官方文档

The QgsVectorLayer is instantiated by specifying the name of a data provider, such as postgres or wfs, and url defining the specific data set to connect to. The vector layer constructor in turn instantiates a QgsVectorDataProvider subclass corresponding to the provider type, and passes it the url. The data provider connects to the data source.

  • 实例化QgsVectorLayer需要提供data provider的名称以及文件路径或url,其构造函数如下
QgsVectorLayer (const QString &path=QString(), const QString &baseName=QString(), const QString &providerLib="ogr", const QgsVectorLayer::LayerOptions &options=QgsVectorLayer::LayerOptions())
  • data provider可以指定的值包括:
Provider说明
ogrOGR提供了一组基于标准的接口和函数库,用于处理和操作地理空间数据。
delimitedtext文本数据按指定的分隔符进行分割
gpxGPX(GPS eXchange Format,GPS交换格式)是一种用于存储坐标数据的 XML 文件格式
spatialiteSpatialite是SQLite数据库的空间数据引擎。
memory数据存在内存中
postgresPOSTGRES是一个对象-关系型数据库管理系统(ORDBMS)
mssqlMSSQL是指微软的SQLServer数据库服务器
wfsWFS(Web Feature Service)是一种允许用户在分布式环境下通过HTTP对空间数据进行增加、删除、修改、查询的GIS数据服务
grassGRASS GIS是一个开源的地理信息系统,可用于处理栅格、拓扑矢量、影像和图表数据。
  • data provider分两类,内置和外部,外部data provider以动态库的形式存在,如下图
    在这里插入图片描述
    以下是完整加载data provider后的输出
C:\src\OSGeo4W\src\qgis-ltr-dev\qgis\src\core\providers\qgsproviderregistry.cpp(337) : (QgsProviderRegistry::init) [633ms] Loaded 25 providers (OAPIF;WFS;arcgisfeatureserver;arcgismapserver;copc;delimitedtext;ept;gdal;geonode;gpx;hana;mdal;memory;mesh_memory;mssql;ogr;pdal;postgres;postgresraster;spatialite;vectortile;virtual;virtualraster;wcs;wms) 

下边分别加载不同data provider的数据

ogr

Accesses data using the OGR drivers (https://gdal.org/drivers/vector/index.html). The url is the OGR connection string. A wide variety of data formats can be accessed using this driver, including file based formats used by many GIS systems, database formats, and web services. Some of these formats are also supported by custom data providers listed below.
OGR是用于读写矢量数据的抽象数据模型类库,是GDAL开源项目的一个分支,也采用X/MIT协议发布。

  • OGR支持的矢量数据格式完整列表见链接
  • 常见的矢量数据包括Shapefile、KML/KMZ、DXF/DMG、GPX、OSM等多种类型
    在这里插入图片描述

Shapefile

  • 一个Shapefile数据仅存储单一要素类型(如点、线、面)
  • 一个Shapefile只包含一个图层
QGis导入.shp文件

QGis中打开后缀名为.shp格式的矢量图层
在这里插入图片描述

代码导入
  • 传入文件路径,图层名,provider名称,构造QgsVectorLayer
  • 调用QgsProject的成员函数addMapLayer即可
void MainWindow::addShpSlot()
{
    QString filename = QStringLiteral("maps/shapefile/protected_areas.shp");
    QFileInfo ff(filename);
    //创建图层
    QgsVectorLayer* vecLayer = new QgsVectorLayer(filename,ff.baseName(),"ogr");
    if(!vecLayer->isValid())
    {
        QMessageBox::critical(this,tr("error"),tr("invalid layer"));
        return;
    }
    QgsProject::instance()->addMapLayer(vecLayer);
    zoomToFirstLayer<QgsVectorLayer*>();
}

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

gpx

GPX是一种以xml格式记录的坐标轨迹文件,通常由GPS设备生成
GPX通常包括航点(Waypoints)、路线(Routes)和轨迹(Tracks)三个主要图层。

QGis导入GPX文件

不同于Shapefile,GPX文件通常包含多个图层,在QGis中会提示用户选择图层
在这里插入图片描述
选择之后,添加图层
在这里插入图片描述

代码导入
  • 基本流程和Shapefile一致
  • ==注意:==路径参数,要通过在文件路径添加后缀|layername=tracks 如下示例代码
void MainWindow::addGpxSlot()
{
    QString filename = QStringLiteral("maps/route.gpx");
    QFileInfo ff(filename);
    //创建图层
    QgsVectorLayer* route_pointsLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=route_points"),"route_points","ogr");
    QgsVectorLayer* routesLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=routes"),"routes","ogr");
    QgsVectorLayer* tracks_pointsLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=track_points"),"track_points","ogr");
    QgsVectorLayer* tracksLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=tracks"),"tracks","ogr");
    QgsVectorLayer* waypointsLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=waypoints"),"waypoints","ogr");
    QList<QgsMapLayer *> mapLayers;
    mapLayers << route_pointsLayer << routesLayer << tracks_pointsLayer << tracksLayer << waypointsLayer;
    QgsProject::instance()->addMapLayers(mapLayers);
    zoomToFirstLayer<QgsVectorLayer*>();
}

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

  • 这样添加有一个问题,需要事先知道文件包含的图层名称,后边的章节会讲述如何获取包含的图层
  • 这里QgsVectorLayer第三个参数provider传入的是ogr,也可以传入gpx,功能相同,但是uri不同,详情见下章

gpkg

全称是GeoPackage,是一种开放的、基于标准的、独立于平台的、可移植的、自描述的、用于传输地理空间信息的紧凑数据格式。

它是一个独立于平台的SQLite数据库文件,其中包含矢量要素、不同比例尺的图像和光栅映射的瓦矩阵集、属性(非空间数据)以及扩展机制。

QGis导入GPKG文件

gpkg基于SQLite,一般会存储多个图层,在QGis中会提示用户选择图层
在这里插入图片描述
在这里插入图片描述

代码导入
  • 流程同gpx,示例代码如下
void MainWindow::addGpkgSlot()
{
    QString filename = QStringLiteral("maps/points_gpkg.gpkg");
    QFileInfo ff(filename);
    //创建图层
    QgsVectorLayer* points_gpkgLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=points_gpkg"),"points_gpkg","ogr");
    QgsVectorLayer* points_smallLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=points_small"),"points_small","ogr");
    QList<QgsMapLayer *> mapLayers;
    mapLayers << points_gpkgLayer << points_smallLayer;
    QgsProject::instance()->addMapLayers(mapLayers);
    zoomToFirstLayer<QgsVectorLayer*>();
}

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

geojson

包含空间信息的数据交换格式,经常用于Web服务,进行数据交换

QGis导入GeoJson文件

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

代码导入
  • 流程和Shapefile相同,代码如下
void MainWindow::addGeoJsonSlot()
{
    QString filename = QStringLiteral("maps/grid_4326.geojson");
    QFileInfo ff(filename);
    QgsVectorLayer* vecLayer = new QgsVectorLayer(filename,ff.baseName(),"ogr");
    if(!vecLayer->isValid())
    {
        QMessageBox::critical(this,tr("error"),tr("invalid layer"));
        return;
    }
    QgsProject::instance()->addMapLayer(vecLayer);
    zoomToFirstLayer<QgsVectorLayer*>();
}

在这里插入图片描述

gml

地理标记语言(GML)是一种用可扩展标记语言(XML)编写地理信息的方式,以方便地理信息的传输和存储。可以将其视为描述应用程序架构的XML语法,应用程序架构描述特定领域或给定上下文中的概念结构。

QGis导入GML

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

代码导入
void MainWindow::addGmlSlot()
{
    QString filename = QStringLiteral("maps/linedensity.gml");
    QFileInfo ff(filename);
    QgsVectorLayer* vecLayer = new QgsVectorLayer(filename,ff.baseName(),"ogr");
    if(!vecLayer->isValid())
    {
        QMessageBox::critical(this,tr("error"),tr("invalid layer"));
        return;
    }
    QgsProject::instance()->addMapLayer(vecLayer);
    zoomToFirstLayer<QgsVectorLayer*>();
}

在这里插入图片描述

kml/kmz

Keyhole 标记语言 (KML) 是一种基于 XML 的格式,用于存储地理数据和相关内容,是一种官方的开放地理空间联盟 (OGC) 标准。 KML 格式便于在 Internet 上发布并可通过许多免费应用程序(例如 Google Earth 和 ArcGIS Explorer)进行查看,因此常用于与非 GIS 用户共享地理数据。 KML 文件以 .kml 或 .kmz(表示压缩的 KML 文件)为扩展名。

QGis导入Kml

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

代码导入
void MainWindow::addKmlSlot()
{
    QString filename = QStringLiteral("maps/multilayer.kml");
    QFileInfo ff(filename);
    //创建图层
    QgsVectorLayer* layer1 = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=Layer1"),"Layer1","ogr");
    QgsVectorLayer* layer2 = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=Layer2"),"Layer2","ogr");
    QgsVectorLayer* layer3 = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=Layer3"),"Layer3","ogr");
    QList<QgsMapLayer *> mapLayers;
    mapLayers << layer1 << layer2 << layer3;
    QgsProject::instance()->addMapLayers(mapLayers);
    zoomToFirstLayer<QgsVectorLayer*>();
}

在这里插入图片描述

dxf/dwg

DXF 是Autodesk公司开发的用于AutoCAD与其它软件之间进行CAD数据交换的CAD数据文件格式

QGis导入dxf

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

代码导入
  • 注意:这里使用了新参数geometrytype=Pointgeometrytype=LineString
  • 由于layername相同,所以使用geometrytype区分不同类型图层
void MainWindow::addDxfSlot()
{
    QString filename = QStringLiteral("maps/points_lines_3d.dxf");
    QFileInfo ff(filename);
    //创建图层
    QgsVectorLayer* points_gpkgLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=entities|geometrytype=LineString"),"entities1","ogr");
    QgsVectorLayer* points_smallLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=entities|geometrytype=Point"),"entities2","ogr");
    QList<QgsMapLayer *> mapLayers;
    mapLayers << points_gpkgLayer << points_smallLayer;
    QgsProject::instance()->addMapLayers(mapLayers);
    zoomToFirstLayer<QgsVectorLayer*>();
}

在这里插入图片描述

Coverage

Coverage 是一种用于存储矢量数据的地理相关数据模型,它包含地理要素的空间(位置)数据和属性(描述性)数据。Coverage 使用一组要素类来表示地理要素。每个要素类存储一组点、线(弧)、面或注记(文本)。Coverage 可以具有拓扑,用于确定要素间的关系。
Coverage 以目录形式存储,而目录中的每个要素类则以一组文件的形式进行存储。

QGis导入Coverage矢量数据
  • 注意: 这里Source Type选的是Directory
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
代码导入
void MainWindow::addCoverageSlot()
{
    QString filename = QStringLiteral("maps/CoverageDir/testvector");
    QFileInfo ff(filename);
    QgsVectorLayer* aaLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=aa"),"aa","ogr");
    QgsVectorLayer* ARCLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=ARC"),"ARC","ogr");
    QgsVectorLayer* CNTLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=CNT"),"CNT","ogr");
    QgsVectorLayer* PALLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=PAL"),"PAC","ogr");
    QList<QgsMapLayer *> mapLayers;
    mapLayers << aaLayer << ARCLayer << CNTLayer << PALLayer;
    QgsProject::instance()->addMapLayers(mapLayers);
    zoomToFirstLayer<QgsVectorLayer*>();
}

在这里插入图片描述

ogr参数总结

  • 加载图层的过程中用到了layerName,geometryType等参数,这里给出ogr支持的所有参数
  • qgis源码中qgsogrprovidermetadata.cpp中encodeUri函数
QString QgsOgrProviderMetadata::encodeUri( const QVariantMap &parts ) const
{
  const QString vsiPrefix = parts.value( QStringLiteral( "vsiPrefix" ) ).toString();
  const QString vsiSuffix = parts.value( QStringLiteral( "vsiSuffix" ) ).toString();
  const QString path = parts.value( QStringLiteral( "path" ) ).toString();
  const QString layerName = parts.value( QStringLiteral( "layerName" ) ).toString();
  const QString layerId = parts.value( QStringLiteral( "layerId" ) ).toString();
  const QString subset = parts.value( QStringLiteral( "subset" ) ).toString();
  const QString geometryType = parts.value( QStringLiteral( "geometryType" ) ).toString();
  const QString authcfg = parts.value( QStringLiteral( "authcfg" ) ).toString();
  const QStringList openOptions = parts.value( QStringLiteral( "openOptions" ) ).toStringList();
  const QString uniqueGeometryType = parts.value( QStringLiteral( "uniqueGeometryType" ) ).toString();
  ......
  }

gpx

Provider reads tracks, routes, and waypoints from a GPX file. The url defines the name of the file, and the type of data to retrieve from it (“track”, “route”, or “waypoint”).
An example url is “/home/user/data/holiday.gpx?type=route”

  • 注意: 这次使用的data provider是gpx

QGis导入gpx

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

代码导入

  • 注意 uri格式是maps/route.gpx?type=route,并且只支持route,track和waypoint
void MainWindow::addGpx1Slot()
{
    QString filename = QStringLiteral("maps/route.gpx");
    QFileInfo ff(filename);
    QgsVectorLayer* routesLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("?type=route"),"route","gpx");
    QgsVectorLayer* tracksLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("?type=track"),"track","gpx");
    QgsVectorLayer* waypointsLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("?type=waypoint"),"waypoint","gpx");
    QList<QgsMapLayer *> mapLayers;
    mapLayers << routesLayer << tracksLayer << waypointsLayer;
    QgsProject::instance()->addMapLayers(mapLayers);
    zoomToFirstLayer<QgsVectorLayer*>();
}

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

总结

  • 分别使用qgis软件和代码导入了ogr,gpx支持的图层格式

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

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

相关文章

2023年全球及中国多肽CDMO市场发展概述分析:CDMO头部企业将拓展至多肽领域[图]

多肽药物是指通过生物合成法或者化学合成法获得的具有特定治疗作用的多肽&#xff0c;多肽药物的分子量介于小分子化药和蛋白质类药物之间&#xff0c;形成了其独特药学空间。多肽药物相比于小分子化药及蛋白质类药物的优势在其发展过程中被逐渐发掘&#xff0c;其在质量控制水…

提升医疗服务质量:将互联网医院源码应用于实践

随着科技的快速发展&#xff0c;医疗行业也亟需寻求创新的解决方案来提升服务质量。在这个数字化时代&#xff0c;互联网医院源码成为了引人注目的选择&#xff0c;为医疗机构和患者之间的沟通和协作提供了前所未有的便利。作为该领域的专家&#xff0c;我将介绍互联网医院源码…

vscode工程屏蔽不使用的文件夹或文件的方法

一. 简介 vscode是一款 微软提供的免费的代码编辑软件。 对于 IMX6ULL-ALPHA开发板而言&#xff0c;NXP官方uboot一定会支持不止 IMX6ULL芯片的代码&#xff0c;也不止支持 一种架构&#xff0c;还支持其他芯片或架构的源码文件。 为了方便阅读代码&#xff0c;vscode软件可…

Java反射调用jar包实现多态

上一篇实现了反射调用jar包&#xff0c;但是没有实现多态&#xff0c;这次先给自己的jar包类抽象一个接口&#xff0c;然后实现类实现接口。最后调用放反射得到的对像转换成接口类型调用执行。 定义接口&#xff0c;指定包为ZLZJar package ZLZJar;public interface ITest {p…

优思学院|改变游戏规则:六西格玛的奇迹力量!

在当今全球竞争激烈的商业环境中&#xff0c;企业家们正在寻找各种方法来提高效率、降低成本并确保顶级质量。在这个追求卓越的道路上&#xff0c;六西格玛以其卓越的数据分析、问题解决和流程优化能力脱颖而出。那么&#xff0c;六西格玛到底是什么&#xff0c;它是如何改变游…

郝培强专访:创业失败、抑郁症和自媒体爆款

近日&#xff0c;我对郝培强&#xff08;网名&#xff1a;Tinyfool&#xff09;老师做了一场视频采访&#xff08;可关注“Micro SaaS开发者公会视频号”观看原视频&#xff09;。70后的Tinyfool是多年资深的创业者、开发者&#xff0c;研发或者技术服务过六间房、有道词典、大…

每日一题 2652. 倍数求和(简单)

最简单的做法&#xff0c;遍历求和&#xff0c;时间O(n) class Solution:def sumOfMultiples(self, n: int) -> int:return sum([i if (i % 3 0) or (i % 5 0) or (i % 7 0) else 0 for i in range(n 1)])如果只求在 [1,n] 内能被m整除的数之和&#xff0c;那么 ans (…

IP地址,端口,域名校验

需求&#xff1a; validateAddress(address) {const parts address.split(:); //例子&#xff1a;[192.168.0.55, 2022]const host parts[0];const port Number(parts[1]);if (/^[0-9]\.[0-9]\.[0-9]\.[0-9]$/.test(host)) {// 是 IP 地址const octets host.split(.);if (…

3、函数式编程--Optional

目录 4. Optional4.1 概述4.2 使用4.2.1 创建对象OptionalofNullable()of()empty() 4.2.2 安全消费值ifPresent 4.2.3 获取值get() 4.2.4 安全获取值orElseGetorElseThrow 4.2.5 过滤filter 4.2.6 判断isPresent 4.2.7 数据转换map 4. Optional 4.1 概述 ​ 我们在编写代码的…

伯俊ERP和金蝶云星空接口打通对接实战

伯俊ERP和金蝶云星空接口打通对接实战 对接系统伯俊ERP 伯俊科技&#xff0c;依托在企业信息化建设方面的领先技术与实践积累&#xff0c;致力于帮助企业实现全渠道一盘货。伯俊提供数字经营的咨询与系统实施&#xff0c;助力企业信息化升级、加速数字化转型&#xff0c;覆盖零…

信息检索与数据挖掘|(四)索引构建

目录 &#x1f4da;硬件基础 &#x1f4da;基于块的排序索引方法 &#x1f407;BSBI算法(blocked sort-based indexing) &#x1f4da;内存式单遍扫描索引构建方法 &#x1f407;SPIMI算法(single-pass in-memory indexing) &#x1f4da;分布式索引构建方法 &#x1f4d…

Cesium Vue(二)— 基础配置

1. 修改默认配置 设置cesium token // 设置cesium token 官网上申请 Cesium.Ion.defaultAccessToken "token";设置默认视角 //设置默认视角 Cesium.Camera.DEFAULT_VIEW_RECTANGLE Cesium.Rectangle.fromDegrees(// 西边的经度89.5,// 南边维度20.4,// 东边经度1…

手把手 java springboot 整合 JUnit进行单元测试

首先 我们在pom.xml中注入JUnit工具 <dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.8.1</version><scope>test</scope> </dependency>然后 我们顺便找…

DM工作笔记-DATEADD(指定日期添加n个时间段)函数和其他时间函数

达梦官方文档已经说得很清楚了&#xff0c;在此仅记录下笔记&#xff0c;方便以后进行查阅。 DATEADD对应的相关文档如下&#xff1a; 这里说明下CREATE_TIME是TIMESTAMP类型。 如下例子&#xff1a; select CREATE_TIME from TEST_TABLE 运行截图如下&#xff1a; 现在有个…

企业数字化转型建设过程中需要哪些能力?

企业数字化转型是一个全面的过程&#xff0c;涉及利用数字技术和战略从根本上改变组织的运营方式和为客户提供价值的方式。为了成功进行这一转型&#xff0c;需要几个关键能力&#xff1a; 1.愿景和领导力&#xff1a;清晰的愿景和强有力的领导力对于指导转型至关重要。领导层…

CV计算机视觉每日开源代码Paper with code速览-2023.10.16

精华置顶 墙裂推荐&#xff01;小白如何1个月系统学习CV核心知识&#xff1a;链接 点击CV计算机视觉&#xff0c;关注更多CV干货 论文已打包&#xff0c;点击进入—>下载界面 点击加入—>CV计算机视觉交流群 1.【目标检测】Rank-DETR for High Quality Object Detecti…

.NET 8使用牛逼的AOT发布ASP.NET Core应用

简介 .NET AOT编译是一种.NET运行时的编译方式&#xff0c;它与传统的JIT编译方式不同。在传统的JIT编译中&#xff0c;.NET应用程序的代码在运行时才会被编译成本地机器码&#xff0c;而在AOT编译中&#xff0c;代码在运行之前就被提前编译成本地机器码。这样可以在代码运行的…

暴露你系统安全的黑暗角落:常见端口漏洞大合集!

目录 前言 一、远程管理端口 1.22 端口&#xff08;SSH&#xff09; 2.23 端口&#xff08;Telnet&#xff09; 3.3389 端口&#xff08;RDP&#xff09; 4.5632 端口&#xff08;Pcanywhere&#xff09; 5.5900 端口&#xff08;VNC&#xff09; 二、Web中间件/服务端口 6.109…

构建强大监控系统:使用Linux Zabbix和cpolar实现远程访问

❤️博客主页&#xff1a; iknow181 &#x1f525;系列专栏&#xff1a; Python、JavaSE、JavaWeb、CCNP &#x1f389;欢迎大家点赞&#x1f44d;收藏⭐评论✍ 目录 1. Linux 局域网访问Zabbix 2. Linux 安装cpolar 3. 配置Zabbix公网访问地址 4. 公网远程访问Zabbix 5. …

基于Java的健身运动网站系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…