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.com 或 maxmind.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 提供两种方式:
使用
DataUtilities
简单创建:SimpleFeatureType TYPE = DataUtilities.createType( "Location", "location:Point:srid=4326," + "name:String");
使用
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);
创建存储集合:
DefaultFeatureCollection collection = new DefaultFeatureCollection();
创建坐标点(需
GeometryFactory
):GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null);
也可创建
Line
或Polygon
等几何类型
转换函数:将坐标转为要素
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); }; }
生成要素并存入集合:
locations.entrySet().stream() .map(toFeature(CITY, geometryFactory)) .forEach(collection::add);
现在 collection
包含所有城市要素。
5. 创建数据存储
GeoTools 的 DataStore API 用于表示地理空间数据源(文件/数据库/服务)。通过 DataStoreFactory
创建存储要素的 DataStore
。
定义输出文件:
File shapeFile = new File( new File(".").getAbsolutePath() + "shapefile.shp");
配置参数(文件路径 + 空间索引):
Map<String, Serializable> params = new HashMap<>(); params.put("url", shapeFile.toURI().toURL()); params.put("create spatial index", Boolean.TRUE);
创建数据存储: ```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)配置!