基于SpingBoot和PostGIS的神奇北纬30度线及其穿越国家时空可视化

举报
夜郎king 发表于 2024/11/28 12:49:41 2024/11/28
【摘要】 博文主要讲解如何通过结合SpringBoot和PostGIS,可以构建一个强大的时空数据管理与查询系统,重点展示如何进行北纬30度纬线及其穿越国家的空间查询检索。

 目录


前言

一、时空数据库知识

1、全球国家基本信息

2、空间相交求解

二、SpringBoot后台设计与实现

1、Model层的实现

2、控制层的实现

三、Leaflet时空可视化

1、国家信息可视化

2、动态图例的展示

四、总结



前言

        北纬30度纬线,一条神秘而又奇特的纬线,它贯穿了四大文明古国,串联了众多世界知名的历史古迹和自然景观。这条纬线附近有着许多至今无法解释的神秘事件,以及令人叹为观止的自然奇观。首先,北纬30度线穿过了古埃及、古巴比伦、古印度和中国这四大文明古国。这些地区不仅是人类文明的摇篮,也是众多历史奇迹的发源地。例如,古埃及的金字塔群和狮身人面像,古巴比伦的“空中花园”,以及古印度河流域文明的遗迹,都是这条纬线上的璀璨明珠。

        除了这些古文明,北纬30度线还与一些失落的文明有关,如神秘的玛雅文明。玛雅文明以其精美的雕刻、绘画和青铜艺术而闻名,但其突然的消失至今仍是一个谜。在自然景观方面,北纬30度线同样不乏奇观。它既是地球山脉的最高峰——珠穆朗玛峰的所在地,同时也是海底最深处——西太平洋的马里亚纳海沟的藏身之所。此外,世界几大河流,如埃及的尼罗河、伊拉克的幼发拉底河、中国的长江、美国的密西西比河,均在这一纬度线入海。

        北纬30度线还与一些神秘事件相关联,比如百慕大三角区的飞机和船只失踪事件,以及长江断流之谜、四川自贡大批恐龙灭绝之谜等。这些事件增添了北纬30度线的神秘色彩,使其成为探险家和科学家研究的热点。此外,北纬30度线也是地震、火山、海难、空难等自然灾害频发的地带。这可能是因为北纬30度线附近是多个地球板块的交接地带,地壳运动活跃,导致这一区域的自然现象和灾害较为集中。

        综上所述,北纬30度纬线不仅是一条连接古代文明和自然奇观的纬线,也是一条充满神秘事件和自然力量的纬线。它的存在,不断地激发着人们对未知世界的探索和对自然界的敬畏。在这样的背景下,基于SpringBoot和PostGIS的神奇北纬30度线及其穿越国家时空可视化项目应运而生。本文即在此背景之下诞生,博文主要讲解如何通过结合SpringBoot和PostGIS,我们可以构建一个强大的时空数据管理与查询系统,重点展示如何进行北纬30度纬线及其穿越国家的空间查询检索。

一、时空数据库知识

        在介绍北纬30度线及其穿越国家之前,首先我们需要的基础数据是全球所有的国家信息。通过空间函数的求解,计算某条时空线及其相交关系,从而得到我们的分析结果。因此空间数据库是我们的基础,在文章的开始,首先对空间数据表进行介绍。

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"."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 '世界国家信息表';

2、空间相交求解

        要想求解北纬30度纬线及其穿越的国家,要经过一下两步。首先需要构造北纬30度纬线,我们可以使用空间对象构造函数ST_MakeLine,然后ST_MakePoint构造两个经纬度点连成一条线即可。在生成30度纬线之后,如何计算穿越的空间关系。这里需要使用的空间函数是:ST_Intersects,其接收的入参是Geometry或者GeoGraphy。在Navicat中连接PostGIS数据库后,执行以下的SQL来查询北纬30度穿越的国家信息,sql语句如下所示:

SELECT pk_id,short_english_name,min_english_name,short_chinese_name,full_chinese_name,continent,
st_asgeojson(geom) geomJson FROM biz_world_country
where ST_Intersects( ST_SetSRID(ST_MakeLine(ST_MakePoint(-180, 30),ST_MakePoint(180, 30)), 4326), geom );

        在上图的执行结果中可以看到,北纬30度纬线在全球一共穿越了17个国家,分别是阿富汗、阿尔及利亚、中国、埃及、印度、伊朗、伊拉克、以色列、约旦、科威特、利比亚、摩洛哥、尼泊尔、巴基斯坦、沙特阿拉伯、美国、墨西哥。 

二、SpringBoot后台设计与实现

        在了解空间数据表以及空间查询检索的相关实现之后,我们来看一下如何在后台进行相关服务接口的设计与实现。本节将重点参数后台的实现需求。

1、Model层的实现

        本文采用MVC的实现方式,首先讲解Model层的实现。对全球国家信息表有其对应的后台映射实体。代码如下:

package com.yelang.project.extend.earthquake.domain;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.yelang.framework.handler.PgGeometryTypeHandler;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
/**
 * - 世界国家信息
 * @author 夜郎king
 *
 */
@TableName(value = "biz_world_country", autoResultMap = true)
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
public class WorldCountries implements Serializable{
	private static final long serialVersionUID = -5984870862010624612L;
	@TableId(value="pk_id")
	private Long pkId;
	@TableField(value="full_english_name")
	private String fullEnglishName;//英文全称
	@TableField(value="short_english_name")
	private String shortEnglishName;//英文简称
	@TableField(value="min_english_name")
	private String minEnglishName;//最简名称
	@TableField(value="full_chinese_name")
	private String fullChineseName;//中文全称
	@TableField(value="short_chinese_name")
	private String shortChineseName;
	private String continent;//所属大洲,如:Asia
	private String unreg;//大洲详情
	@TableField(typeHandler = PgGeometryTypeHandler.class)
	private String geom;
	@TableField(exist=false)
	private String geomJson;
	public WorldCountries(String fullEnglishName, String shortEnglishName, String minEnglishName,
			String fullChineseName, String shortChineseName, String continent, String unreg, String geom) {
		super();
		this.fullEnglishName = fullEnglishName;
		this.shortEnglishName = shortEnglishName;
		this.minEnglishName = minEnglishName;
		this.fullChineseName = fullChineseName;
		this.shortChineseName = shortChineseName;
		this.continent = continent;
		this.unreg = unreg;
		this.geom = geom;
	}
}

        基于实体类,定义与空间数据库表交互的查询类。代码如下:

final static String LAT30_COUNTRIES_SQL = "<script>"
			+ " SELECT pk_id,short_english_name,min_english_name,short_chinese_name,full_chinese_name,continent," 
			+ " st_asgeojson(geom) geomJson FROM biz_world_country"
			+ " where ST_Intersects( ST_SetSRID(ST_MakeLine(ST_MakePoint(-180, 30),ST_MakePoint(180, 30)), 4326), geom )"
			+ "</script>";	
/**
* - 查询北纬30度线穿越的所有国家列表 add by 夜郎king
* @return
*/
@Select(LAT30_COUNTRIES_SQL)
List<WorldCountries> findLat30Countries();

        其实就是将我们的空间查询SQL放到Mapper实现层中。方便在业务层中进行调用。

2、控制层的实现

        在进行数据层的实现后,基于数据访问层来开发更上层的应用。即API接口,主要是方便前端的调用。由于业务层比较简单,在此仅介绍控制层的实现。控制层对外主要提供两个方法,第一个方法是实现将页面跳转至具体的可视化界面,第二个方法是实现调用穿越国家的信息接口。下面贴出两个具体方法的实现。

@RequiresPermissions("eq:magiclat30:map")
@GetMapping("/magiclat30")
public String magicLat30(){
    return prefix + "/magiclat30";
}
@RequiresPermissions("eq:magiclat30:list")
@GetMapping("/magiclat30/list")
@ResponseBody
public AjaxResult magiclat30List(){
    List<WorldCountries> countries = wCountryService.findLat30Countries();
    return AjaxResult.success().put("data", countries);
}

        在此基础之上,下面我们就可以基于Leafet来展示穿越的国家信息。将在下一节中重点阐述。

三、Leaflet时空可视化

        本节将重点介绍如何基于Leaflet进行时空可视化展示,主要内容有相关国家信息的可视化以及动态图例的生成两个部分。

1、国家信息可视化

        在上一节中,我们开发了一个查询北纬30度纬线穿越的国家信息列表接口。通过这个接口就可以获取所有的国家信息。因此工作的重点就是如何通过接口获取相关信息。关键代码如下所示:

function getMagicLat30Data(){
	$.ajax({  
		 type:"get",  
		 url:prefix + "/magiclat30/list",  
		 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 = ccolor = getRandomColor();
		        	var areaLayer = L.geoJSON(JSON.parse(countryData.geomJson),{style: {color:ccolor,fillColor:ccolor,weight:3,"opacity":0.95}}).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'>" + (i+1) + "、" + countryData.fullChineseName+"<span class='temperature'></span></div><div class='marsBlackPanel-text'>"+countryData.shortEnglishName+"</div></div>"
		        	});
			        showLayerGroup.addLayer(areaLayer);
			        //中心点位
			        L.marker(areaLayer.getBounds().getCenter(), { icon: myIcon}).addTo(showLayerGroup);
			        }
		      }
		 },
		 error:function(){
		     $.modal.alertWarning("获取空间信息失败");
		 }
	});
}

        下面来看一下前端输出的web可视化效果:

        可以看到已经成功的在界面上进行相关国家的空间可视化展示。虽然功能基本满足需求,但是不是一目了然,也就是没有一个清晰的图例,让大家知道具体国家信息以及它的颜色对应关系。因此我们需要动态的创建一个图例对象来进行展示。 

2、动态图例的展示

        为了实现动态图例的展示,需要我们在构建国家信息的同时,动态的来创建图例对象,以及颜色等信息。因此我们需要上述的for循环中加入以下的代码:

function getMagicLat30Data(){
	$.ajax({  
		type:"get",  
		url:prefix + "/magiclat30/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 countryData = result.data[i];
		        	var color = ccolor = getRandomColor();
		        	var areaLayer = L.geoJSON(JSON.parse(countryData.geomJson),{style: {color:ccolor,fillColor:ccolor,weight:3,"opacity":0.95}}).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'>" + (i+1) + "、" + 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);
			        legendData.push({
				           label: "\xa0\xa0"+countryData.shortChineseName,
				           type: "rectangle",
				           radius: 12,
				           color: color,
				           fillColor: color,
				           fillOpacity: 0.6,
				           weight: 2});
		        		}
		        	mymap.fitBounds(showLayerGroup.getBounds());
		        		
		        	legendData.push({
			            label: "\xa0\xa0三十度纬线",
			            type: "polyline",
			            radius: 12,
			            color: "red",
			            fillColor: "red",
			            fillOpacity: 0.6,
			            dashArray: [6, 6],
			            weight: 2});
		        		
		        	initLegend(legendData);
		      }
		  },
		  error:function(){
		        $.modal.alertWarning("获取空间信息失败");
		  }
	});
}

        最后调用图例的展示方法将生成的动态图例展示出来,

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

        下面来看一下加了动态图例生成的实际效果。

        在地图的右下角就出现动态的图例,是不是更加清晰了呢。

四、总结

        以上就是本文的主要内容,博文主要讲解如何通过结合SpringBoot和PostGIS,我们可以构建一个强大的时空数据管理与查询系统,重点展示如何进行北纬30度纬线及其穿越国家的空间查询检索。文章首先介绍使用数据库表的设计与表结构还有空间相交的求解,其次介绍如何在后台进行相应的空间接口开发,最后基于Leaflet介绍如何进行WebGIS的开发与实现。世界很大很奇妙,值得我们去探索。如果您对本文感兴趣,不妨来这里看看。行文仓促,难免有许多不足之处。在此恳请各位专家朋友在评论区批评指正,不胜感激。

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

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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