1. 概述

本文将带你快速掌握 GeoTools 开源 Java 库的基础用法——处理地理空间数据的利器。该库提供了符合标准的地理信息系统(GIS)实现方法,并支持众多开放地理空间联盟(OGC)标准。

当 OGC 发布新标准时,GeoTools 总能快速跟进实现,使其成为地理空间开发的不二之选。

2. 依赖配置

我们需要在 pom.xml 中添加 GeoTools 依赖。由于这些依赖不在 Maven 中央仓库,还需额外声明仓库地址:

<repositories>
    <repository>
        <id>osgeo</id>
        <name>开放地理空间基金会仓库</name>
        <url>http://download.osgeo.org/webdav/geotools/</url>
    </repository>
    <repository>
        <id>opengeo</id>
        <name>OpenGeo Maven 仓库</name>
        <url>http://repo.opengeo.org</url>
    </repository>
</repositories>

随后添加核心依赖:

<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-shapefile</artifactId>
    <version>28.1</version>
</dependency>
<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-epsg-hsql</artifactId>
    <version>28.1</version>
</dependency>

3. GIS 与 Shapefile

要玩转 GeoTools,得先了解地理信息系统和 Shapefile 的基本概念。

3.1. GIS 基础

处理地理数据离不开地理信息系统(GIS)。它主要用于呈现、捕获、存储、操作、分析或管理地理数据

地理数据的核心是空间数据——指向地球上的具体位置。空间数据通常伴随着属性数据(如城市名称、人口等)。

✅ 示例:城市数据中

  • 空间数据:城市经纬度坐标
  • 属性数据:城市名称、人口数量

3.2. Shapefile 格式

地理空间数据主要有两种格式:栅格和矢量。本文聚焦矢量数据(点、线、多边形)。

⚠️ Shapefile 是存储矢量数据的行业标准文件格式,兼容几乎所有 GIS 软件。使用 GeoTools 可以轻松创建包含城市、学校、地标等要素的 Shapefile。

4. 创建地理要素

GeoTools 文档定义:要素是地图上可绘制的对象(如城市、地标)。创建后可保存为 Shapefile。

4.1. 存储地理数据

创建要素前需准备地理数据(经纬度坐标)和属性数据(名称)。这些数据可从 simplemaps.commaxmind.com 等网站获取。

将城市坐标存入 Map 对象:

private static void addToLocationMap(
  String name,
  double lat,
  double lng,
  Map<String, List<Double>> locations) {
    List<Double> coordinates = new ArrayList<>();
    coordinates.add(lat);
    coordinates.add(lng);
    locations.put(name, coordinates);
}

填充数据示例:

Map<String, List<Double>> locations = new HashMap<>();

addToLocationMap("曼谷", 13.752222, 100.493889, locations);
addToLocationMap("纽约", 53.083333, -0.15, locations);
addToLocationMap("开普敦", -33.925278, 18.423889, locations);
addToLocationMap("悉尼", -33.859972, 151.211111, locations);
addToLocationMap("渥太华", 45.420833, -75.69, locations);
addToLocationMap("开罗", 30.07708, 31.285909, locations);

实际项目中可通过 CSV 解析器替代硬编码数据。

4.2. 定义要素类型

创建要素前必须定义其类型。GeoTools 提供两种方式:

  1. 使用 DataUtilities 简单创建:

    SimpleFeatureType TYPE = DataUtilities.createType(
    "Location", "location:Point:srid=4326," + "name:String");
    
  2. 使用 SimpleFeatureTypeBuilder 灵活配置(推荐): ```java SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder(); builder.setName("Location"); builder.setCRS(DefaultGeographicCRS.WGS84);

builder .add("Location", Point.class); .length(15) .add("Name", String.class);

SimpleFeatureType CITY = builder.buildFeatureType();


⚠️ 两种方式存储相同信息:
- 城市位置 → `Point` 类型
- 城市名称 → `String` 类型

❌ 要素类型变量(如 `TYPE`/`CITY`)创建后不可修改,建议全大写命名强调其不可变性。

### 4.3. 要素创建与集合

准备好要素类型和数据后,开始创建要素:

1. 初始化构建器:
```java
SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(CITY);
  1. 创建存储集合:

    DefaultFeatureCollection collection = new DefaultFeatureCollection();
    
  2. 创建坐标点(需 GeometryFactory):

    GeometryFactory geometryFactory
    = JTSFactoryFinder.getGeometryFactory(null);
    

也可创建 LinePolygon 等几何类型

  1. 转换函数:将坐标转为要素

    private static Function<Map.Entry<String, List<Double>>, SimpleFeature>
    toFeature(SimpleFeatureType CITY, GeometryFactory geometryFactory) {
     return location -> {
         Point point = geometryFactory.createPoint(
            new Coordinate(location.getValue()
              .get(0), location.getValue().get(1)));
    
         SimpleFeatureBuilder featureBuilder
           = new SimpleFeatureBuilder(CITY);
         featureBuilder.add(point);
         featureBuilder.add(location.getKey());
         return featureBuilder.buildFeature(null);
     };
    }
    
  2. 生成要素并存入集合:

    locations.entrySet().stream()
    .map(toFeature(CITY, geometryFactory))
    .forEach(collection::add);
    

现在 collection 包含所有城市要素。

5. 创建数据存储

GeoTools 的 DataStore API 用于表示地理空间数据源(文件/数据库/服务)。通过 DataStoreFactory 创建存储要素的 DataStore

  1. 定义输出文件:

    File shapeFile = new File(
    new File(".").getAbsolutePath() + "shapefile.shp");
    
  2. 配置参数(文件路径 + 空间索引):

    Map<String, Serializable> params = new HashMap<>();
    params.put("url", shapeFile.toURI().toURL());
    params.put("create spatial index", Boolean.TRUE);
    
  3. 创建数据存储: ```java ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();

ShapefileDataStore dataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params); dataStore.createSchema(CITY);


## 6. 写入 Shapefile

最后一步:使用 **Transaction 接口**安全写入文件。该接口支持:
- ✅ 提交(`commit`)写入成功的数据
- ❌ 回滚(`rollback`)失败操作

```java
Transaction transaction = new DefaultTransaction("create");

String typeName = dataStore.getTypeNames()[0];
SimpleFeatureSource featureSource
  = dataStore.getFeatureSource(typeName);

if (featureSource instanceof SimpleFeatureStore) {
    SimpleFeatureStore featureStore
      = (SimpleFeatureStore) featureSource;

    featureStore.setTransaction(transaction);
    try {
        featureStore.addFeatures(collection);
        transaction.commit();

    } catch (Exception problem) {
        transaction.rollback();
    } finally {
        transaction.close();
    }
}

⚠️ 关键点:

  • SimpleFeatureSource 用于只读
  • SimpleFeatureStore 用于读写
  • 通过 instanceof 检查写入权限(官方推荐做法)

生成的 Shapefile 可在任何支持该格式的 GIS 查看器中打开。

7. 总结

本文展示了使用 GeoTools 进行地理空间开发的核心流程。虽然示例简单,但可扩展用于创建丰富的 Shapefile 文件。

❗ 记住:

  • GeoTools 是持续更新的活跃库
  • 本文仅作入门引导
  • 库不仅支持矢量数据,同样适用于栅格数据处理

踩坑提示:实际项目中注意版本兼容性和坐标参考系统(CRS)配置!


原始标题:Introduction to GeoTools | Baeldung

« 上一篇: EthereumJ 入门指南
» 下一篇: Jukito 简介