跳到主要内容WebGIS 省域区县天气可视化实战:基于 Leaflet 与 SpringBoot | 极客日志Java大前端java
WebGIS 省域区县天气可视化实战:基于 Leaflet 与 SpringBoot
基于 Leaflet 和 SpringBoot 构建省域区县天气可视化系统。利用 PostgreSQL 管理空间数据,集成百度天气 API 获取实时气象信息。后端采用 MyBatis Plus 简化数据访问,前端通过 Leaflet 实现地图渲染、动态色带映射及标签碰撞检测。示例覆盖湖南与西藏两地,演示了从数据清洗到交互式展示的全链路开发过程。
17396582021 浏览 WebGIS 省域区县天气可视化实战:基于 Leaflet 与 SpringBoot
前言
地理信息系统(GIS)与 Web 技术的融合,为地理信息的可视化展示带来了新的机遇。WebGIS 能够将地理空间数据直观地呈现给用户,而天气数据作为重要的地理信息之一,其可视化在气象预报、灾害预警等领域意义重大。本文从 WebGIS 视角出发,探讨如何利用 Leaflet 实现省域区县的天气可视化。

本文将系统介绍如何获取和整合省域区县的天气数据,利用 Leaflet 搭建平台,实现地图初始化、图层添加及数据符号化展示,并通过实战案例演示完整开发流程。
一、空间数据基础
本节介绍相关的空间数据基础,包括省级空间范围、区县行政空间范围以及区县驻地等信息的检索。为了将天气数据与行政区划关联,我们在天气表中预留了行政区划编码字段。
1、省域空间检索
省域信息主要用于省级行政范围展示,以及在调用天气接口时通过行政区划代码获取下级区县信息。
查询省域信息及表结构如下:
select * from biz_province;
返回结果中的 code 即为省份对应的行政区划代码,例如 130000 表示河北省。查询该省份下属区县信息需使用区县信息表:
select * from biz_area t where t.province_code = '130000';
通过上述 SQL 即可获取指定省份的下属区县信息,后续可根据区县 code 获取天气信息。
2、区县天气信息检索
涉及的数据表主要包括实时天气信息表 (biz_weather_now)、区县信息表 (biz_area) 和城市信息表 (biz_geographic_name)。
以查询湖南省 (430000) 某日期的区县天气信息为例,SQL 语句如下:
SELECT t2.*, T.province_code, T.province_name, T.area_code, T.area_name, t1.geom, st_asgeojson ( T.geom ) geomJson, st_x ( t1.geom ) lon, st_y ( t1.geom ) lat
FROM biz_weather_now t2, biz_area T, biz_geographic_name t1
WHERE to_char( t2.uptime, 'YYYY-MM-DD' ) = '2025-08-17'
AND T.province_code = '430000'
AND T.area_name t1.NAME
T.area_code t2.location_code
st_contains(T.geom, t1.geom)
t.area_code;
=
AND
=
AND
ORDER
BY
注意:原 SQL 中 st_contains(t.geom, ...) 存在笔误,已修正为 T.geom 以确保逻辑正确。
二、天气数据简介
天气数据的准确性至关重要。本例以百度天气接口为例,获取区域内的天气信息。
1、省域天气数据获取
核心在于批量处理省级数据并入库。以下是 Java 后台采集的核心代码示例:
@Test
public void bdWeather2PGWithProvince() throws InterruptedException {
String provinceCode = "430000";
Random random = new Random();
QueryWrapper<Area> queryWrapper = new QueryWrapper<Area>();
queryWrapper.like("province_code", provinceCode);
List<Area> areaList = areaService.list(queryWrapper);
if(StringUtils.isNotEmpty(areaList)) {
for (Area area : areaList) {
String areaCode = area.getAreaCode();
HttpResponse<String> result = baiduWeatherApiService.getWeather(areaCode, DATA_TYPE);
Gson gson = new Gson();
BdWeatherDTO bdWeatherInfo = gson.fromJson(result.getBodyResult(), BdWeatherDTO.class);
WeatherInfoDTO bdResult = bdWeatherInfo.getResult();
if(null != bdResult) {
Long weatherId = IdWorker.getId();
bdResult.getWeatherNow().setPkId(weatherId);
bdResult.getWeatherNow().setLocationCode(areaCode);
weatherService.insertWeatherInfo(bdResult);
}
Thread.sleep(1500 + random.nextInt(1000));
}
}
}
运行后即可查看 PostgreSQL 数据库中的实际天气信息。
2、区县名称不一致
行政区划调整可能导致区县名称不一致(如'望城县'改为'望城区')。为保证查询关联成功,需统一两张表的数据名称,建议参考官方标准进行清理。
三、SpringBoot 后台实现
采用 SpringBoot 框架提供后台服务,重点描述天气数据查询与控制层实现。
1、Java 后台天气数据查询
基于 MyBatis Plus 定义数据视图对象,关键 Mapper 代码如下:
package com.yelang.project.meteorology.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yelang.project.meteorology.domain.AreaWeatherVO;
import com.yelang.project.meteorology.domain.WeatherNow;
public interface WeatherNowMapper extends BaseMapper<WeatherNow>{
final static String GET_WEATHER_BYPROVINCE_ANDDAY = "<script>" +
" SELECT t2.*,T.province_code,T.province_name,T.city_code,T.city_name,T.area_code,T.area_name, " +
" t1.geom,st_asgeojson ( T.geom ) geomJson,st_x ( t1.geom ) lon,st_y ( t1.geom ) lat " +
" FROM biz_weather_now t2,biz_area T,biz_geographic_name t1 " +
" WHERE to_char( t2.uptime, 'YYYY-MM-DD' ) = #{day} AND T.province_code = #{provinceCode} " +
" AND T.area_name = t1.NAME AND T.area_code = t2.location_code AND st_contains(T.geom, t1.geom) " +
" ORDER BY t.area_code " +
"</script>";
@Select(GET_WEATHER_BYPROVINCE_ANDDAY)
List<AreaWeatherVO> getWeatherByProvinceAndday(@Param("provinceCode") String provinceCode,@Param("day") String day);
}
视图对象集成了实时天气对象 JavaBean,以便复用:
package com.yelang.project.meteorology.domain;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Data
@ToString(callSuper=true)
@EqualsAndHashCode(callSuper=false)
public class AreaWeatherVO extends WeatherNow implements Serializable{
private static final long serialVersionUID = -7559774548761847068L;
@TableField(exist = false,value= "province_code") private String provinceCode;
@TableField(exist = false,value= "province_name") private String provinceName;
@TableField(exist = false,value= "city_code") private String cityCode;
@TableField(exist = false,value= "city_name") private String cityName;
@TableField(exist = false,value= "area_name") private String areaName;
@TableField(exist = false) private String geomJson;
private String lat;
private String lon;
}
2、控制层实现
控制层负责接收前端请求并返回响应数据,核心代码如下:
package com.yelang.project.meteorology.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.yelang.framework.web.controller.BaseController;
import com.yelang.framework.web.domain.AjaxResult;
import com.yelang.project.meteorology.domain.AreaWeatherVO;
import com.yelang.project.meteorology.service.IWeatherNowService;
@Controller
@RequestMapping("/met/province/weather")
public class ProvinceWeatherController extends BaseController{
private String prefix = "meteorology/weather";
@Autowired
private IWeatherNowService weatherNowService;
@GetMapping("/province")
public String province(){ return prefix + "/province"; }
@GetMapping("/list/{pcode}")
@ResponseBody
public AjaxResult ewsnProvinceList(@PathVariable("pcode") String pcode){
String day = "2025-08-17";
List<AreaWeatherVO> dataList = weatherNowService.getWeatherByProvinceAndday(pcode,day);
return AjaxResult.success().put("data", dataList);
}
}
四、WebGIS 前端实现
Leaflet 凭借轻量级、易上手的特点成为 WebGIS 开发的首选。本节重点介绍气温颜色定义及数据展示。
1、气温颜色及图例初始化
为了直观展示气温,我们定义了气温色带(colormap),将数值映射到颜色。以下配置包含十六进制代码及 RGB 值:
| 气温范围 (℃) | 颜色描述 | 十六进制颜色代码 |
|---|
| 45℃以上 | 深红色 | #8B0000 |
| 40℃ - 45℃ | 红色 | #FF0000 |
| 35℃ - 40℃ | 橙红色 | #FF4500 |
| 30℃ - 35℃ | 橙色 | #FFA500 |
| 25℃ - 30℃ | 黄色 | #FFFF00 |
| 20℃ - 25℃ | 浅绿色 | #90EE90 |
| 15℃ - 20℃ | 绿色 | #00FF00 |
| 10℃ - 15℃ | 青色 | #00FFFF |
| 5℃ - 10℃ | 浅蓝色 | #ADD8E6 |
| 0℃ - 5℃ | 蓝色 | #0000FF |
| -5℃ - 0℃ | 深蓝色 | #4169E1 |
| -10℃ - -5℃ | 紫色 | #800080 |
| -15℃ - -10℃ | 深紫色 | #4B0082 |
| -20℃ - -15℃ | 黑色 | #000000 |
var weatherColorList = [
{name:"-20℃ - -15℃",color:"#000000",rgb:new Color(0,0,0),colorDesc:"黑色"},
{name:"-15℃ - -10℃",color:"#4B0082",rgb:new Color(75,0,130),colorDesc:"深紫色"},
{name:"-10℃ - -5℃",color:"#800080",rgb:new Color(128,0,128),colorDesc:"紫色"},
{name:"-5℃ - 0℃",color:"#4169E1",rgb:new Color(65,105,225),colorDesc:"深蓝色"},
{name:"0℃ - 5℃",color:"#0000FF",rgb:new Color(0,0,255),colorDesc:"蓝色"},
{name:"5℃ - 10℃",color:"#ADD8E6",rgb:new Color(173,216,230),colorDesc:"浅蓝色"},
{name:"10℃ - 15℃",color:"#00FFFF",rgb:new Color(0,255,255),colorDesc:"青色"},
{name:"15℃ - 20℃",color:"#00FF00",rgb:new Color(0,255,0),colorDesc:"绿色"},
{name:"20℃ - 25℃",color:"#90EE90",rgb:new Color(144,238,144),colorDesc:"浅绿色"},
{name:"25℃ - 30℃",color:"#FFFF00",rgb:new Color(255,255,0),colorDesc:"黄色"},
{name:"30℃ - 35℃",color:"#FFA500",rgb:new Color(255,165,0),colorDesc:"橙色"},
{name:"35℃ - 40℃",color:"#FF4500",rgb:new Color(255,69,0),colorDesc:"橙红色"},
{name:"40℃ - 45℃",color:"#FF0000",rgb:new Color(255,0,0),colorDesc:"红色"},
{name:"45℃以上",color:"#8B0000",rgb: new Color(139,0,0),colorDesc:"深红色"}
];
var DIY_BLUE_GREEN_YELLOW_RED_SCHEME;
$(document).ready(function () {
initSidebar();
var legendData = new Array();
var colorArray = new Array();
for(var i=0;i<weatherColorList.length;i++){
var _tempData = weatherColorList[i];
legendData.push({
label: "\xa0\xa0"+_tempData.name,
type: "rectangle",
radius: 12,
color: _tempData.color,
fillColor: _tempData.color,
fillOpacity: 0.8,
weight: 2
});
}
colorArray.push(_tempData.rgb);
DIY_BLUE_GREEN_YELLOW_RED_SCHEME = new MultiColorScheme('', -20,45 ,colorArray);
initLegend(legendData);
});
2、气温数据展示实现
考虑到区县数量较多,为避免中文标签遮挡,采用碰撞检测组件辅助提升效果:
var collisionLayer = L.LayerGroup.collision({margin:2});
function previewWeather(pid,provinceCode,name){
previewProvince(pid,name);
$.ajax({
type:"get",
url:ctx + "/met/province/weather/list/" + provinceCode,
data:{},
dataType:"json",
cache:false,
processData:false,
success:function(result){
if(result.code == web_status.SUCCESS){
$("#title_info").html(name+"天气实况<sub>更新时间:20250817" +"</sub>");
collisionLayer.clearLayers();
var dataArray = result.data;
if(dataArray != null && dataArray.length > 1){
for(var i=0;i< dataArray.length;i++){
var areaData = dataArray[i];
var color = makeColor(areaData.temp,-20,45,DIY_BLUE_GREEN_YELLOW_RED_SCHEME);
var areaLayer = L.geoJSON(JSON.parse(areaData.geomJson),{
style: {
color:color,
fillColor:color,
weight:3,
"opacity":0.65,
fillOpacity: 0.65
}
}).addTo(mymap);
var myIcon = L.divIcon({
iconSize: null,
className: '',
popupAnchor:[5,5],
shadowAnchor:[5,5],
html: buildShowInfo(i,color,areaData)
});
showLayerGroup.addLayer(areaLayer);
L.marker([areaData.lat, areaData.lon], { icon: myIcon}).addTo(collisionLayer);
collisionLayer.addTo(showLayerGroup);
}
}
} else {
$.modal.alertWarning("获取空间信息失败");
}
},
error:function(){
$.modal.alertWarning("获取空间信息失败");
}
});
}
五、成果展示
1、湖南省天气展示
整体来看,湖南 8 月 17 日 8 点左右全省气温范围在 20 度到 29 度之间。低温前五区县为桂东县、南岳区、汝城县等;高温前五区县集中在岳阳市和益阳市,如岳阳楼区、云溪区等,温度均为 29.00℃。
2、西藏自治区天气展示
西藏整体气温较低,范围从 2 度到 21 度。低温前五区县包括嘉黎县、错那县等;高温前五区县主要集中在林芝市,墨脱县温度最高达 21.00℃,体现了高海拔地区的气温差异。
六、总结
本文介绍了基于 Leaflet 和 SpringBoot 实现省域区县天气可视化的完整流程。从空间数据检索、天气数据采集,到后端 API 构建及前端地图渲染,涵盖了全链路开发的关键技术点。通过实际案例展示了如何处理数据清洗、色带映射及交互优化,为类似项目提供了可参考的解决方案。
相关免费在线工具
- Keycode 信息
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
- Escape 与 Native 编解码
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
- JavaScript / HTML 格式化
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
- JavaScript 压缩与混淆
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online