赞
踩
目录
星垂平野阔,月涌大江流”“晴川历历汉阳树,芳草萋萋鹦鹉洲”……祖国的每一寸土地,都饱含着诗情画意。旅行一定是很多朋友的爱好,有人说:“人生至少要有两次冲动:一场奋不顾身的爱情和一段走就走的旅行。”不知道在看博文的朋友,是否也是一位旅行爱好者呢。
随着后疫情时代的到来,许多人又开始踏上旅行。旅游可以放松自己身心,缓解工作和生活方面的压力.旅行的过程中是不需要有任何的心理负担的,可以使人达到一种完全放松的状况.感受最原始的快乐。旅行的时候不仅可以观赏风景,还可以尝美食,住宾馆,听故事,感受全国各地的饮食文化.增长自己的见识,可以看到更多的人.了解更多的民俗文化,看到更多的景色使自己的内心感到充实。旅游可以开阔眼界,观察到丰富的人文景观,了解各地的文化风俗,饮食习惯和宗教信仰,广交朋友。旅游还可以锤炼人的意志,增加人的智慧,尤其是去一些有挑战性的景区游玩,征服一座山,跨过一条河学会一项新技能,都可以使自己变的更加勇敢。
中华大地,旅游景点众多,那我们国家到底有多少旅游景区呢?在前面的很多博文中,我们讲过如何将空间数据进行入库。那么文本将采用Java语言,重点讲述如何将全国A级风景区数据导入到PostGis数据库中,为后续我们进行旅游资源和旅游路线的推荐和展示打下坚实的基础。如果您也是WebGis的爱好者,可以从本文了解空间数据的入库开发方式,知道空间数据库的设计和操作。
数据说明,本文下载的数据是朋友分享的2023年全国A级风景区数据。数据大小为36MB左右,数据格式shapfile,下面是数据展示。
这里我们采用Qgis对空间数据进行导入前查看。其基础信息如下表所示:
序号 | 参数 | 说明 |
1 | 文件格式 | ESRI Shapefile |
2 | 文件编码 | GBK |
3 | 元素类型 | Point |
4 | 坐标参考系 | EPSG:4326 - WGS 84 |
5 | 数据单位 | 度 |
6 | 数据总数 | 14,847 |
在shp文件中,除了有空间数据的定义,还有属性数据的定义,A级景区shp数据一共有15个字段,详情请看下面的表定义。
序号 | 字段名 | 数据类型 | 长度 |
1 | 景区名称 | String | 254 |
2 | 等级 | String | 254 |
3 | 所属省份 | String | 254 |
4 | 地址 | String | 254 |
5 | 评定时间 | String | 254 |
6 | 发布时间 | String | 254 |
7 | 发布链接 | String | 254 |
8 | lng_GCJ02(高德经度) | Double | 18 |
9 | lat_GCJ02(高德纬度) | Double | 18 |
10 | lng_BD09(百度经度) | Double | 18 |
11 | lat_BD09(百度纬度) | Double | 18 |
12 | lng_WGS84 | Double | 18 |
13 | lat_WGS84 | Double | 18 |
14 | 所属城市 | String | 254 |
15 | 所属区县 | String | 254 |
我们使用qgis对数据进行简单标绘,使用景区名字进行标注,使用景区等级做分类。可以看到如下的分类结果展示。
空间数据库我们采用PostGIS进行存储,这里来简单设计一下如何存储景区数据。完整的景区数据条数在1万5千条左右。因此我们只需要设计一张景区表即可。与其空间属性保持一一对应的关系,我们来看一下数据表的表结构信息。
下面给出风景区空间数据库表的表结构:
- /*==============================================================*/
- /* Table: biz_scenic_spot */
- /*==============================================================*/
- create table biz_scenic_spot (
- id INT8 not null,
- name VARCHAR(255) null,
- level VARCHAR(4) null,
- province VARCHAR(255) null,
- city VARCHAR(255) null,
- area VARCHAR(255) null,
- address VARCHAR(255) null,
- evaluation_time VARCHAR(255) null,
- publish_time VARCHAR(255) null,
- publish_link VARCHAR(255) null,
- lng_GCJ02 VARCHAR(30) null,
- lat_GCJ02 VARCHAR(30) null,
- lng_BD09 VARCHAR(30) null,
- lat_BD09 VARCHAR(30) null,
- lng_WGS84 VARCHAR(30) null,
- lat_WGS84 VARCHAR(30) null,
- geom geometry null,
- constraint PK_BIZ_SCENIC_SPOT primary key (id)
- );
-
- comment on table biz_scenic_spot is
- '全国风景区信息表';
-
- comment on column biz_scenic_spot.id is
- '主键';
-
- comment on column biz_scenic_spot.name is
- '景区名称';
-
- comment on column biz_scenic_spot.level is
- '景区级别';
-
- comment on column biz_scenic_spot.province is
- '所属省份';
-
- comment on column biz_scenic_spot.city is
- '所属城市';
-
- comment on column biz_scenic_spot.area is
- '所属区县';
-
- comment on column biz_scenic_spot.address is
- '地址';
-
- comment on column biz_scenic_spot.evaluation_time is
- '评定时间';
-
- comment on column biz_scenic_spot.publish_time is
- '发布时间';
-
- comment on column biz_scenic_spot.publish_link is
- '发布链接';
-
- comment on column biz_scenic_spot.lng_GCJ02 is
- 'lng_GCJ02';
-
- comment on column biz_scenic_spot.lat_GCJ02 is
- 'lat_GCJ02';
-
- comment on column biz_scenic_spot.lng_BD09 is
- 'lng_BD09';
-
- comment on column biz_scenic_spot.lat_BD09 is
- 'lat_BD09';
-
- comment on column biz_scenic_spot.lng_WGS84 is
- 'lng_WGS84';
-
- comment on column biz_scenic_spot.lat_WGS84 is
- 'lat_WGS84';
为了在后面的应用中应用空间索引,我们在geom字段上创建空间索引,创建语句如下:
- -- ----------------------------
- CREATE INDEX "idx_biz_scenic_spot_geom" ON "public"."biz_scenic_spot" USING gist (
- "geom" "public"."gist_geometry_ops_2d"
- );
这里主要讲解如何使用Java语言将shp数据进行导入到PostGis数据库中,主要采用的组件还是Gdal,如果大家对gdal不太熟悉,可以翻看博主以前的博客,有关于gdal的部署和具体使用方法。下面从代码实现来详细讲解具体的入库过程。后台开发框架采用Springboot,ORM框架采用Mybatis-plus,都是熟悉的组件。如果看博客的朋友对上述框架不是很熟悉,可以先学习一下相关的知识,对于理解和代码掌握有很大的帮助。
示例工程采用MVC三层开发模式,这里只讲解M层,V和C在后续博文中讲解。
- package com.yelang.project.extend.scenicspot.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 wzh
- *
- */
- @TableName(value = "biz_scenic_spot", autoResultMap = true)
- @NoArgsConstructor
- @AllArgsConstructor
- @Setter
- @Getter
- @ToString
- public class ScenicSpot implements Serializable{
- private static final long serialVersionUID = 1830004907219610805L;
-
- @TableId
- private Long id;
-
- private String name;//景区名称
-
- private String level;//景区级别
-
- private String province;//所属省份
-
- private String city;//所属城市
-
- private String area;//所属区县
-
- private String address;//地址
-
- @TableField(value="evaluation_time")
- private String evaluationTime;//评定时间
-
- @TableField(value="publish_time")
- private String publishTime;//发布时间
-
- @TableField(value="publish_link")
- private String publishLink;//发布时间
-
- @TableField(value="lng_GCJ02")
- private String lngGCJ02;
-
- @TableField(value="lat_GCJ02")
- private String latGCJ02;
-
- @TableField(value="lng_BD09")
- private String lngBD09;
-
- @TableField(value="lat_BD09")
- private String latBD09;
-
- @TableField(value="lng_WGS84")
- private String lngWGS84;
-
- @TableField(value="lat_WGS84")
- private String latWGS84;
-
- @TableField(typeHandler = PgGeometryTypeHandler.class)
- private String geom;
-
- @TableField(exist=false)
- private String geomJson;
-
- public ScenicSpot(String name, String level, String province, String city, String area, String address,
- String evaluationTime, String publishTime, String publishLink,String lngGCJ02, String latGCJ02, String lngBD09, String latBD09,
- String lngWGS84, String latWGS84, String geom) {
- super();
- this.name = name;
- this.level = level;
- this.province = province;
- this.city = city;
- this.area = area;
- this.address = address;
- this.evaluationTime = evaluationTime;
- this.publishTime = publishTime;
- this.publishLink = publishLink;
- this.lngGCJ02 = lngGCJ02;
- this.latGCJ02 = latGCJ02;
- this.lngBD09 = lngBD09;
- this.latBD09 = latBD09;
- this.lngWGS84 = lngWGS84;
- this.latWGS84 = latWGS84;
- this.geom = geom;
- }
- }
这里有几个地方要注意的就是,在类最开始定义的地方,@TableName(value = "biz_scenic_spot", autoResultMap = true),这里一定要这么写,否则后续将无法操作geometry数据。其次是@TableField(typeHandler = PgGeometryTypeHandler.class),通过绑定typehandler来设置具体的处理函数。
熟悉Mybatis-Plus(mp)的朋友一定了解ORM操作的三个重要对象之一就是Mapper,相当与对jdbc的封装。下面是mapper的实现:
- package com.yelang.project.extend.scenicspot.mapper;
- import org.apache.ibatis.annotations.Param;
- import org.apache.ibatis.annotations.Select;
- import com.baomidou.mybatisplus.core.mapper.BaseMapper;
- import com.yelang.project.extend.scenicspot.domain.ScenicSpot;
-
- public interface ScenicSpotMapper extends BaseMapper<ScenicSpot>{
- static final String FIND_GEOJSON_SQL="<script>"
- + "select st_asgeojson(geom) as geomJson from biz_scenic_spot "
- + "where id = #{id} "
- + "<if test='null != name'>and name like concat('%', #{name}, '%')</if>"
- + "</script>";
- @Select(FIND_GEOJSON_SQL)
- ScenicSpot findGeoJsonById(@Param("id")Long id,@Param("name")String name);
- }
为了方便做景区数据的批量入库,我们在Mp之上实现serviceimpl,好直接调用其的批量处理方法,示例代码如下:
- package com.yelang.project.extend.scenicspot.service.impl;
- import org.springframework.stereotype.Service;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.yelang.project.extend.scenicspot.domain.ScenicSpot;
- import com.yelang.project.extend.scenicspot.mapper.ScenicSpotMapper;
- import com.yelang.project.extend.scenicspot.service.IScenicSpotService;
- @Service
- public class ScenicSpotServiceImpl extends ServiceImpl<ScenicSpotMapper, ScenicSpot> implements IScenicSpotService{
-
- @Override
- public ScenicSpot findGeoJsonById(Long id) {
- return this.baseMapper.findGeoJsonById(id, null);
- }
- }
这里采用junit测试组件来进行数据入库,首先将调用gdal进行shp数据解析,然后调用service方法进行空间数据入库。这里需要注意的是,要在junit测试方法中注入bean对象,因此,需要在测试bean中使用下面的注解。
- @SpringBootTest
- @RunWith(SpringRunner.class)
- package com.yelang.project;
- import java.util.ArrayList;
- import java.util.List;
- import org.gdal.gdal.gdal;
- import org.gdal.ogr.DataSource;
- import org.gdal.ogr.Feature;
- import org.gdal.ogr.Geometry;
- import org.gdal.ogr.Layer;
- import org.gdal.ogr.ogr;
- import org.gdal.osr.SpatialReference;
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.boot.test.context.SpringBootTest;
- import org.springframework.test.context.junit4.SpringRunner;
- import com.yelang.project.extend.scenicspot.domain.ScenicSpot;
- import com.yelang.project.extend.scenicspot.service.IScenicSpotService;
- @SpringBootTest
- @RunWith(SpringRunner.class)
- public class ImportScenicSpot {
- @Autowired
- private IScenicSpotService scenicSpotService;
-
- @Test
- public void importData() {
- // 指定文件的名字和路径
- String strVectorFile = "C:/BaiduDownload/20230726 A级景点、宗教分布、与非遗空间分布\\2023年全国A级景区数据/2023年全国A级景区数据.shp";
- // 注册所有的驱动
- ogr.RegisterAll();
- gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
- gdal.SetConfigOption("SHAPE_ENCODING", "CP936");
- String strDriverName = "ESRI Shapefile";
- org.gdal.ogr.Driver oDriver = ogr.GetDriverByName(strDriverName);
- if (oDriver == null) {
- System.out.println(strDriverName + " 驱动不可用!\n");
- return;
- }
- DataSource dataSource = oDriver.Open(strVectorFile);
- Layer layer = dataSource.GetLayer(0);
- SpatialReference spatialReference = layer.GetSpatialRef();
- String srid = spatialReference.GetAttrValue("AUTHORITY", 1);
- long featureCount = layer.GetFeatureCount();
- List<ScenicSpot> list = new ArrayList<ScenicSpot>(3000);
- for (int i = 0; i < featureCount; i++) {
- Feature feature = layer.GetFeature(i);
- String name = feature.GetFieldAsString("景区名称");
- String level = feature.GetFieldAsString("等级");
- String province = feature.GetFieldAsString("所属省份");
- String city = feature.GetFieldAsString("所属城市");
- String area = feature.GetFieldAsString("所属区县");
- String address = feature.GetFieldAsString("地址");
- String evaluationTime = feature.GetFieldAsString("评定时间");
- String publishTime = feature.GetFieldAsString("发布时间");
- String publishLink = feature.GetFieldAsString("发布链接");
- String lngGCJ02 = feature.GetFieldAsString("lng_GCJ02");
- String latGCJ02 = feature.GetFieldAsString("lat_GCJ02");
- String lngBD09 = feature.GetFieldAsString("lng_BD09");
- String latBD09 = feature.GetFieldAsString("lat_BD09");
- String lngWGS84 = feature.GetFieldAsString("lng_WGS84");
- String latWGS84 = feature.GetFieldAsString("lat_WGS84");
- Geometry geom = feature.GetGeometryRef();
- //step 1、生成原始wkt
- String wkt = geom.ExportToWkt();
- wkt = "SRID=" + srid +";" + wkt;//拼接srid,实现动态写入
- list.add(new ScenicSpot(name, level, province, city, area, address, evaluationTime, publishTime, publishLink, lngGCJ02, latGCJ02, lngBD09, latBD09, lngWGS84, latWGS84, wkt));
- if(list.size() == 2000) {
- System.out.println("00000000000000");
- scenicSpotService.saveBatch(list,2000);
- list.clear();
- }
- }
- if(list.size() >0) {
- scenicSpotService.saveBatch(list,1000);
- }
- System.out.println("完成!!!");
- dataSource.delete();
- gdal.GDALDestroyDriverManager();
- }
- }
下面我们来运行一下测试代码,试着将数据导入到数据库中,鼠标右键运行。
运行后在控制台可以看到以下输出:
- 20:29:30.821 [main] DEBUG c.y.p.e.s.m.S.insert - [debug,137] - ==> Parameters: 1762817301184356354(Long), 八面山景区(String), 3A(String), 湖南(String), 湘西土家族苗族自治州(String), 龙山县(String), 湖南湘西自治州八面山景区(String), -(String), 发布时间:2022-08-03;统计截至时间:2021年底(String), (String), 109.25780600000(String), 28.83474400000(String), 109.26441070000(String), 28.84042333000(String), 109.25318500000(String), 28.83790594000(String), SRID=4326;POINT(109.253185 28.83790594)(PGgeometry)
- 20:29:30.822 [main] DEBUG c.y.p.e.s.m.S.insert - [debug,137] - ==> Parameters: 1762817301184356355(Long), 湘西自治州花垣县古苗河百瀑大峡谷景区(String), 3A(String), 湖南(String), 湘西土家族苗族自治州(String), 花垣县(String), 湖南湘西自治州湘西自治州花垣县古苗河百瀑大峡谷景区(String), -(String), 发布时间:2022-08-03;统计截至时间:2021年底(String), (String), 109.48161300000(String), 28.58698200000(String), 109.48818110000(String), 28.59279936000(String), 109.47683150000(String), 28.59022625000(String), SRID=4326;POINT(109.4768315 28.59022625)(PGgeometry)
- 20:29:30.822 [main] DEBUG c.y.p.e.s.m.S.insert - [debug,137] - ==> Parameters: 1762817301188550658(Long), 浏阳古风洞(String), 2A(String), 湖南(String), 长沙市(String), 浏阳市(String), 湖南长沙市浏阳古风洞(String), -(String), 发布时间:2022-08-03;统计截至时间:2021年底(String), (String), 113.79441900000(String), 28.21724500000(String), 113.80095370000(String), 28.22317049000(String), 113.78889760000(String), 28.22061438000(String), SRID=4326;POINT(113.7888976 28.22061438)(PGgeometry)
- 20:29:30.822 [main] DEBUG c.y.p.e.s.m.S.insert - [debug,137] - ==> Parameters: 1762817301188550659(Long), 耒阳市农耕文化博物馆旅游景区(String), 2A(String), 湖南(String), 衡阳市(String), 耒阳市(String), 湖南衡阳市耒阳市农耕文化博物馆旅游景区(String), -(String), 发布时间:2022-08-03;统计截至时间:2021年底(String), (String), 112.86089200000(String), 26.42240400000(String), 112.86748910000(String), 26.42806999000(String), 112.85559400000(String), 26.42594269000(String), SRID=4326;POINT(112.855594 26.42594269)(PGgeometry)
- 20:29:30.822 [main] DEBUG c.y.p.e.s.m.S.insert - [debug,137] - ==> Parameters: 1762817301188550660(Long), 耒阳市党史陈列馆(String), 2A(String), 湖南(String), 衡阳市(String), 耒阳市(String), 湖南衡阳市耒阳市党史陈列馆(String), -(String), 发布时间:2022-08-03;统计截至时间:2021年底(String), (String), 112.85569800000(String), 26.40719700000(String), 112.86228240000(String), 26.41286866000(String), 112.85039320000(String), 26.41072176000(String), SRID=4326;POINT(112.8503932 26.41072176)(PGgeometry)
- 完成!!!
最后到数据库中验证数据是否已经成功导入,在客户端中运行以下语句。可以看到数据全部导入,数据总条数是14847条。
以上就是本文的主要内容,那么文本将采用Java语言,重点讲述如何将全国A级风景区数据导入到PostGis数据库中,为后续我们进行旅游资源和旅游路线的推荐和展示打下坚实的基础。如果您也是WebGis的爱好者,可以从本文了解空间数据的入库开发方式,知道空间数据库的设计和操作。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。