基于SpringBoot和PostGIS的云南与缅甸的千里边境线实战

举报
夜郎king 发表于 2024/12/12 12:53:13 2024/12/12
【摘要】 文章首先介绍如何进行空间距离求解,然后结合PgAdmin来进行空间查询实践,最后使用SpringBoot框架结合PostGIS来详细说明如何进行云南的边防线WebGIS可视化实战。

 目录

前言

一、PostGIS空间求解

1、相邻的求解

二、后台程序实现

1、数据查询的实现

2、API接口实现

三、WebGIS可视化实现

1、空间面展示

2、增加面标注

3、图例展示

4、与缅甸距离较近的区县信息

四、总结



前言

        云南,这个位于中国西南边陲的省份,以其独特的地理位置和丰富的民族文化而闻名。作为中国连接东南亚和南亚的重要门户,云南拥有长达四千多公里的边境线,与缅甸、老挝和越南三国接壤。这条边境线不仅是中国对外开放的前沿,也是维护国家安全和地区稳定的关键地带。随着全球化的深入发展和区域合作的不断加强,云南边境线的战略地位日益凸显。云南的边境线总长达到4060公里,是中国边境线最长的省份之一。这条边境线没有天然物理屏障,地势错综复杂、犬牙交错,有的是山高林密、荆棘丛生,沼泽密布、河水湍急。

        云南与缅甸、老挝和越南三国接壤,边境线交错纵横,展现出云南的边境线地域广阔。其中,与缅甸接壤的边境线长达1960公里,与老挝的边境线长约475公里,与越南的边境线长约1180公里。云南的边境线上,374个边境村寨如同一颗颗明珠,闪耀着无尽的光芒,呈现出“边民富、边关美、边境稳、边防固”的美丽新画卷。边境线上的茶叶、咖啡、草果等农产品依托边境口岸走出深山,走向世界。在云南的边境线上,有无数隐姓埋名的边防战士守卫着边境的安全。他们顶着湿热寒冷,忍着蚊虫叮咬,守卫在边境。这些守边人,无论是边防战士、移民管理警察、民兵还是自发巡逻的村民,都在默默地守护着国境线。边境线上的守边人生活条件艰苦,他们住帐篷、睡木板、劈柴烧饭,生烟驱蚊、居边而眠、沿边而巡。他们面对的不仅是自然环境的挑战,还有蛇鼠毒虫的骚扰,以及各种健康风险。

        相信前几年一个令人闻风丧胆的地方-缅北。让大家闻言就不仅害怕,这里是犯罪的天堂,电信诈骗,无数人倾家荡产。而我们的祖国,作为守卫我们安全的最强大后盾,在我们的背后默默的守候。当缅国内出现动荡的时候,许多的边民来到口岸,要求进入我国庇护。为了人民的安全,我们的工作人员与战士、警察构筑了一道坚固的防线。云南边防,是我们的安全防线。

        在信息技术迅猛发展的今天,地理信息系统(GIS)已经成为管理和决策的重要工具。WebGIS,作为GIS技术与互联网技术结合的产物,以其强大的空间数据管理和分析能力,为用户提供了一个全新的视角来观察和理解地理空间信息。云南的千里边境线WebGIS项目,正是在这样的背景下应运而生,旨在通过先进的WebGIS技术,为云南边境线的管理和开发提供科学、高效的解决方案。文章首先介绍如何进行空间距离求解,然后结合PgAdmin来进行空间查询实践,最后使用SpringBoot框架结合PostGIS来详细说明如何进行云南的边防线WebGIS可视化实战。如果您也有兴趣,不妨来这里看看。

一、PostGIS空间求解

        在进行云南边境线区县WebGIS求解时,首选需要正确的计算边界信息。由于我们拿到的国家边界信息与云南省的曲线面数据准确性有一定的问题。因此这里的数据仅供参考,文章重点讲解这种实现思路。如何通过空间函数来求解相邻问题。

1、相邻的求解

        在进行相邻的空间计算求解时,需要用到的数据有两份。首先是国家信息,即缅甸的面数据。这里的数据采用从osm中采集的全球国家信息。然后与云南省的区县数据进行空间计算。区县信息来源于互联网。但是缅甸与云南区县的空间范围还是有一定的问题,这与原始的数据有直接的关系。这里我们首先采用PgAdmin来看一下具体的展示效果。

        在PgAdmin中查询空间数据的sql如下:

select  -1 dist,1 "id", '' province_code,''province_name,'' city_code,'' city_name,
			     '' area_code,'缅甸' area_name,'国家' as "type",st_asgeojson(geom) as geomJson from biz_world_country where short_chinese_name = '缅甸' 
union
SELECT ta.dist,ta.id,ta.province_code,ta.province_name,ta.city_code,ta.city_name,
			     ta.area_code,ta.area_name,ta.type,st_asgeojson(geom) as geomJson 
FROM (
		WITH ynarea AS ( SELECT * FROM biz_area WHERE province_name = '云南省' 
		) SELECT st_distance ( cinfo.geom :: geography, ynarea.geom :: geography ) dist,
		ynarea.* 
	FROM biz_world_country cinfo,
		ynarea 
	WHERE
		short_chinese_name = '缅甸' 
	ORDER BY
		dist DESC 
	) ta 
WHERE
	dist <= 10000;

        将缅甸的国家边界同时查询出来也是为了在WebGIS中重点展示边界的情况。在SQL中增加了一个求解面的距离信息,这里设置一个阈值即10公里。假设两个面距离10公里内的就算是相邻(这只是一种模拟情况,实际情况中还是需要标准的边界矢量地图来进行计算)。执行完查询语句之后,可以看到以下的查询结果。

        然后再点击空间数据预览按钮对空间数据进行预览,整体效果如下:

        咋一看,没有什么问题。仔细将边界拉进后可以看到边界的接边情况比较毛躁。如下图标红的地方。

         在上图中也具体的展示了边界的情况,下面我们会在Leaflet当中对上述空间信息进行空间展示。

二、后台程序实现

        在了解了空间函数计算和空间数据的问题之后,我们基于空间数据库的查询结果来进行后台应用程序的设计,为前端提供可视化查询接口。本小节主要介绍Mapper数据库查询与API接口的实现。

1、数据查询的实现

        在应用程序后台,我们基于Mybatis-Plus来进行空间数据库的查询操作。根据上一节中的空间相邻计算规则,将查询SQL写入到Mapper对象中。关键代码如下:

static final String COUNTRY_NEIGHBOR_BYPROVINCE_SQL = "select  -1 dist,1 id, '' province_code,''province_name,'' city_code,'' city_name,"
				 + " '' area_code,#{country_name} area_name,'国家' as type,st_asgeojson(geom) as geomJson "
			     +" from biz_world_country where short_chinese_name = #{country_name} "
				 + " union "
				 +" select ta.dist,ta.id,ta.province_code,ta.province_name,ta.city_code,ta.city_name,"
			     + "ta.area_code,ta.area_name,ta.type,st_asgeojson(geom) as geomJson "
			     + " from ( with ynarea as ( select * from biz_area where province_name = #{province_name} ) "
			     + " select st_distance(cinfo.geom::geography, ynarea.geom ::geography) dist,ynarea.* "
			     + " from biz_world_country cinfo,ynarea where short_chinese_name = #{country_name} "
				 + " order by dist desc ) ta where dist <= #{max_distance} ";
@Select(COUNTRY_NEIGHBOR_BYPROVINCE_SQL)
List<AreaNeighborVo> findNeihborByProvince(@Param("province_name")String provinceName,
			@Param("country_name")String countryName,@Param("max_distance")Double maxDistance);

        这个查询相邻的方法有三个参数,第一个参数是目标省份,比如云南省,第二个参数是国家中文简称,第三个参数的距离参数。求解相应的国家和对应的省份的面距离,最后根据距离值来进行识别。在求解面和面的距离时,需要注意的是,两个面的最短距离时计算最近的两个点的位置。

2、API接口实现

        有了基础查询函数之后,我们可以对外开放一个列表查询接口和页面跳转方法。关键的代码如下:

@RequiresPermissions("eq:miandianyn:map")
@GetMapping("/miandianyn")
public String miandianyn(){
    return prefix + "/miandianyn";
}
    
@RequiresPermissions("eq:miandianyn:list")
@GetMapping("/miandianyn/list")
@ResponseBody
public AjaxResult miandianynList(){
    List<AreaNeighborVo> countries = areaService.findNeihborByProvince("云南省", "缅甸", 10000D);
    return AjaxResult.success().put("data", countries);
}

        到此基础数据库查询类与API查询类均已开发完成。下面我们可以使用Leaflet来进行WebGIS空间数据展示。

三、WebGIS可视化实现

        有了空间查询函数以及后台的查询接口之后,下面我们就可以使用Leaflet来开发WebGIS可视化效果。

1、空间面展示

        在进入到页面中时,首先先对空间面数据进行展示。这里使用Leaflet来展示GeoJSON数据。同时结合自定义面颜色。关键代码如下:

function getYunnanData(){
	 $.ajax({  
		  type:"get",  
		  url:prefix + "/miandianyn/list",  
		  data:{},  
		  dataType:"json",  
		  cache:false,
		  processData:false,
		  success:function(result){
		     if(result.code == web_status.SUCCESS){
		        showLayerGroup.clearLayers();
		        var legendData = new Array();
		        for(var i = 0;i< result.data.length;i++){
		        	var areaData = result.data[i];
		        	var color = ccolor = getRandomColor();
		        	var areaLayer = L.geoJSON(JSON.parse(areaData.geomJson),{style: {color:ccolor,fillColor:ccolor,weight:3,"opacity":0.65, fillOpacity: 0.65 }}).addTo(mymap); 
		        }
		   },
		    error:function(){
		        $.modal.alertWarning("获取空间信息失败");
		   }
}

        这里先将所有的面数据进行集中展示,这一步的效果如下所示:

2、增加面标注

        为了方便用户在地图上直观的看到各个块表示的区县或者国家信息。可以在地图上增加自定义的名字标绘。这里使用DivMarker的方式进行展示,关键代码如下:

var myIcon = L.divIcon({
		iconSize: null,
		className: '',
		popupAnchor:[5,5],
		shadowAnchor:[5,5],
		html: buildShowInfo(i,color,areaData)
});
//中心点位
L.marker(areaLayer.getBounds().getCenter(), { icon: myIcon}).addTo(showLayerGroup);

function buildShowInfo(index,color,data){
	var result = "<div class='marsBlackPanel' style='background:" + color + ";' animation-spaceInDown><div class='marsBlackPanel-text'>" + (index + 1) + "、" + data.areaName+ "【" + data.type +"】<span class='temperature'></span></div>";
	result += "<div class='marsBlackPanel-text'>"+data.cityName+"<span class='temperature'></span></div>";
	result += "</div>";
	return result;
}

        增加了文字标注后的效果如下:

3、图例展示

         最后为了在地图上直接展示不同的颜色表示的地区信息,即图例展示。还可以在系统中增加动态图例的功能。

legendData.push({
	label: "\xa0\xa0"+areaData.areaName,
	type: "rectangle",
	radius: 12,
	color: color,
	fillColor: color,
	fillOpacity: 0.8,
    weight: 2});

function initLegend(legendData){
	const legend = L.control.Legend({
	     position: "bottomright",
	     collapsed: false,
	     symbolWidth: 35,
	     opacity: 1,
		 title:"图例",
	     column: 2,
	     legends: legendData
	 }).addTo(mymap);
}

        加上了图例后的效果如下:

         在这里,我们可以在Leaflet当中查看缅甸与云南省各区县的相邻关系,将地图放大后可以看到接面的信息,如下图中红色框中的标识所示:

4、与缅甸距离较近的区县信息

         为了方便大家对距离缅甸较近的云南省区县信息有一个直观的展示,这里将空间数据库中的查询结果直接贴出来,方便大家进行查询。

city_name	area_name	type
西双版纳傣族自治州	勐腊县	县
普洱市	孟连傣族拉祜族佤族自治县	自治县
保山市	龙陵县	县
德宏傣族景颇族自治州	芒市	县级市
怒江傈僳族自治州	福贡县	县
临沧市	沧源佤族自治县	自治县
西双版纳傣族自治州	勐海县	县
西双版纳傣族自治州	景洪市	县级市
德宏傣族景颇族自治州	瑞丽市	县级市
保山市	腾冲市	县级市
普洱市	西盟佤族自治县	自治县
临沧市	耿马傣族佤族自治县	自治县
怒江傈僳族自治州	泸水市	市辖区
普洱市	澜沧拉祜族自治县	自治县
德宏傣族景颇族自治州	陇川县	县
临沧市	镇康县	县
怒江傈僳族自治州	贡山独龙族怒族自治县	自治县
德宏傣族景颇族自治州	盈江县	县

        一共有这19个区县。

四、总结

        以上就是本文的主要内容,文章首先介绍如何进行空间距离求解,然后结合PgAdmin来进行空间查询实践,最后使用SpringBoot框架结合PostGIS来详细说明如何进行云南的边防线WebGIS可视化实战。千里边防线漫漫,感谢为我们守护安全的那些人。行文仓促,难免有许多不足之处,如有不足,还恳请各位专家朋友在评论区留言批评指正,不胜感激。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。