本系列文章主要参考GeoTools官网的13个示例GeoTools Tutorials,做一简化阐述以及扩展。在第一节Quickstart中,我们主要讲述一下Maven Quickstart这个示例讲解,其他的实例大家可以参照官网做进一步学习。另外,为了降低学习成本,本系列课程的摒弃了QGIS、UDig等可视化工具,而是通过本篇文章提到的JMapFrame
框架展示处理结果。
本实例主要用到的数据为官网提供的实例数据1:50m Cultural Vectors。
本示例采用自行编译的19.1的版本。大家可以根据实际情况决定使用的版本。pom文件内容如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.surpass</groupId>
<artifactId>geotools</artifactId>
<version>0.0.1-SNAPSHOT</version>
<url>http://maven.apache.org</url>
<!--定义的常量-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<geotools.version>19.1</geotools.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-shapefile</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-swing</artifactId>
<version>${geotools.version}</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>osgeo</id>
<name>OSGeo Release Repository</name>
<url>https://repo.osgeo.org/repository/release/</url>
<snapshots><enabled>false</enabled></snapshots>
<releases><enabled>true</enabled></releases>
</repository>
<repository>
<id>osgeo-snapshot</id>
<name>OSGeo Snapshot Repository</name>
<url>https://repo.osgeo.org/repository/snapshot/</url>
<snapshots><enabled>true</enabled></snapshots>
<releases><enabled>false</enabled></releases>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<inherited>true</inherited>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
需要指出的一点是: 我们正常的maven仓库(比如
alimaven
、repo2
)并没有提供关于GeoTools的jar包,所以,这里需要指定GeoTools相关依赖包的中心仓库。当然,我这里是自行编译的版本,所以这里可以没有repositories
的相关配置。
package cn.curpass.geotools.quickstart;
import java.io.File;
import org.geotools.data.FileDataStore;
import org.geotools.data.FileDataStoreFinder;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.map.FeatureLayer;
import org.geotools.map.Layer;
import org.geotools.map.MapContent;
import org.geotools.styling.SLD;
import org.geotools.styling.Style;
import org.geotools.swing.JMapFrame;
import org.geotools.swing.data.JFileDataStoreChooser;
public class Quickstart {
public static void main(String[] args) throws Exception {
// 选择一个shp文件
File file = JFileDataStoreChooser.showOpenFile("shp", null);
if (file == null) {
return;
}
//加载shp图层数据源
FileDataStore store = FileDataStoreFinder.getDataStore(file);
SimpleFeatureSource featureSource = store.getFeatureSource();
// 创建一个地图容器
MapContent map = new MapContent();
map.setTitle("Quickstart");
//创建一个简单的样式,并将样式和shp数据源加载到一个图层上
Style style = SLD.createSimpleStyle(featureSource.getSchema());
Layer layer = new FeatureLayer(featureSource, style);
//在地图容器添加图层
map.addLayer(layer);
// 展示地图
JMapFrame.showMap(map);
}
}
这段代码读起来并不困难,需要注意一点是,我们所说的矢量图层主要记录的是图形的坐标信息,如果要做图形化渲染,还需要一个SLD的样式文件。在这个文件里,主要记录了一些样式信息。比如:
另外可以针对shp要素的属性信息有区别化的渲染要素信息。比如,对于一个面状的中国地图,可以通过省份的字段针对不用省份显示不同的颜色。
虽然这段代码简单,我还是想画一个图,方便大家记忆:
此时,我们运行程序,选择对应的shp文件(这里需要注意的是我们需要选择以shp为后缀名的shp文件)。通过GeoTools提供的界面按钮我们可以对显示图形做放大、缩小、平移等操作。
通过上诉程序我们知道,必须选择以“shp”为后缀名的文件,否则会报空指针异常。所以我们做的一个优化是通过选择一个文件后,我们会自动查找相同路径、相同文件名字并且以“shp”结尾的文件。
private static File findShpFile(File file){
if(file.getName().toLowerCase().endsWith(".shp")){
return file;
}
String path = file.getAbsolutePath();
String shpPath = path.substring(0,path.lastIndexOf(".")) + ".shp";
File shpFile = new File(shpPath);
if(!shpFile.exists()){
throw new RuntimeException("当前文件夹不存在以shp结尾的文件");
}
return shpFile;
}
在实际的开发过程中,通过选择本地shp文件创建FileDataStore
的情况还是不多的,更多的情况是连接到数据库(比如postGis)或者 Web 功能服务器(Geoserver)。此时我们需要另外一种方式创建FileDataStore
,即DataStoreFinder
,代码如下:
File file = JFileDataStoreChooser.showOpenFile("shp", null);
Map<String, Object> params = new HashMap<>();
params.put("url", file.toURI().toURL());
params.put("create spatial index", false);
params.put("memory mapped buffer", false);
params.put("charset", "ISO-8859-1");
DataStore store = DataStoreFinder.getDataStore(params);
SimpleFeatureSource featureSource = store.getFeatureSource(store.getTypeNames()[0]);
通过上面的代码我们发现,通过传递一个Map,而这个Map有一个key为url,就是配置多种数据源的。到这里,有可能有人有疑问了,这只有一个URL,如果连接数据库涉及到的用户名或者密码怎么办?如果是Web 功能服务器需要传递一些认证信息怎么办?这里就体现了这里设计思想的强大之处,通过一个Map,传递不同的参数。也为后面的多数据源提供了强大的扩展性。下面我们主要以PostGis为例,说明一下GeoTools怎么配置数据库的数据源。
上面的实例只是简单的说明了配置其他的数据源,需要配置postgis数据源还是有点复杂。
要增加如下的依赖
<dependency>
<groupId>org.geotools.jdbc</groupId>
<artifactId>gt-jdbc-postgis</artifactId>
<version>${geotools.version}</version>
</dependency>
/**
* 通过PostGis获取FeatureSource
* @param host ip地址
* @param port 端口号
* @param database 需要连接的数据库
* @param userName 用户名
* @param password 密码
* @param tableName 需要连接的表名
* @return
*/
public static SimpleFeatureSource connAndGetFeatureSource(
String host, String port, String database,
String userName,String password, String tableName) {
Map<String, Object> params = new HashMap<String, Object>(8);
//需要连接何种数据库,postgis
params.put(PostgisNGDataStoreFactory.DBTYPE.key, "postgis");
//ip地址
params.put(PostgisNGDataStoreFactory.HOST.key, host);
//端口号
params.put(PostgisNGDataStoreFactory.PORT.key, new Integer(port));
//需要连接的数据库
params.put(PostgisNGDataStoreFactory.DATABASE.key, database);
//架构
params.put(PostgisNGDataStoreFactory.SCHEMA.key, "public");
//需要连接数据库的名称
params.put(PostgisNGDataStoreFactory.USER.key, userName);
//数据库的密码
params.put(PostgisNGDataStoreFactory.PASSWD.key, password);
try {
//获取存储空间
DataStore pgDataStore = DataStoreFinder.getDataStore(params);
//根据表名获取source
return pgDataStore.getFeatureSource(tableName);
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
public class QuickStart {
public static void main(String[] args) throws IOException {
SimpleFeatureSource featureSource = getFeatureSourceByPostGis();
MapContent map = new MapContent();
map.setTitle("Quickstart");
Style style = SLD.createSimpleStyle(featureSource.getSchema());
Layer layer = new FeatureLayer(featureSource, style);
map.addLayer(layer);
JMapFrame.showMap(map);
}
private static SimpleFeatureSource getFeatureSourceByPostGis() {
String ip = "192.168.10.201";
String port = "5432";
String database = "nyc";
String userName = "postgres";
String password = "postgres";
String tableName = "nyc_neighborhoods";
return PostGisUtil.connAndGetFeatureSource(
ip, port, database, userName, password, tableName);
}
}