简介本资源是一套完整的WebGIS古村古镇数字化平台源码面向地理信息科学、计算机相关专业本科生及WebGIS初学者解决文化遗产数字化展示与管理的典型教学与实践需求适合作为期末作业、课程设计或小型WebGIS项目开发参考。压缩包共159个文件含43个JavaScript核心逻辑文件、20个CSS样式文件如bootstrap.min.css、layer.css等、58个PNG/GIF/SVG图像资源、8个HTML页面及8个MP4演示视频整体容量218.99MB结构清晰覆盖前端交互、地图渲染、用户权限与数据可视化全流程。已有380人学习下载资源完整包含数据采集、地图查询、分析展示、角色管理等六大功能模块配套多格式静态资源与可运行前端代码无需额外配置即可本地部署调试特别适合理解WebGIS中HTML/CSS/JS与GIS API协同开发的实际路径。1. 古村古镇数字化平台不是“地图套壳”而是用WebGIS把砖瓦木石变成可计算、可追溯、可演化的空间数据资产你花三天搭好Leaflet基础地图加载完高德瓦片往上面标几个古建图标——这不叫古村古镇数字化平台。真正的平台是让文旅局能查清某座清代祠堂的梁架年代、修缮记录、产权归属、游客热力分布让规划院在浏览器里拖拽滑动叠加遥感影像、三维倾斜摄影、管线BIM模型一键生成保护范围缓冲区分析报告让村民用手机拍下破损窗棂上传系统自动关联到该建筑的数字档案并触发修缮工单流转。这个【WebGIS系统古村古镇数字化平台源码】核心不在“展示”而在“空间数据驱动业务闭环”它把散落在档案馆、测绘院、文保所、村委会的非结构化信息通过空间坐标锚定、属性结构化建模、多源异构数据融合变成可查询、可分析、可联动、可更新的活态数据库。适合两类人一是高校地理信息/城乡规划专业学生做课程设计或毕设需要真实业务逻辑支撑不是画个地图交差二是基层文保单位技术岗想快速验证本地化部署可行性避开从零造轮子的坑。它不是炫技型Demo而是按“县-镇-村-院落-构件”五级空间粒度设计的数据底座源码里藏着大量针对古建语义建模的妥协与取舍——比如如何用GeoJSON表达飞檐翘角的拓扑关系怎么让非GIS人员也能维护构件照片元数据。下面我们就从源码结构开始一层层拆解这个系统怎么跑起来、怎么改、怎么不翻车。2. 搭建本地开发环境用Docker Compose一键拉起PostGISGeoServer前端服务绕过90%的环境依赖地狱这个平台的源码结构非常典型后端用Java Spring Bootbackend/目录空间数据引擎依赖PostGIS而非纯内存GeoJSON图层发布靠GeoServer不是直接吐GeoJSON前端是Vue3OpenLayers不是Leaflet轻量版。很多新手卡在第一步——光看README里“安装JDK、Maven、Node.js、PostgreSQL”就头皮发麻。实际最稳的路径是跳过本地环境配置用Docker Compose统一编排。源码根目录下的docker-compose.yml文件就是关键入口它定义了四个核心容器postgres带PostGIS扩展、geoserver预装了WMS/WFS插件、backendSpring Boot应用、frontendVue生产构建镜像。你不需要手动装PostGIS扩展也不用折腾GeoServer的WAR包部署——Docker镜像里全配好了。2.1 初始化空间数据库执行SQL脚本创建schema并导入样例数据进入backend/src/main/resources/sql/目录你会看到三个关键SQL文件init_schema.sql建表空间字段、insert_sample_data.sql含5个典型古村的点线面数据、create_views.sql为统计报表建视图。别直接用psql连上去执行——先确认Docker容器已启动docker-compose up -d postgres # 等待30秒让PostgreSQL初始化完成 docker exec -it webgis_postgres_1 psql -U postgres -d webgis_db -f /app/sql/init_schema.sql docker exec -it webgis_postgres_1 psql -U postgres -d webgis_db -f /app/sql/insert_sample_data.sql提示webgis_postgres_1是docker-compose自动命名的容器名可通过docker ps确认。/app/sql/是容器内挂载路径对应宿主机的backend/src/main/resources/sql/。执行后用pgAdmin连接localhost:5432检查publicschema下是否出现village,building,component三张表且geom字段类型为geometry(Geometry,4326)——这是WGS84坐标系必须严格匹配否则后续GeoServer发布图层会报错。2.2 配置GeoServer数据存储用REST API自动注册PostGIS数据源避免手动点点点源码里backend/src/main/resources/application.yml中有一段geoserver:配置包含用户名密码和URL。但真正让GeoServer认出PostGIS表的是backend/src/main/java/com/gucun/webgis/config/GeoServerConfig.java里的initGeoServerDataStore()方法。它在Spring Boot启动时调用GeoServer REST API自动创建数据存储DataStore和图层Layer。关键参数在application.yml里geoserver: url: http://localhost:8080/geoserver/rest username: admin password: geoserver workspace: webgis_ws datastore: pg_webgis_ds启动backend服务前确保geoserver容器已运行docker-compose up -d geoserver然后访问http://localhost:8080/geoserver/web/用admin/geoserver登录进入Workspaces → webgis_ws → Data Stores应能看到pg_webgis_ds数据源且状态为“Available”。如果看不到检查backend日志里是否有HTTP 401 Unauthorized——说明密码不对或HTTP 500——说明PostGIS连接参数host/port/dbname在GeoServer容器内部无法解析Docker网络隔离导致需用host.docker.internal代替localhost。2.3 启动前后端服务用docker-compose up -d一次拉起全栈前端自动代理API请求所有服务都准备就绪后执行docker-compose up -d # 查看日志确认启动状态 docker logs -f webgis_backend_1 docker logs -f webgis_frontend_1此时访问http://localhost:8080应该看到登录页。注意前端Vue应用默认监听8080端口但它的vue.config.js里配置了devServer.proxy将/api/**请求代理到http://localhost:8081即backend服务。这个代理只在开发模式生效生产构建时npm run build前端静态文件被复制到frontend/dist/由Nginx容器docker-compose.yml中定义直接托管此时API请求走的是相对路径/api/xxx由Nginx反向代理到backend容器。所以不要手动改前端代码里的API baseURL——那是给开发环境用的生产环境靠Nginx配置。3. 数据建模实战古建构件级空间语义建模为什么用PostGIS的GEOMETRY而非GEOGRAPHY平台最硬核的部分不是地图渲染而是如何用空间数据库表达古建的复杂语义。比如一座祠堂它既是“面”建筑轮廓、又是“点”GPS定位坐标、还包含多个“线”梁架走向、“点”柱础位置、甚至“体”三维模型边界。源码里village表存行政边界building表存单体建筑component表存构件——这才是真正的“数字化”起点。而component表的设计暴露了PostGIS选型的关键考量。3.1 构件表component的空间字段设计GEOMETRY(Point,4326) vs GEOGRAPHYcomponent表结构如下简化CREATE TABLE component ( id SERIAL PRIMARY KEY, building_id INTEGER NOT NULL, type VARCHAR(50) NOT NULL, -- dou-gong, roof-tile, wood-carving geom GEOMETRY(Point,4326), photo_url TEXT, repair_history JSONB, CONSTRAINT fk_building FOREIGN KEY (building_id) REFERENCES building(id) );注意geom类型是GEOMETRY(Point,4326)不是GEOGRAPHY。原因很实在所有前端交互点击、框选、距离计算都在WGS84经纬度平面进行PostGIS的GEOMETRY类型对小范围10km²古村的平面距离计算误差0.1%且性能比GEOGRAPHY快3倍以上。而GEOGRAPHY虽支持大地距离米但OpenLayers前端做缓冲区分析时必须先把经纬度转成墨卡托EPSG:3857再算反而增加转换开销。源码里backend/src/main/java/com/gucun/webgis/service/ComponentService.java的findNearbyComponents()方法用的就是ST_DWithin(geom, ST_SetSRID(ST_MakePoint(:lng, :lat), 4326), :distance)——这里:distance单位是“度”不是“米”。所以当你调接口传distance0.001时实际是搜索经度差±0.001°约111米、纬度差±0.001°赤道处约111米高纬度略小的矩形区域。这是WebGIS开发里一个典型的“玄学”用度当米用靠经验校准。3.2 属性结构化用JSONB存储修缮记录兼顾灵活性与查询效率repair_history字段用JSONB而非单独建表是权衡结果。古建修缮记录字段极不固定有的记“2023年更换瓦片”有的记“2019年梁架加固附检测报告PDF链接”有的记“2021年彩绘修复含前后对比图”。若建repair_log表每次查某构件所有修缮记录要JOIN而JSONB可直接WHERE repair_history {year: 2023}。源码里ComponentRepository.java的findByRepairYear()方法就用了这个语法。但要注意JSONB索引必须显式创建否则查询慢。在init_schema.sql末尾有这行CREATE INDEX idx_component_repair_year ON component USING GIN ((repair_history - year));没这行索引查“2023年修缮的所有构件”会全表扫描。这是血泪经验——我第一次部署时漏了这行10万条构件数据查询耗时从80ms飙到3.2秒。3.3 空间关系建模用ST_Contains实现“构件属于某建筑”的拓扑验证building表的geom是POLYGONcomponent表的geom是POINT。要确保每个构件点都在其所属建筑面内不能悬空。源码里ComponentService.java的saveComponent()方法在保存前执行String sql SELECT ST_Contains(b.geom, c.geom) FROM building b, component c WHERE b.id ? AND c.id ?; // 若返回false则抛出BusinessException(构件坐标不在建筑范围内)这不是可选项是强制校验。因为古建测绘常有误差GPS打点偏移5米而祠堂围墙只有3米宽点就落到墙外了。这种拓扑错误不拦截后续做“建筑内构件统计”时就会漏数据。ST_Contains用的是DE-9IM模型比简单的ST_Distance threshold更严谨——它要求点严格在面的内部不含边界避免边界模糊带来的歧义。4. 避坑部署与数据迁移的5个致命陷阱踩中一个就重启三天这个平台源码看着清爽但实际部署时90%的失败都集中在以下五个点。它们不是文档里写的“注意事项”而是我在三轮县级项目落地中亲手填平的坑。4.1 现象GeoServer图层预览正常但前端OpenLayers加载WMS图层白屏原因GeoServer发布的图层CRS坐标参考系与前端Map视图的view projection不匹配。源码默认用EPSG:3857Web墨卡托但GeoServer新建图层时可能默认选EPSG:4326。解决进GeoServer Web UI →Layer Preview→ 找到webgis_ws:village图层 → 点击右侧Edit→ 在Coordinate Reference Systems区域Declared SRS选EPSG:3857Native SRS保持EPSG:4326因PostGIS数据存的是WGS84勾选Force declared。保存后前端main.js里OpenLayers的View配置必须同步const view new View({ center: fromLonLat([116.4, 39.9]), // 必须用fromLonLat转墨卡托坐标 zoom: 12, projection: EPSG:3857 // 此处必须显式声明 });4.2 现象上传构件照片后前端显示404但后端日志无错误原因照片物理存储路径在application.yml里配置为/opt/webgis/uploads/但Docker容器内该路径不存在或宿主机映射权限不足Linux下chmod 777都不管用因容器用户UID不匹配。解决修改docker-compose.yml为backend服务添加卷映射和用户UIDbackend: # ...其他配置 volumes: - ./uploads:/opt/webgis/uploads user: 1001:1001 # 与宿主机uploads目录的owner UID/GID一致然后在宿主机执行sudo chown -R 1001:1001 ./uploads。上传路径就通了。4.3 现象搜索“徽州古村”返回空但数据库里明明有数据原因全文检索用的是PostgreSQL的to_tsvector但village表的name字段未建GIN索引且application.yml里spring.jpa.hibernate.ddl-autovalidate非update导致启动时没自动建索引。解决手动执行SQL建索引CREATE INDEX idx_village_name_search ON village USING GIN (to_tsvector(chinese, name));并在VillageRepository.java的searchByName()方法里HQL写成Query(SELECT v FROM Village v WHERE to_tsvector(chinese, v.name) plainto_tsquery(chinese, :keyword)) ListVillage searchByName(Param(keyword) String keyword);注意chinese字典——这是PostgreSQL中文分词关键没它徽州会被切成徽、州两个单字搜徽州古村就匹配不到。4.4 现象三维倾斜摄影模型加载卡顿浏览器内存暴涨至4GB原因源码里frontend/src/components/3DViewer.vue直接加载.osgb格式模型但未做LODLevel of Detail分级也未启用Cesium Ion的流式加载。解决将原始.osgb用3DCityDB工具转成3D Tiles格式.b3dm并配置Cesium的Cesium3DTilesetconst tileset viewer.scene.primitives.add( new Cesium.Cesium3DTileset({ url: /3dtiles/hongcun/tileset.json, maximumScreenSpaceError: 2 // 控制细节精度值越大越模糊但越快 }) );tileset.json需用3d-tiles-tools生成不是简单改后缀。4.5 现象导出Excel报表时中文乱码显示为?原因Spring Boot默认用ISO-8859-1编码写响应头而Apache POI生成的Excel是UTF-8。解决在ExportController.java的导出方法里显式设置响应头response.setContentType(application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charsetUTF-8); response.setHeader(Content-Disposition, attachment; filename*UTF-8 URLEncoder.encode(fileName, UTF-8));并且POI创建Workbook时用new XSSFWorkbook()而非new HSSFWorkbook()后者是xls老格式对UTF-8支持差。5. 进阶技巧用QGIS Desktop做数据质检三步批量修正古建面状数据拓扑错误平台上线后最头疼的不是功能开发而是数据质量。古建轮廓面building.geom常有自相交、缝隙、重叠等拓扑错误导致缓冲区分析失真、面积统计不准。源码里没提供数据清洗工具但你可以用免费开源的QGIS Desktopv3.28配合Python脚本10分钟搞定批量质检。这不是“高级玩法”而是日常运维必备技能。5.1 第一步用QGIS连接PostGIS导出building图层为GeoPackage打开QGIS →Layer → Add Layer → Add PostGIS Layers→ 填写数据库连接参数hostlocalhost, port5432, databasewebgis_db, usernamepostgres→ 选中building表 →Add。右键图层 →Export → Save Features As→ 格式选GeoPackage→ 路径设为./data/building.gpkg。这步关键GeoPackage是单文件矢量格式比Shapefile更稳定且QGIS对其拓扑检查支持更好。5.2 第二步运行Topology Checker插件标记所有自相交与缝隙QGIS菜单栏 →Plugins → Manage and Install Plugins→ 搜索Topology Checker→ 安装并启用。然后 →Vector → Topology Checker → Configure→ 添加规则Must not have invalid geometry检查自相交、环方向错误Must not have gaps检查面之间缝隙针对古村连片建筑群Must not overlap检查同一建筑被重复录入点击Validate AllQGIS会在地图上标出所有错误位置红点并生成topology_errors.gpkg图层。双击错误记录可定位到具体building的id。5.3 第三步用PyQGIS脚本自动修复并同步回PostGIS在QGIS Python控制台Plugins → Python Console运行以下脚本。它读取topology_errors.gpkg对每个错误building用buffer(0)修复自相交用make_valid()处理无效几何最后更新PostGISfrom qgis.core import QgsVectorLayer, QgsProject, QgsGeometry import psycopg2 # 1. 加载错误图层 error_layer QgsVectorLayer(./data/topology_errors.gpkg, errors, ogr) # 2. 连接PostGIS conn psycopg2.connect(hostlocalhost dbnamewebgis_db userpostgres passwordpostgres) cur conn.cursor() # 3. 遍历错误修复并更新 for f in error_layer.getFeatures(): bid f[building_id] # 错误记录里存了building的id # 查询原几何 cur.execute(SELECT ST_AsText(geom) FROM building WHERE id %s, (bid,)) wkt cur.fetchone()[0] geom QgsGeometry.fromWkt(wkt) # 修复先buffer(0)去自相交再make_valid兜底 fixed_geom geom.buffer(0, 5).makeValid() # 5是容差单位为度 if fixed_geom.isGeosValid(): # 写回PostGIS cur.execute(UPDATE building SET geom ST_GeomFromText(%s, 4326) WHERE id %s, (fixed_geom.asWkt(), bid)) conn.commit() print(fFixed building {bid}) else: print(fFailed to fix building {bid}) cur.close() conn.close()注意buffer(0)是PostGIS里修复自相交的黄金操作原理是把面先转成0宽度缓冲区即去除自相交部分再膨胀回来。makeValid()是QGIS 3.16新增方法能处理更复杂的无效几何如悬挂线。这个脚本跑完再用ST_IsValid(geom)查一遍building表应该100%返回true。我带过的三个学生团队都在毕设答辩前一周发现数据拓扑问题。有人手动画了三天修复有人直接重采——而用这套QGISPyQGIS流程我帮他们20分钟搞定。后来我把这个脚本封装成qgis_fix_topology.py放在源码tools/目录下成了团队标配。数据质量不是上线后才管的事它是每天晨会第一句“今天谁来跑一遍topology check”——希望帮到你。本文还有配套的精品资源点击获取
