1. 项目概述
这个项目源于我在旅游行业做数据分析时的一个实际需求:如何快速了解全国省会城市风景区分布情况,为旅游线路规划提供数据支持。传统表格数据难以直观展示空间分布特征,而商业GIS软件又过于笨重。于是我用SpringBoot+Leaflet搭建了一个轻量级WebGIS系统,实现了风景区分布可视化与基础空间分析功能。
整套方案从数据采集、存储到前端展示全部自主完成,核心解决了三个问题:
- 风景区POI数据的标准化采集与空间化处理
- 基于PostGIS的空间查询与聚合分析
- 通过Leaflet实现交互式地图可视化
技术栈选择上特别考虑了轻量化与开源特性:
- 后端:SpringBoot 2.7 + PostGIS 3.1
- 前端:Leaflet 1.9 + Bootstrap 5
- 数据源:高德地图POI接口+公开行政区划数据
提示:项目完整代码已托管在Gitee,文末会提供获取方式。下面我会重点拆解关键技术实现细节。
2. 数据准备与处理
2.1 空间数据采集
风景区数据通过高德地图POI接口获取,采用分布式爬虫确保数据完整性。关键处理步骤:
python复制# 伪代码:高德POI采集示例
def get_poi_by_city(city_name):
params = {
"keywords": "风景区",
"city": city_name,
"offset": 20,
"key": "your_amap_key"
}
response = requests.get("https://restapi.amap.com/v3/place/text", params=params)
return parse_poi_data(response.json())
采集到的原始数据需要经过:
- 坐标转换:高德GCJ-02转WGS84
- 属性清洗:去除重复、无效POI
- 分类标注:按A级景区标准分级
2.2 PostGIS数据库设计
创建空间数据库表时特别注意SRID设置(使用EPSG:4326):
sql复制CREATE TABLE scenic_spots (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
level VARCHAR(10),
city VARCHAR(20),
geom GEOMETRY(POINT, 4326)
);
-- 创建空间索引大幅提升查询性能
CREATE INDEX idx_scenic_spots_geom ON scenic_spots USING GIST(geom);
数据入库采用Spring Data JPA + Hibernate Spatial:
java复制@Entity
@Table(name = "scenic_spots")
@TypeDef(name = "geometry", typeClass = GeometryType.class)
public class ScenicSpot {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "geom", columnDefinition = "Geometry(Point,4326)")
private Point geom;
// 其他字段...
}
3. 核心功能实现
3.1 空间查询接口
通过SpringBoot暴露RESTful API,关键接口设计:
| 接口类型 | 路径 | 参数 | 说明 |
|---|---|---|---|
| GET | /api/spots/within | lat, lng, radius | 半径查询 |
| GET | /api/spots/city | city | 城市查询 |
| GET | /api/spots/cluster | zoom | 聚合查询 |
半径查询的PostGIS实现:
sql复制SELECT * FROM scenic_spots
WHERE ST_DWithin(
geom,
ST_SetSRID(ST_MakePoint(:lng, :lat), 4326),
:radius/111000
)
3.2 Leaflet地图集成
前端核心配置要点:
javascript复制// 初始化地图
const map = L.map('map', {
center: [35, 105],
zoom: 5,
preferCanvas: true // 大数据量时启用Canvas渲染
});
// 加载高德底图(需申请key)
L.tileLayer('https://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}', {
subdomains: ['1', '2', '3', '4'],
attribution: '©高德地图'
}).addTo(map);
3.3 聚合展示优化
当缩放级别较小时,采用Leaflet.markercluster插件实现点聚合:
javascript复制const markers = L.markerClusterGroup({
spiderfyOnMaxZoom: true,
showCoverageOnHover: false,
zoomToBoundsOnClick: true
});
fetch('/api/spots/all')
.then(res => res.json())
.then(data => {
data.forEach(item => {
markers.addLayer(
L.marker([item.lat, item.lng])
.bindPopup(`<b>${item.name}</b><br>等级:${item.level}`)
);
});
map.addLayer(markers);
});
4. 空间分析实践
4.1 密度分析
通过PostGIS计算各城市风景区密度(个/万平方公里):
sql复制SELECT
city,
COUNT(*) as spot_count,
COUNT(*)/(ST_Area(ST_Union(geom))/100000000) as density
FROM scenic_spots
GROUP BY city
ORDER BY density DESC;
4.2 缓冲区分析
生成5A级景区10公里缓冲区的SQL示例:
sql复制SELECT
id,
name,
ST_AsGeoJSON(ST_Buffer(geom, 10/111)) as buffer_geom
FROM scenic_spots
WHERE level = '5A';
4.3 可视化效果增强
使用Leaflet.heat插件实现热力图展示:
javascript复制const heatData = spots.map(spot => [spot.lat, spot.lng, 0.5]);
L.heatLayer(heatData, {radius: 25}).addTo(map);
5. 性能优化技巧
5.1 数据库层面
-
空间索引优化:
sql复制ANALYZE scenic_spots; -- 更新统计信息 REINDEX INDEX idx_scenic_spots_geom; -- 重建索引 -
查询优化:添加ST_Subdivide处理复杂几何
5.2 前端优化
- 采用Canvas渲染模式
- 实现分页加载(每页500个点)
- 使用Web Worker处理大数据量
5.3 缓存策略
java复制@Cacheable(value = "spotCache", key = "#city")
public List<ScenicSpot> findByCity(String city) {
return repository.findByCity(city);
}
6. 常见问题排查
-
坐标偏移问题
- 现象:标记点与底图位置偏差
- 检查:确认所有坐标系统一为WGS84
- 解决方案:使用proj4leaflet插件校正
-
聚合显示异常
- 现象:缩放时聚合点不更新
- 检查:确认zoomend事件绑定正确
- 解决方案:调用markers.refreshClusters()
-
跨域问题
java复制@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("*"); } }
7. 项目扩展方向
- 实时数据:接入景区人流监控API
- 三维展示:集成Cesium实现3D可视化
- 路径规划:结合OpenRouteService API
- 时空分析:研究节假日分布特征
我在实际部署时发现,当数据量超过5万条时,需要特别注意:
- 采用GeoServer发布WFS服务替代直接数据库查询
- 前端使用Leaflet.LayerGroup实现动态加载
- 后端增加@Transactional(timeout=30)防止长事务
完整项目包含:
- 后端工程(SpringBoot)
- 前端页面(HTML+JS)
- 数据库初始化脚本
- 部署文档
项目源码获取:在Gitee搜索"scenic-spots-analysis",或私信我获取仓库地址。部署时记得修改application.yml中的数据库配置和高德地图key。
