基于SpringBoot和PostGIS的世界各国邻国可视化实践

目录

前言

一、空间数据查询基础

1、空间数据库基础

2、空间相邻查询

二、SpringBoot后台功能设计

1、后台查询接口的实现

2、业务接口设计

三、Leaflet进行WebGIS开发

1、整体结构介绍

2、相邻国家展示可视化

四、成果展示

1、印度及其邻国

2、乌克兰及其邻国

3、中东小霸王及其邻国

五、总结


前言

        胸怀祖国,放眼世界。在全球的世界当中,许多国家是陆地相连的,而邻国因为领土争议,是很多国家长期面临的斗争问题,比如朝鲜和韩国的问题,还有印度和巴基斯坦的领土争端问题。通过地理来探索世界,我们来看一下,如何使用WebGIS来对全球的国家基础信息进行查询,快速的通过空间分析来构建一个国家邻国查询的应用,通过空间的角度来看一下不同的国家,它的陆地领土相邻关系。如下图所示:

         本文以SpringBoot框架和PostGIS空间数据库为例,重点讲解如何实现一个国家的邻国查询以及WebGIS可视化应用的实现。文章首先讲解如何在PostGIS数据中进行空间相邻的求解,然后讲解使用Java来开发相应的查询接口,接着介绍在Leaflet当中进行数据的WebGIS展示,最后围绕一些国家及其邻国空间展示为大家做重点的介绍。地图会将故事,通过本文,不仅可以学习如何在SpringBoot中进行GIS的应用开发,而且通过WebGIS来展示我们的地球。如果您对这方面也感兴趣,不妨来看看呢。

一、空间数据查询基础

        在进行相关应用的开发之前,我们首先要对涉及的空间表以及空间查询函数进行介绍。让大家对相关的空间物理结构和空间检索函数有一个充分的认识。因此首先我们先来介绍一下在国家邻国查询的应用中需要使用的数据基础知识。

1、空间数据库基础

        虽然在前面的博文中,这里不再做过多的介绍,将空间表的物理结构给大家进行展示。

CREATE TABLE "public"."biz_world_country" ("pk_id" int8 NOT NULL,"full_english_name" varchar(255) COLLATE "pg_catalog"."default","short_english_name" varchar(255) COLLATE "pg_catalog"."default","min_english_name" varchar(50) COLLATE "pg_catalog"."default","full_chinese_name" varchar(255) COLLATE "pg_catalog"."default","short_chinese_name" varchar(255) COLLATE "pg_catalog"."default","continent" varchar(50) COLLATE "pg_catalog"."default","unreg" varchar(50) COLLATE "pg_catalog"."default","geom" "public"."geometry",CONSTRAINT "pk_biz_world_contry" PRIMARY KEY ("pk_id")
);
CREATE INDEX "idx_biz_world_country_continent" ON "public"."biz_world_country" USING btree ("continent" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
);
CREATE INDEX "idx_biz_world_country_geom" ON "public"."biz_world_country" USING gist ("geom" "public"."gist_geometry_ops_2d"
);
CREATE INDEX "idx_biz_world_country_min_englis" ON "public"."biz_world_country" USING btree ("min_english_name" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
);
COMMENT ON COLUMN "public"."biz_world_country"."pk_id" IS 'pk_id';
COMMENT ON COLUMN "public"."biz_world_country"."full_english_name" IS '英文全称';
COMMENT ON COLUMN "public"."biz_world_country"."short_english_name" IS '英文简称';
COMMENT ON COLUMN "public"."biz_world_country"."min_english_name" IS '最简名称';
COMMENT ON COLUMN "public"."biz_world_country"."full_chinese_name" IS '中文全称';
COMMENT ON COLUMN "public"."biz_world_country"."short_chinese_name" IS '中文简称';
COMMENT ON COLUMN "public"."biz_world_country"."continent" IS '所属大洲,如Asia';
COMMENT ON COLUMN "public"."biz_world_country"."unreg" IS '大洲详情';
COMMENT ON COLUMN "public"."biz_world_country"."geom" IS 'geom';
COMMENT ON TABLE "public"."biz_world_country" IS '世界国家信息表';

        以上就是全球国家信息表的主表物理结构和SQL管理语句。下面来看一下数据库中的数据,如下图所示:

select * from biz_world_country t;

2、空间相邻查询

        介绍完空间表结构和相应的表结构之后,我们再来介绍一下如何实现上述的需求,如何利用空间函数来进行国家以及其邻国的求解运算。这里我们使用PostGIS空间数据库为例,基于PostGIS来介绍如何进行相邻求解。要想实现求解这个需求,其实方法较多,最简单的方法就是直接利用相邻函数,在数据库中可以使用ST_Touches(Geometry geom1,Geometry geom2)。这里我们对这个ST_Touches函数来进行简单的介绍。掌握这个函数是求解空间相邻的关键。                        boolean ST_Touches( raster rastA , raster rastB );来看一下这个函数的介绍。如果raster RastA在空间上接触raster rastB,则返回TRUE。这意味着Rasta和rastB至少有一个共同点,但它们的内部并不相交。如果未提供波段编号(或设置为空),则在测试中仅考虑栅格的凸包。如果提供了波段编号,则在测试中只考虑那些有值的像素(不考虑NODATA)。

         国家相邻的概念与上述的需求一致,即两个面至少有一个共同点,即认为国家相邻。因此我们就使用这个函数来进行相邻国家的求解。首先基于PgAdmin来进行空间查询的结果展示。查询语句如下所示,这里以欧洲国家德国为例:

SELECTpk_id,short_english_name,min_english_name,full_chinese_name,continent,geom,st_asgeojson ( geom ) geomJson 
FROMbiz_world_country 
WHEREpk_id = 1843094270664282114 
UNION
SELECTother_c.pk_id,other_c.short_english_name,other_c.min_english_name,other_c.full_chinese_name,other_c.continent,other_c.geom,st_asgeojson ( other_c.geom ) geomJson 
FROMbiz_world_country AS target_cJOIN biz_world_country AS other_c ON ST_Touches ( target_c.geom, other_c.geom ) 
WHEREtarget_c.pk_id = 1843094270664282114

        前面的数据是查询当前国家,后面是查询跟所属国家相邻的国家的信息,包括空间坐标信息。在数据库中运行以上的sql后可以在下面看到执行的数据。

        可以点击空间结果字段可以在PgAdmin中进行空间数据的查看,如下所示:

        当然,您也可以直接在查询客户端中进行数据的查询,但是明显是不够方便的。而且,我们的终端用户更加不方便,需要使用Web的界面来进行操作和查询。因为需要我们基于PostGIS空间数据库来进行相关功能的开发。

二、SpringBoot后台功能设计

        在进行空间业务数据库表的介绍之后,下面来具体介绍如何使用SpringBoot来进行相关的业务实现。这一块其实比较简单,主要是提供后台的检索接口,为前台提供根据国家来查询所有相邻国家的功能。

1、后台查询接口的实现

        为了便于对空间数据库的操作,这里以Mybatis-Plus进行介绍。由于需要使用自定义的SQL查询来实现,因此这里我们需要自定义查询脚本。可以在Mapper接口中进行相关的查询定义。关键代码如下所示:

static final String NEIGHBOR_COUNTRY_BYID = "<script>"+ " SELECT pk_id,short_english_name,min_english_name,full_chinese_name,continent," + " st_asgeojson(geom) geomJson FROM biz_world_country where pk_id = #{id} union "+ " SELECT other_c.pk_id,other_c.short_english_name,other_c.min_english_name, "+ " other_c.full_chinese_name,other_c.continent,st_asgeojson(other_c.geom) geomJson "+ " FROM biz_world_country AS target_c JOIN biz_world_country AS other_c "+ " ON ST_Touches(target_c.geom, other_c.geom) "+ " where target_c.pk_id = #{id} "+ "</script>";
/**
* - 根据国家主键ID查询邻国列表 add by 夜郎ling in 2024-10-31
* @param id 查询国家ID
* @return 该国对应的邻国列表
*/
@Select(NEIGHBOR_COUNTRY_BYID)
List<WorldCountries> findNeighborCountryById(@Param("id")Long id);

2、业务接口设计

        业务层其实非常简单,就是在service中调用mapper层中的方法,即上一节中分享的方法,获取指定国家的邻国信息。这里分享业务接口的实现,业务接口包含两个方法,第一个是跳转到相应的地图界面,另外一个是查询接口。下面给出相应的实现代码:

@RequiresPermissions("eq:nearcountry:map")
@GetMapping("/nearcountry")
public String nearCountry(){return prefix + "/nearcountry";
}@RequiresPermissions("eq:nearcountry:list")
@GetMapping("/nearcountry/list/{id}")
@ResponseBody
public AjaxResult nearCountryList(@PathVariable("id") Long id){List<WorldCountries> countries = wCountryService.findNeighborCountryById(id);return AjaxResult.success().put("data", countries);
}

        以上就是java后台接口的相关实现。在介绍完后台的实现后,接下来看一下如何进行WebGIS界面开发。

三、Leaflet进行WebGIS开发

        本节将重点介绍如何在Leaflet当中如何进行WebGIS开发,根据一个国家查询该国对应的所有邻国,并且将所有国家信息在页面上进行相应的标注。通过这最后一节,将让大家对邻国查询有一个直观的掌握。

1、整体结构介绍

        为了很好的进行国家和邻国展示,需要对国家列表进行展示。这里我们采用sidebar来进行表格展示,同时在列表中支持国家的定位查询,通过点击国家来查找对应国家的所有邻国。整体来说,分为左右结构。表格的初始化代码如下:

function initSidebar(){//初始化sidebar页面var sidebar = L.control.sidebar('sidebar', {position: 'right'}).addTo(mymap);//默认sidebar打开,并展示一个tab页sidebar.open();$("#xz_info").addClass("active");$("#home").addClass("active");//初始化行政区划表格initWorldCountryTable();
}function initWorldCountryTable(){var options = {url: prefix + "/list",createUrl: prefix + "/add",updateUrl: prefix + "/edit/{id}",modalName: "全球国家列表",columns: [{checkbox: true},{field: 'pkId',title: '',visible: false},{field: 'shortChineseName',title: '名称',formatter: function(value, row, index) {return row.shortChineseName + "(" + row.minEnglishName + ")";}},{title: '操作',align: 'center',formatter: function(value, row, index) {var actions = [];actions.push('<a class="btn btn-success btn-xs ' + editFlag + '" href="javascript:void(0)" onclick="previewTown(\'' + row.pkId + '\',\''+row.fullChineseName+'\',\''+row.shortEnglishName+'\')"><i class="fa fa-paper-plane"></i>邻国</a>');return actions.join('');}}]};$.table.init(options);
}

2、相邻国家展示可视化

        当选择一个国家之后,会将国家的数据库编号进行空间查询,调用空间函数来进行查询。将相邻的国家查询出来,查询的结果是一个列表,因此我们需要使用list来进行循环获取。

function previewTown(gid,cnName,enName){$.ajax({  type:"get",  url:prefix + "/nearcountry/list/" + gid,  data:{},  dataType:"json",  cache:false,processData:false,success:function(result){if(result.code == web_status.SUCCESS){showLayerGroup.clearLayers();for(var i = 0;i< result.data.length;i++){var countryData = result.data[i];var color = gid == countryData.pkId ? "" : getRandomColor();var ccolor = gid == countryData.pkId ? "red" : color;var areaLayer = L.geoJSON(JSON.parse(countryData.geomJson),{style: {color:ccolor,weight:6,"opacity":0.85}}).addTo(mymap);var myIcon = L.divIcon({iconSize: null,className: '',popupAnchor:[5,5],shadowAnchor:[5,5],html: "<div class='marsBlackPanel' style='background:" + color + ";' animation-spaceInDown><div class='marsBlackPanel-text'>" + countryData.fullChineseName+"<span class='temperature'></span></div><div class='marsBlackPanel-text'>"+countryData.shortEnglishName+"<span class='temperature'></span></div></div>"});showLayerGroup.addLayer(areaLayer);//中心点位L.marker(areaLayer.getBounds().getCenter(), { icon: myIcon}).addTo(showLayerGroup);}mymap.fitBounds(showLayerGroup.getBounds());}},error:function(){$.modal.alertWarning("获取空间信息失败");}});
}

        从以上代码中可以看到,我们使用for循环来进行国家和空间信息的展示。请注意在上述的代码中,有一个生成随机颜色的方法,代码如下:

function getRandomColor() {var letters = '0123456789ABCDEF';var color = '#';for (var i = 0; i < 6; i++) {color += letters[Math.floor(Math.random() * 16)];}return color;
}

        到这里,基本我们就完成了所有的如何进行邻国和邻国空间查询求解的过程。从最开始的空间数据库的基础查询、到springboot后台计算、到leaflet的前端生成。下面我们来看一下实际的效果。

四、成果展示

        经过了前面的编码环节,我们基本掌握了如何进行国家的展示以及如何进行空间相邻的求解。最后我们来看一下实际的效果,结合一些实际的国家信息和邻国信息来进行深入介绍。

1、印度及其邻国

        首先来看看我们的邻居,印度。印度位于印度洋,是亚洲一个国家。看看它有哪些邻国呢?首先来看一下其自身空间位置及邻国信息,如下图所示:

        通过上图可知,与印度相邻的国家有缅甸、中国、孟加拉国、不丹、尼泊尔、巴基斯坦。印度不仅与我国有边界争端,与巴基斯坦同样有争端问题。克什米尔一直是两国一道难以逾越的坎。我国与印度的领土争端也有,最近双方后撤,希望是好消息。

2、乌克兰及其邻国

        俄乌战争一直在持续,当然这里无异于对战争进行评论,这里仅对乌克兰及其邻国进行相关的介绍。也让大家对使用gis的视角来对空间冲突有所了解。乌克兰是欧洲国家,是这两年的战争焦点。下面随着WebGIS来看一下乌克兰的位置和其邻国信息吧。

        可以看到,与乌克兰相邻的国家有俄罗斯、白俄罗斯 、摩尔多瓦、匈牙利、波兰、斯洛伐克。

3、中东小霸王及其邻国

        再来看一个最近经常上榜而且很热闹的地区和国家。这个国家就是我们熟悉的中东小霸王,以色列。那是一言不合就开干,最近经常上新闻榜。这里来看一些它的区位和邻国信息。

        可以看到,以色列周边都是阿拉伯国家,比如埃及、约旦、黎巴嫩、叙利亚。最近、黎巴嫩和以色列的冲突一直持续。

五、总结

        以上就是本文的主要内容,本文以SpringBoot框架和PostGIS空间数据库为例,重点讲解如何实现一个国家的邻国查询以及WebGIS可视化应用的实现。文章首先讲解如何在PostGIS数据中进行空间相邻的求解,然后讲解使用Java来开发相应的查询接口,接着介绍在Leaflet当中进行数据的WebGIS展示,最后围绕一些国家及其邻国空间展示为大家做重点的介绍。地图会将故事,通过本文,不仅可以学习如何在SpringBoot中进行GIS的应用开发,而且通过WebGIS来展示我们的地球。行文仓促,定有许多不足支持,如有不足,还恳请各位专家朋友在评论区留下真知灼见,不胜感激。

        站在巨人的肩膀上,更能看得高,看得远。博文编写过程中参考以下文献,在此表示感谢:

1、RT_ST_Touches介绍。

2、【PostGIS入门】三、空间关系与空间连接。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/461766.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python之groupby()及aggregate()方法

目录 数据准备df.describe()思考1 分组 pd.groupby()思考2 df.aggregate()思考1 现在有一份titanic_train.csv&#xff0c;包含泰坦尼克号乘客信息及获救情况的明细数据&#xff0c;我们需要使用一些聚合函数&#xff0c;统计相关指标。 数据准备 import pandas as pd df pd.…

Unity 二次元三渲二

三渲二 注意&#xff1a;Unity必须是2022.3LTS及以上和URP项目&#xff01;&#xff01;&#xff01; 下载三渲二插件 【如何将原神的角色导入Unity】全网最细致教程&#xff0c;全程干货。不使用任何收费插件&#xff0c;使用Spring Bone对头发和衣服进行物理模拟。_原神 步…

Unity计算二维向量夹角余弦值和正弦值的优化方法参考

如果不考虑优化问题&#xff0c;计算两个向量的余弦值或者正弦值可以直接使用类似的方法&#xff1a; [SerializeField] Vector2 v1, v2;void Start() {float valCos Mathf.Acos(Vector2.SignedAngle(v1, v2));float valSin Mathf.Asin(Vector2.SignedAngle(v1, v2)); } 但是…

深度|谁在为OpenAI和Anthropic的AI编程竞赛提供“军火”?已赚得盆满钵满

图片来源&#xff1a;Unsplash AI 开发者之所以一致认为编程的重要性&#xff0c;是有原因的&#xff1a;大型语言模型编程能力越强&#xff0c;它回答与软件无关的其他类型问题的能力也越强。 去年秋天&#xff0c;几位 Google 人工智能领导者与初创公司 CEO Jonathan Siddh…

2024年北京市安全员-A证证模拟考试题库及北京市安全员-A证理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年北京市安全员-A证证模拟考试题库及北京市安全员-A证理论考试试题是由安全生产模拟考试一点通提供&#xff0c;北京市安全员-A证证模拟考试题库是根据北京市安全员-A证最新版教材&#xff0c;北京市安全员-A证大…

[ 问题解决篇 ] win11中本地组策略编辑器gpedit.msc打不开(gpedit.msc缺失)

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

前端聊天室页面开发(赛博朋克科技风,内含源码)

肝了一天&#xff0c;经过各种处理美化&#xff0c;肝出来了一个赛博朋克科技风的前端页面&#xff0c;用的原生三件套htmlcssjavascript开发的&#xff0c;本来想是加点功能调用一下gpt接口&#xff0c;但是基本都需要webscoket通信&#xff0c;可惜我js学的不是很深入&#x…

TMDOG的Gin学习笔记_01——初识Gin框架

TMDOG的Gin学习笔记_01——初识Gin框架 博客地址&#xff1a;[TMDOG的博客](https://blog.tmdog114514.icu) 作者自述&#xff1a; 停更太久了&#xff0c;是因为开学了课太多了&#xff0c;并且我一直在准备上篇文章的内容正在coding&#xff0c;就先搁置了更新博客QAQ&…

wsl2.0(windows linux子系统)使用流程

1.什么是wsl wsl指的是windows的linux子系统&#xff0c;最初是wsl1.0&#xff0c;靠windows内核来模拟linux内核&#xff0c;并不运行真正的linux内核&#xff0c;所以有时会有兼容性的问题。 而wsl2.0是基于windows自带的虚拟机功能hyper-v的&#xff0c;它会把设备上的每个…

计算机网络:网络层 —— IPv4 数据报的首部格式

文章目录 IPv4数据报的首部格式IPv4数据报分片生存时间 TTL字段协议字段首部检验和字段 IPv4数据报的首部格式 IPv4 数据报的首部格式及其内容是实现 IPv4 协议各种功能的基础。 在 TCP/IP 标准中&#xff0c;各种数据格式常常以32比特(即4字节)为单位来描述 固定部分&#x…

vue3学习记录-nextTick

vue3学习记录-nextTick 1. 案例场景2. 使用方法2.1 回调方式2.2 async&#xff0c;await 3.原理 1. 案例场景 聊天框实现输入内容&#xff0c;滚动条默认滚到最底部。 <template><div class"chat_box"><div class"chat_list" ref"chat…

Facebook群控策略详解

Facebook群控早在前几年就很火爆了&#xff0c;对于做Facebook营销或者电商的跨境选手来说&#xff0c;这是个不错的提高效率扩大增长的办法。具体来说&#xff0c;Facebook群控是一种通过同时管理多个Facebook账户进行自动化推广活动的方法&#xff0c;它可以实现自动发布帖子…

【私聊记录】最近在忙什么啊?听说你在学人工智能?

小舒&#xff1a;哎&#xff0c;你最近在忙什么啊&#xff1f; 小元&#xff1a;我在学习人工智能呢。 小舒&#xff1a;人工智能&#xff1f;难不难学啊&#xff1f; 小元&#xff1a;不难&#xff0c;找到正确的学习姿势就不难了&#xff01; 小舒&#xff1a;那你为什么想学…

BLE 协议之 L2CAP

目录 一、简介二、L2CAP Protocol 架构1、逻辑信道划分2、信道模式3、设计思想4、帧结构4.1 面向连接信道 B-frame4.2 无连接数据信道包 G-frame4.3 重传/流量控制/流传输模式下的面向连接的信道 S-frame、I-frame4.4 面向连接的通道分为 LE 信用流控模式和增强型信用流控模式 …

『 Linux 』网络传输层 - TCP(二)

文章目录 TCP六个标志位TCP的连接三次握手 四次挥手为什么是三次握手和四次挥手 重传机制 TCP六个标志位 在TCP协议报文的报头中存在一个用于标志TCP报文类型的标志位(不考虑保留标志位),这些标志位以比特位选项的方式存在,即对应标志位为0则表示为假,对应标志位为1则为真; SYN…

安科瑞AMB400分布式光纤测温系统解决方案--远程监控、预警,预防电气火灾

安科瑞戴婷 可找我Acrel-Fanny 安科瑞AMB400电缆分布式光纤测温具有多方面的特点和优势&#xff1a; 工作原理&#xff1a; 基于拉曼散射效应。激光器产生大功率的光脉冲&#xff0c;光在光纤中传播时会产生散射。携带有温度信息的拉曼散射光返回光路耦合器&#xff0c;耦…

Raspberry Pi 树莓派产品系列说明

系列文章目录 前言 随着我们产品线的不断扩展&#xff0c;要了解所有不同的 Raspberry Pi 板可能会让人感到困惑。以下是 Raspberry Pi 型号的高级分类&#xff0c;包括我们的旗舰系列、Zero 系列、计算模块系列和 Pico 微控制器。 Raspberry Pi 电脑分为几个不同的系列&#x…

电阻电容电感为什么通常是10、22、47这些数

电阻电容电感为什么通常是10、22、47这些数 优先数的来源优先数的优点&#xff1a;E24和E96的来源 我们在选择电阻时&#xff0c;经常看到的阻值是33Ohm&#xff0c;4.7KOhm&#xff0c;1KOhm&#xff0c;680Ohm.基本上是以这几个数字开头。 同时在选择电容时&#xff0c;经常看…

以「JIMUMETA元宇宙体验馆」为例,探讨有哪些元宇宙场景?

让我们以「JIMUMETA元宇宙体验馆」为例&#xff0c;深入探讨元宇宙场景中提供的产品与服务。该体验馆由视创云展精心打造&#xff0c;集成了企业主展馆、元宇宙虚拟活动分会场、品牌展示分会场、线上论坛会场以及会议室接待会客等多重功能&#xff0c;旨在全方位满足企业发布会…

在MacOS玩RPG游戏 - RPGViewerPlus

背景知识 由于我一直使用Mac电脑&#xff0c;所以一直对Mac如何玩RPGMV/RPGMZ游戏的方式有进一步的想法。 网上能给出的方案都是自行启动一个HTTP服务进行&#xff0c;进行服务加载。这个方法有效&#xff0c;但兼容性较差。涉及到自定义功能模块的游戏&#xff0c;都会有报错…