简介:面向WebGIS期末作业与入门学习者的古村古镇数字化平台完整源码,前端采用HTML、CSS、JavaScript、jQuery和Bootstrap,GIS部分可结合ArcGIS API或百度地图API调用,实现数据采集存储、地图展示查询、数据分析、数字化展示与用户角色管理等模块,清晰对应Web与GIS两条设计主线,适合作为课程设计参照或理解WebGIS框架的实战案例。资源共159个文件,压缩包约218.99MB,其中43个JavaScript逻辑脚本、20个CSS样式、8个HTML页面构成开发核心,另有58张PNG图片、8个MP4操作演示和6个GIF动图,以及字体、PHP、JSON等辅助文件,便于直接运行和二次修改;同时附带演示录屏和界面素材,可快速对照源码梳理页面与地图服务的交互逻辑。目前已有380人学习下载。按功能组织目录,拿到后可以对照录屏逐模块查看数据流、图层调用和角色管理实现,快速搭建属于自己的古村古镇数字化展示系统。
1. 古村古镇数字化平台到底在数字化什么:先想清楚再写第一行代码
有人看到“WebGIS系统古村古镇数字化平台源码”这个标题,第一反应是三维扫描、倾斜摄影、UE5 大屏。做过一个期末作业级别的 WebGIS 项目之后你会发现,这类平台七分在数据,两分在样式,只有一分才是功能代码。说白了,它做的事情是:把一栋老宅、一条巷道、一棵古树变成带坐标、带属性、能查询的记录,再集中发布成地图服务,让浏览器里能看、能点、能筛。这个链路恰好覆盖了 WebGIS 入门和期末作业里最常被问到的几个环节:数据从哪来、服务怎么发、前端怎么接。
所以这篇适合三类读者:正在为 WebGIS 期末作业找完整案例的人;刚入门前端想搞明白 GIS 服务和地图引擎关系的人;手里有某个村镇的影像或矢量数据、想低成本做个可演示平台的人。先说结论:按照“数据先行、服务中转、前端点缀”的顺序做,一个周末能出可演示版本;反过来先调样式、后补数据,大概率翻车。
2. 技术栈怎么选:从课程作业到可演示系统的四层方案
一个 WebGIS 平台不管多简单,都躲不开四层:数据存储层、地图服务层、前端渲染层、业务逻辑层。古村古镇数字化平台的特殊点在于数据量不大、业务逻辑不复杂,所以选型原则不是“越强越好”,而是“每一层都有现成工具,别自己发明轮子”。这章先把四层分别用什么讲清楚,再给一套能直接照着搭的工程结构。
2.1 前端:OpenLayers 还是 Leaflet,为什么我推荐 OpenLayers
前端渲染层的主流选择是 OpenLayers 和 Leaflet。Leaflet 体积小、插件生态丰富,三五分钟能画出一张带标记的地图,很多 WebGIS 入门教程喜欢用它演示。但真到了古村古镇平台这种场景——要同时叠加矢量底图、服务图层、做点击查询和分类渲染——Leaflet 的很多能力要靠插件拼装,插件质量参差不齐,出了问题你得自己去读插件源码。
OpenLayers 把 WMS、WMTS、矢量切片、坐标系重投影这些能力做进了引擎本身,而不是靠第三方补丁。它的设计思路更接近“GIS 客户端”:坐标系转换是内置的,TileWMS 是原生支持的,点击查询有现成的接口。对学习者来说,用 OpenLayers 写一遍,能顺带理解 WebGIS 的请求-响应模型,这个认知沉淀比换个漂亮底图值钱得多。
我建议的前端技术栈对比大致如下:
| 能力项 | Leaflet | OpenLayers |
|---|---|---|
| 原生 WMS 图层加载 | 需插件 | 内置 TileWMS、ImageWMS |
| 坐标系重投影 | 较弱 | 内置,自动完成 |
| GetFeatureInfo 查询 | 需手写请求 | 有对应工具方法 |
| 样式分等渲染 | 依赖 L.geoman 等插件 | StyleFunction 原生支持 |
| 学习曲线 | 平缓 | 略陡但值得 |
这里有一个必须提前知道的坑:OpenLayers 从旧版到新版 API 变化很大。早年教程里很多写法,比如new ol.Map、ol.layer.Tile,在现在基于 ES Module 的版本里已经是另一套导入方式。搜到的示例代码如果跑不起来,先看代码里是import Map from 'ol/Map.js'还是ol.Map,再决定要不要继续抄。这不是你的问题,是库在演进。
2.2 后端与数据:GeoServer+PostGIS 是省事组合
地图服务层我一般直接用 GeoServer。它是开源实现,把矢量数据发布成 WMS、WFS 都通过图形界面完成,不需要写一行服务端代码。相比商用 GIS 服务软件,它下载即用,部署在本地就是一套完整的环境,对期末作业和中小型数字化项目来说,授权成本和折腾成本最低。
数据存储层用 PostGIS。它是在 PostgreSQL 上扩展的空间数据库,能存点、线、面,能写空间索引,更重要的是 GeoServer 可以直接连它读数据。你白天在 QGIS 里改一条属性,晚上刷新前端页面就能看到变化,不用重启服务。这个“改数据即生效”的体验,对反复调参的古村项目特别重要。
装好环境后先做健康检查,确认两个服务真的能用:
# 检查 GeoServer 是否启动,默认端口 8080 # -s 静默模式,-o 丢弃响应体,-w 只输出 HTTP 状态码 curl -s -o /dev/null -w "%{http_code}\n" \ http://localhost:8080/geoserver/web/ # 进入数据库检查 PostGIS 扩展是否安装成功 psql -U postgres -d village_db -c "SELECT PostGIS_Version();"第一条命令如果输出 200 或 302,说明 GeoServer 的 Web 管理界面已经就绪;如果输出 000,通常是服务没起来或端口被占用。第二条命令能返回 PostGIS 版本号,说明空间扩展安装成功。这两步过了,后面发布图层才有基础。别急着写代码,先让地图服务能看到数据,再做前端。
2.3 工程结构:前端静态页+GeoServer,期末作业不翻车的搭法
很多初学者一上来就搭 Vue 工程、写 Node 后端,最后数据没几行,业务代码倒是堆了不少。古村古镇数字化平台的查询、筛选逻辑本身不复杂,常见做法是“静态页面 + GeoServer 直接出接口”,前端只负责渲染和发请求。我通常这样组织目录:
digital-village/ ├── index.html # 页面入口,容器元素写在这里 ├── css/ │ └── main.css # 排版、弹窗、侧栏样式 ├── js/ │ ├── config.js # GeoServer 地址和图层名统一收口 │ └── map.js # 地图初始化、图层加载、点击事件 ├── data/ │ ├── village.gpkg # 本地矢量数据,可被 GeoServer 直接读取 │ └── 说明.txt # 数据来源、坐标系、字段说明 └── styles/ ├── building.sld # 建筑图层样式 └── poi.sld # POI 点图层样式data目录和 PostGIS 二选一即可。数据量在几百条以内用 GeoPackage 最省事,一个文件拷走就是全部数据;要多人协作或数据量上几千条,再导入 PostGIS。前端接 GeoServer 时,把服务地址和图层名单独放到config.js里,方便以后切换本地与部署环境:
// config.js:所有后端地址和图层标识集中管理 const CONFIG = { // GeoServer 的 WMS 服务地址,注意以 /wms 结尾而不是根地址 geoserverUrl: 'http://localhost:8080/geoserver/village/wms', workspace: 'village', // GeoServer 工作区名 layers: { poi: 'village:poi', // 完整图层名 = 工作区 + 冒号 + 图层名 building: 'village:building' } };workspace必须和 GeoServer 里创建工作区时填的名字保持一致。layers里写的也不是单纯的图层名,而是“工作区名:图层名”的完整标识,这是 WMS 请求能识别图层的唯一方式。部署到服务器时只需要改geoserverUrl一个值,其余代码不用动,这是我最推荐的配置方式。
3. 把古村古镇变成 GIS 数据:采集、矢量化与属性表设计
这章是古村古镇数字化平台真正的核心。功能代码谁都能写,拉开差距的是数据质量:属性字段缺不缺、坐标系乱不乱、分类统不统一。数据准备阶段通常占整个项目 70% 的时间,千万别跳过。
3.1 底图与坐标:坐标系为什么是第一个坑
坐标系是 GIS 里最容易让人翻车的东西。EPSG:4326 是经纬度坐标,单位是度;EPSG:3857 是 Web 墨卡托投影,单位是米,浏览器里的在线底图基本都是它。一个平台的完整链路里存在四个坐标系环节:QGIS 工程坐标系、矢量数据的坐标系、GeoServer 发布配置里的坐标系、前端地图的显示坐标系。这四个只要有一个不一致,表现就是图层偏移几百米,或者干脆不显示。
常见做法是:数据统一存成 EPSG:4326,也就是 WGS84 经纬度;显示交给 OpenLayers 和 GeoServer 自动重投影到 EPSG:3857。不要在 QGIS 里手动翻转坐标,也不要给前端代码里写死一个“偏移量修正”,那些都是掩耳盗铃。如果拿到的是 shapefile,入库前用 ogr2ogr 统一处理:
# 把 shapefile 转成 GeoPackage,并强制统一为 EPSG:4326 + UTF-8 编码 # -f 指定输出格式,-t_srs 指定目标坐标系,-lco 是图层创建选项 ogr2ogr -f GPKG -t_srs EPSG:4326 -lco ENCODING=UTF-8 village.gpkg village.shp-t_srs EPSG:4326的作用是无论输入数据原本是什么坐标系,输出都变成经纬度;-lco ENCODING=UTF-8则解决中文属性乱码问题。执行完以后,可以在 QGIS 里打开village.gpkg,查看图层属性里的坐标系,确认已经变成 WGS84。这个习惯能省掉后面一整类玄学问题。
3.2 QGIS 里手工矢量化:三层数据怎么勾出来
有了底图之后,下一步是矢量化。我把古村平台的数据分成三层:建筑面、巷道线、POI 点。建筑用手工勾画面,巷道画线,古井、古树、游客中心这类用点。为什么不用自动矢量化?因为古村建筑轮廓复杂、树木阴影多,自动化勾出来的边界根本没法用,手工虽然慢,但每一笔都在控制之内。
QGIS 里的操作步骤大致是:新建工程并设置 EPSG:4326;加载在线影像底图或用 GeoPackage 自带底图;新建三个图层,类型分别选面、线、点;进入编辑状态后开始勾画。勾画时有两个要点:一是把捕捉容差设到 20 像素以上,避免边界重叠或留缝;二是缩放级别拉到能看清建筑屋檐的层级再落点,太小的比例尺下勾出来全是误差。
勾完几何后,要给要素生成编号。不要一个个手敲,用字段计算器批量生成:
-- QGIS 字段计算器表达式:给 POI 生成四位编号 -- $id 是要素内部序号,to_string 转成文本,lpad 补零 lpad(to_string($id), 4, '0')lpad的第一个参数是待补零的文本,第二个参数 4 表示总位宽,第三个参数 '0' 表示补的字符。这样生成出来的编号是 0001、0002 这种固定宽度,排序时不会出现 1、10、2 的顺序错乱。手动矢量化最大的好处是,你在勾画的同时其实是在给平台做一次全面的属性普查。
3.3 属性表设计:给 WebGIS 端留好字段
属性表是前端弹窗和筛选的数据来源,字段设计直接影响平台能做什么。我给古村项目设计过一套通用字段,拿 POI 点来说:
| 字段名 | 类型 | 示例值 | 用途 |
|---|---|---|---|
| name | 字符串 | 古井 | 弹窗标题 |
| category | 字符串 | 古建/古树/古井 | 分类渲染和筛选 |
| dynasty | 字符串 | 清代 | 年代展示 |
| status | 字符串 | 已修缮/未修缮 | 状态筛选 |
| description | 长文本 | 始建于…… | 弹窗详情 |
| geom | 几何 | POINT | 空间位置 |
把status和category设计成离散值而不是自由文本,是很重要的一个决策。你可以在 QGIS 里给字段设置值域,也可以用 PostGIS 建表时直接定好规则。导入 PostGIS 的建表语句长这样:
-- 点要素表:古井、古树、游客中心等 POI 的通用结构 CREATE TABLE poi ( gid SERIAL PRIMARY KEY, -- 自增主键 name VARCHAR(50) NOT NULL, -- 名称 category VARCHAR(20), -- 分类:古建/古树/古井/服务设施 dynasty VARCHAR(30), -- 建造年代,用于展示 status VARCHAR(10) DEFAULT '未修缮', -- 状态,用于前端筛选 description TEXT, -- 简介,弹窗正文 geom GEOMETRY(Point, 4326) -- 空间字段,明确坐标系 ); -- GIST 空间索引:提升范围查询和点击查询的速度 CREATE INDEX idx_poi_geom ON poi USING GIST (geom);SERIAL PRIMARY KEY自动生成不重复的序号;GEOMETRY(Point, 4326)直接限定空间字段必须是经纬度点。最后一行创建的是 GIST 空间索引,数据量大了以后,前端做点击查询和拉框查询全靠它,没有这个索引,几百个点可能还能跑,几千个点就会出现明显延迟。
4. 后端发布与前端联动:GeoServer 图层发布和 OpenLayers 加载的完整链路
数据准备好之后,就要进入“服务中转”环节。这章从 GeoServer 发布配置开始,到 OpenLayers 加载、点查、样式,把整条链路走通。这也是最容易出现“单看教程没问题,合起来全是问题”的阶段,每一步都值得耐心检查。
4.1 GeoServer 发布 PostGIS 图层的五个必填项
GeoServer 发布一个图层,核心五个步骤:创建数据存储、创建工作区、发布图层、配置样式、预览验证。常见顺序是先建工作区和数据存储,再发布图层,最后配样式。
| 配置项 | 示例值 | 注意点 |
|---|---|---|
| 工作区 | village | 与前端 config.js 里的 workspace 一致 |
| 数据存储 | village_db | 指向 PostGIS 数据库或 GeoPackage 文件 |
| 图层 | poi | 发布时选择 poi 表,提前确认几何字段是 geom |
| 样式 | poi_style | 可以先选默认样式,发布成功后再换 SLD |
| 预览 | OpenLayers 预览 | 预览成功说明服务链路通 |
发布完成后,一定要用请求验证图层确实能从 WMS 服务取到:
# 请求 GetCapabilities,确认目标图层已被 WMS 服务暴露 curl -s \ "http://localhost:8080/geoserver/village/ows?service=WMS&request=GetCapabilities&version=1.3.0" \ | grep -i "poi" | head -n 5ows是 GeoServer 的统一服务入口,service=WMS指定你要的是地图服务,GetCapabilities返回当前服务里所有图层的列表清单。grep -i "poi"如果能看到包含 poi 的图层名条目,说明发布成功,前端就按这个入口去请求。如果这里查不到,先回到 GeoServer 界面检查图层状态,别急着改前端。
4.2 OpenLayers 加载 WMS 图层的代码模板
前端加载 WMS 是这整套系统里最标准、也最值得记牢的代码。可以用 CDN 直接在 HTML 里引入 OpenLayers,也可以 npm 安装。下面这段是 npm 工程的写法:
// map.js:初始化地图并叠加 GeoServer WMS 图层 import Map from 'ol/Map.js'; import View from 'ol/View.js'; import TileLayer from 'ol/layer/Tile.js'; import TileWMS from 'ol/source/TileWMS.js'; import OSM from 'ol/source/OSM.js'; const villageLayer = new TileLayer({ source: new TileWMS({ url: 'http://localhost:8080/geoserver/village/wms', params: { 'LAYERS': 'village:poi', // 必须写工作区:图层名 'TILED': true // 按瓦片请求,加载更快 }, serverType: 'geoserver', // 按 GeoServer 规则解析服务响应 crossOrigin: 'anonymous' // 允许跨域读取瓦片像素 }) }); const map = new Map({ target: 'map', layers: [ new TileLayer({ source: new OSM() }), // 底图 villageLayer // 业务图层 ], view: new View({ center: [0, 0], // 初始中心,后续用真实坐标替换 zoom: 2 }) });这一段里有三个参数值得专门说。LAYERS必须写全工作区:图层名,少了工作区直接返回错误;serverType: 'geoserver'告诉 OpenLayers 按 GeoServer 的习惯解析能力文档,避免拿到数据却识别不了;crossOrigin: 'anonymous'允许页面读取服务端图片像素,有了它才能做后续的像素点查。底图 OSM 是 EPSG:3857,业务数据是 EPSG:4326,两者叠加后 OpenLayers 会自动请求重投影后的瓦片,不需要手工转换。
4.3 点查询、属性弹窗和分类渲染怎么落地
平台能不能“用”,关键看点击要素能不能看到属性。OpenLayers 里最典型的方式是走 WMS 的 GetFeatureInfo 接口,让 GeoServer 帮你算“哪个要素被点到了”,前端只负责发请求和渲染结果:
// 地图单击事件:请求点击位置的要素属性 map.on('singleclick', function (evt) { const url = villageLayer.getSource().getFeatureInfoUrl( map.getCoordinateFromPixel(evt.pixel), // 点击处的经纬度坐标 map.getView().getResolution(), // 当前地图分辨率 'EPSG:3857', // 返回结果的坐标系 { INFO_FORMAT: 'application/json' } // 请求 JSON 格式 ); if (url) { fetch(url) .then(res => res.json()) .then(js => { const features = js.features; if (features.length > 0) { const p = features[0].properties; alert(p.name + ' | ' + p.category + ' | ' + p.description); } }) .catch(err => console.error('查询失败', err)); } });getFeatureInfoUrl是 TileWMS 提供的方法,它根据点击坐标和服务端图层配置拼出 GetFeatureInfo 请求。INFO_FORMAT指定返回格式,GeoServer 支持application/json,不需要额外插件。如果点击后没有返回任何要素,优先检查发布图层时是否勾选了“允许查询”,这步漏了,前端怎么调都不起作用。
再看一下分类渲染。古村镇平台里,古建、古树、古井如果用同一个样式的点,视觉上会非常单调,也看不出平台能力。用 OpenLayers 的样式函数按属性返回不同样式:
import { Style, Circle, Fill, Stroke, Text } from 'ol/style.js'; // 样式函数:根据 category 字段返回不同颜色和大小的点样式 function getPoiStyle(feature) { const cat = feature.get('category'); let color = '#B8860B'; // 默认:棕黄 if (cat === '古建') { color = '#8B0000'; // 古建:深红 } else if (cat === '古树') { color = '#228B22'; // 古树:深绿 } return new Style({ image: new Circle({ radius: cat === '古建' ? 8 : 6, // 古建点更大 fill: new Fill({ color: color }), stroke: new Stroke({ color: '#ffffff', width: 1 }) }), text: new Text({ text: feature.get('name') || '', offsetY: -12, // 文字显示在点上方,避免压盖 fill: new Fill({ color: '#333333' }), stroke: new Stroke({ color: '#ffffff', width: 3 }) }) }); }样式函数本质上是一个“输入要素、输出 Style”的普通函数,OpenLayers 在渲染每个要素时调用它。这里的radius可以按分类动态变化,实现重点要素突出显示;offsetY: -12把文字推到点符号上方,否则名称和点会叠在一起。样式调到位,平台的专业感立刻就出来了。
5. 避坑指南:坐标系与跨域,5 个让新手熬夜的常见问题
前面的链路看着顺,但真正动手时,几乎所有人的报错都集中在这五个问题上。这章按“现象 → 原因 → 解决”写,直接对着自己的报错排查就行。
5.1 图层一片空白或 404:LAYERS 参数写错的两种可能
现象:底图显示正常,自己的图层一片空白,或者 Network 面板里 WMS 请求返回 400。原因:LAYERS参数里只写了poi,但 GeoServer 里的完整图层名是village:poi;或者大小写与发布时不匹配。解决:先在 GeoServer 的 Layer Preview 里用 OpenLayers 预览,复制预览请求里的LAYERS参数值,粘贴到前端配置里,这个值就是唯一正确的答案。
5.2 浏览器控制台报 CORS 跨域错误
现象:F12 里出现Access to fetch at ... has been blocked by CORS policy。原因:浏览器安全策略限制了一个源的页面读取另一个源的地图服务响应,本地调试时前端跑在 5173,GeoServer 跑在 8080,天然跨域。解决:先确认是不是要真跨域;开发阶段最简单的做法是在 GeoServer 的web.xml里配置 CORS 过滤器,允许浏览器跨域访问 WMS 服务,改完重启 GeoServer。如果是部署到生产环境,更推荐把前端页面和 GeoServer 放到同一个域名下,由同域服务做请求转发,一劳永逸。
5.3 属性弹窗中文乱码
现象:GeoServer 预览正常,前端弹窗里中文变成乱码。原因:数据入库时编码不对,或者 PostGIS 连接层没有指定 UTF-8 字符集。解决:数据入库用ogr2ogr -lco ENCODING=UTF-8;检查 PostGIS 的连接 URL,确认已经加上characterEncoding=UTF-8参数。如果用的是 GeoPackage 文件,检查 QGIS 保存时的编码设置。乱码问题根源几乎全是编码链路上某一环在偷懒。
5.4 点位和底图对不上:采集的经纬度为什么偏
现象:手机采集的 POI 点,加载到平台里整体偏移了几十米。原因:采集工具默认导出的坐标系、入库坐标系、底图坐标系三者不一致,最常见的是把投影坐标当成经纬度使。解决:确认采集工具导出的是经纬度还是投影坐标;入库前用ogr2ogr -t_srs EPSG:4326强制统一;前端不要手动加修正值,偏移不是均匀的,手动修正只会修出一个“这里准、那里不准”的假象。
5.5 量算距离不对:平面和球面混用
现象:用测量工具量巷道长度,结果比实地短不少。原因:EPSG:3857 是投影坐标系,长度在高纬度地区会被拉伸,直接量平面坐标得到的长度不是真实距离。解决:使用球面距离算法,OpenLayers 里用ol/sphere的getLength:
import { getLength } from 'ol/sphere.js'; // lineGeom 是 OpenLayers 的 LineString 几何对象 // 第二个参数指定几何所在的坐标系,默认按 EPSG:3857 const meters = getLength(lineGeom, 'EPSG:3857'); console.log('巷道长度(米):', meters.toFixed(1));getLength内部按球面公式计算,不受投影拉伸影响,结果接近真实距离。如果你的几何对象是 EPSG:4326 经纬度坐标,需要传{ projection: 'EPSG:4326' }这样带参数的形式,否则它会默认把坐标当成米制单位,量出来的数字会大得离谱。
6. 进阶:从能运行到能演示,把古村镇项目做到答辩不虚
系统能跑只是及格线,能让人看出来“这个平台懂古村”才是加分项。最后一章给三个能直接提升完成度的技巧:样式、筛选和性能验证。
6.1 用 SLD 给建筑图层加“古韵”风格
前端样式函数适合点要素,面要素我习惯在 GeoServer 里直接用 SLD 管理。SLD 是 OGC 标准的样式语言,让服务端控制渲染,前端只负责展示。古村建筑用米黄填充加深棕描边,比默认样式更像“古建测绘”该有的样子:
<StyledLayerDescriptor xmlns="http://www.opengis.net/sld" version="1.0.0"> <NamedLayer> <Name>village:building</Name> <UserStyle> <FeatureTypeStyle> <Rule> <PolygonSymbolizer> <Fill> <CssParameter name="fill">#F5DEB3</CssParameter> <CssParameter name="fill-opacity">0.8</CssParameter> </Fill> <Stroke> <CssParameter name="stroke">#7B5B3A</CssParameter> <CssParameter name="stroke-width">2</CssParameter> </Stroke> </PolygonSymbolizer> </Rule> </FeatureTypeStyle> </UserStyle> </NamedLayer> </StyledLayerDescriptor>fill是米黄色,模拟夯土墙;fill-opacity控制在 0.8,让底图纹理能透出来,画面不闷;stroke用深棕色描边模拟木构轮廓线。把这段粘贴到 GeoServer 的样式编辑页里,再在图层发布配置里切换到这个样式,效果立竿见影。
6.2 加一个“修缮状态”筛选:一行参数搞定
演示时最有效的功能往往是“筛选”。给平台加一个只显示“已修缮”古建的状态筛选,前端只需要在 WMS 参数里加一行:
// 通过 CQL_FILTER 参数,让服务端直接返回符合条件的数据 const repairedOnlyLayer = new TileWMS({ url: CONFIG.geoserverUrl, params: { LAYERS: CONFIG.layers.building, TILED: true, // 这里可以动态拼接下拉框选择的值 CQL_FILTER: "status = '已修缮'" } });CQL_FILTER是 GeoServer 的要素过滤语法,相当于把 SQL 的WHERE子句交给了服务端,前端不需要下载全部数据再过滤,请求范围小、响应快。这个能力在答辩现场非常加分,因为能直观演示“平台不只是地图,背后还有数据管理”。
6.3 用开发者工具验证:Network 里看瓦片请求
性能验证不用装额外工具。按 F12 打开开发者工具,切到 Network 面板,筛选wms请求,能看到每次拖动地图时发起了多少瓦片请求、单个请求耗时多少。如果出现大量 400 或 404,说明图层参数或缓存配置有问题;如果瓦片请求是串行的,说明服务端没有开启缓存。我去 GeoServer 的图层发布配置里勾选 Tile Caching 之后,瓦片响应速度通常能快一个量级。
我做这类项目最大的一个教训,是第一版把时间全花在地图样式上,结果属性字段没填完整,现场演示点开弹窗,里面只有一条空描述,非常尴尬。后来养成的习惯是先做属性巡检:把 name、category、status 挨个查一遍,确认每条记录都能支撑起一句完整介绍,再谈样式和交互。数据是你自己的,链路才是你自己的;骨架随处可见,真正让平台立住的永远是数据质量。希望帮到你。
本文还有配套的精品资源,点击获取