第02章 - 环境搭建与快速开始
第02章 - 环境搭建与快速开始
2.1 开发环境准备
2.1.1 Java 环境配置
GeoTools 31.x 需要 Java 17 或更高版本。推荐使用 Eclipse Temurin(原 AdoptOpenJDK)或 Oracle JDK。
Windows 安装步骤:
- 下载 JDK 17:Eclipse Temurin
- 运行安装程序
- 配置环境变量:
:: 设置 JAVA_HOME
setx JAVA_HOME "C:\Program Files\Eclipse Adoptium\jdk-17.0.9.9-hotspot"
:: 添加到 PATH
setx PATH "%PATH%;%JAVA_HOME%\bin"
验证安装:
java -version
# 输出:openjdk version "17.0.9" 2023-10-17
# OpenJDK Runtime Environment Temurin-17.0.9+9 (build 17.0.9+9)
javac -version
# 输出:javac 17.0.9
Linux/macOS 安装:
# Ubuntu/Debian
sudo apt update
sudo apt install openjdk-17-jdk
# macOS (Homebrew)
brew install openjdk@17
# 验证安装
java -version
2.1.2 Maven 安装配置
GeoTools 使用 Maven 进行依赖管理,推荐 Maven 3.8.6 或更高版本。
下载安装:
- 访问 Maven 下载页面
- 下载 Binary zip archive
- 解压到目标目录
配置环境变量:
# Windows
setx M2_HOME "C:\apache-maven-3.9.6"
setx PATH "%PATH%;%M2_HOME%\bin"
# Linux/macOS
export M2_HOME=/opt/apache-maven-3.9.6
export PATH=$M2_HOME/bin:$PATH
验证安装:
mvn -version
# Apache Maven 3.9.6 (bc0240f3c744dd6b6ec2920b3cd08dcc295161ae)
# Maven home: /opt/apache-maven-3.9.6
# Java version: 17.0.9, vendor: Eclipse Adoptium
2.1.3 配置 Maven 仓库
GeoTools 的依赖包托管在 OSGeo Maven 仓库,需要在 settings.xml 或 pom.xml 中配置。
全局配置 (~/.m2/settings.xml):
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-1.0.0.xsd">
<profiles>
<profile>
<id>geotools</id>
<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>
</profile>
</profiles>
<activeProfiles>
<activeProfile>geotools</activeProfile>
</activeProfiles>
<!-- 可选:配置镜像加速 -->
<mirrors>
<mirror>
<id>aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Aliyun Maven Mirror</name>
<url>https://maven.aliyun.com/repository/central</url>
</mirror>
</mirrors>
</settings>
2.1.4 IDE 配置
IntelliJ IDEA 配置
-
安装插件(可选):
- Maven Helper
- SonarLint
-
配置 Maven:
- File → Settings → Build, Execution, Deployment → Build Tools → Maven
- 设置 Maven home path
- 设置 User settings file
-
配置 JDK:
- File → Project Structure → Project
- 选择 JDK 17
-
内存设置:
- Help → Edit Custom VM Options
-Xms512m -Xmx2048m
Eclipse 配置
-
安装 m2e 插件:
- Help → Eclipse Marketplace
- 搜索 "Maven Integration for Eclipse"
-
配置 Maven:
- Window → Preferences → Maven → Installations
- 添加 Maven 安装目录
-
配置 JRE:
- Window → Preferences → Java → Installed JREs
- 添加 JDK 17
2.2 创建 GeoTools 项目
2.2.1 使用 Maven 创建项目
命令行创建:
# 创建项目目录
mkdir geotools-tutorial
cd geotools-tutorial
# 使用 Maven 原型创建项目
mvn archetype:generate \
-DgroupId=com.example.geotools \
-DartifactId=geotools-quickstart \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DarchetypeVersion=1.4 \
-DinteractiveMode=false
2.2.2 完整的 pom.xml 配置
<?xml version="1.0" encoding="UTF-8"?>
<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>com.example.geotools</groupId>
<artifactId>geotools-quickstart</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>GeoTools Quickstart</name>
<description>GeoTools 入门示例项目</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<geotools.version>31.0</geotools.version>
</properties>
<!-- GeoTools 仓库配置 -->
<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>
</repositories>
<!-- 使用 BOM 统一管理版本 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>geotools</artifactId>
<version>${geotools.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- ==================== 核心模块 ==================== -->
<!-- GeoTools 核心 API -->
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-main</artifactId>
</dependency>
<!-- API 定义模块 -->
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-api</artifactId>
</dependency>
<!-- ==================== 数据格式 ==================== -->
<!-- Shapefile 支持 -->
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-shapefile</artifactId>
</dependency>
<!-- GeoJSON 支持 -->
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-geojson</artifactId>
</dependency>
<!-- GeoPackage 支持 -->
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-geopkg</artifactId>
</dependency>
<!-- ==================== 坐标系统 ==================== -->
<!-- 坐标参考系统核心 -->
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-referencing</artifactId>
</dependency>
<!-- EPSG 坐标系数据库(HSQL 实现) -->
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-epsg-hsql</artifactId>
</dependency>
<!-- ==================== 渲染模块 ==================== -->
<!-- 地图渲染引擎 -->
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-render</artifactId>
</dependency>
<!-- Swing GUI 支持 -->
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-swing</artifactId>
</dependency>
<!-- ==================== 数据库支持 ==================== -->
<!-- JDBC 核心 -->
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-jdbc</artifactId>
</dependency>
<!-- PostGIS 支持 -->
<dependency>
<groupId>org.geotools.jdbc</groupId>
<artifactId>gt-jdbc-postgis</artifactId>
</dependency>
<!-- ==================== 测试依赖 ==================== -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
<!-- 可执行 JAR 插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.example.geotools.App</mainClass>
</transformer>
<!-- 合并 SPI 服务文件 -->
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
2.2.3 项目结构
geotools-quickstart/
├── pom.xml
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ └── geotools/
│ │ │ ├── App.java
│ │ │ ├── DataStoreExample.java
│ │ │ ├── GeometryExample.java
│ │ │ └── MapRenderExample.java
│ │ └── resources/
│ │ └── log4j2.xml
│ └── test/
│ └── java/
│ └── com/
│ └── example/
│ └── geotools/
│ └── AppTest.java
└── data/
└── sample/
└── countries.shp
2.3 模块选择指南
2.3.1 按功能选择模块
根据项目需求选择必要的模块:
┌─────────────────────────────────────────────────────────────┐
│ 模块选择决策树 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 需要什么功能? │
│ │ │
│ ├─→ 基础几何处理 │
│ │ └─→ gt-main │
│ │ │
│ ├─→ 读写 Shapefile │
│ │ └─→ gt-main + gt-shapefile │
│ │ │
│ ├─→ 读写 GeoJSON │
│ │ └─→ gt-main + gt-geojson │
│ │ │
│ ├─→ 坐标转换 │
│ │ └─→ gt-referencing + gt-epsg-hsql │
│ │ │
│ ├─→ 地图渲染 │
│ │ └─→ gt-render + gt-referencing │
│ │ │
│ ├─→ 连接 PostGIS │
│ │ └─→ gt-jdbc + gt-jdbc-postgis │
│ │ │
│ ├─→ WMS/WFS 客户端 │
│ │ └─→ gt-wms / gt-wfs-ng │
│ │ │
│ └─→ 空间分析处理 │
│ └─→ gt-process + gt-process-feature │
│ │
└─────────────────────────────────────────────────────────────┘
2.3.2 常用模块组合
基础配置(最小依赖):
<dependencies>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-main</artifactId>
</dependency>
</dependencies>
Shapefile 处理:
<dependencies>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-shapefile</artifactId>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-epsg-hsql</artifactId>
</dependency>
</dependencies>
地图渲染:
<dependencies>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-render</artifactId>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-swing</artifactId>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-epsg-hsql</artifactId>
</dependency>
</dependencies>
数据库访问:
<dependencies>
<dependency>
<groupId>org.geotools.jdbc</groupId>
<artifactId>gt-jdbc-postgis</artifactId>
</dependency>
<!-- PostgreSQL 驱动 -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.6.0</version>
</dependency>
</dependencies>
2.3.3 EPSG 数据库选择
GeoTools 提供多种 EPSG 坐标系数据库实现:
| 模块 | 大小 | 特点 | 适用场景 |
|---|---|---|---|
| gt-epsg-hsql | ~6MB | 完整数据库,启动快 | 通用开发 |
| gt-epsg-wkt | ~2MB | 仅 WKT 定义 | 嵌入式应用 |
| gt-epsg-extension | ~6MB | 支持自定义扩展 | 需要自定义 CRS |
推荐:一般情况下使用 gt-epsg-hsql。
2.4 快速开始示例
2.4.1 几何操作示例
package com.example.geotools;
import org.locationtech.jts.geom.*;
import org.geotools.geometry.jts.JTSFactoryFinder;
/**
* JTS 几何操作示例
*/
public class GeometryExample {
private static final GeometryFactory gf = JTSFactoryFinder.getGeometryFactory();
public static void main(String[] args) {
System.out.println("=== JTS 几何操作示例 ===\n");
// 1. 创建各种几何类型
createGeometries();
// 2. 几何操作
geometryOperations();
// 3. 空间关系判断
spatialRelations();
// 4. 几何度量
geometryMeasurements();
}
private static void createGeometries() {
System.out.println("【创建几何对象】");
// 创建点
Point point = gf.createPoint(new Coordinate(116.4, 39.9));
System.out.println("Point: " + point);
// 创建线
Coordinate[] lineCoords = {
new Coordinate(0, 0),
new Coordinate(10, 10),
new Coordinate(20, 5)
};
LineString line = gf.createLineString(lineCoords);
System.out.println("LineString: " + line);
// 创建多边形
Coordinate[] polyCoords = {
new Coordinate(0, 0),
new Coordinate(10, 0),
new Coordinate(10, 10),
new Coordinate(0, 10),
new Coordinate(0, 0) // 闭合点
};
Polygon polygon = gf.createPolygon(polyCoords);
System.out.println("Polygon: " + polygon);
// 从 WKT 创建
try {
WKTReader reader = new WKTReader(gf);
Geometry geom = reader.read("POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))");
System.out.println("从 WKT 创建: " + geom.getGeometryType());
} catch (Exception e) {
e.printStackTrace();
}
System.out.println();
}
private static void geometryOperations() {
System.out.println("【几何操作】");
// 创建两个多边形
Polygon poly1 = gf.createPolygon(new Coordinate[]{
new Coordinate(0, 0),
new Coordinate(10, 0),
new Coordinate(10, 10),
new Coordinate(0, 10),
new Coordinate(0, 0)
});
Polygon poly2 = gf.createPolygon(new Coordinate[]{
new Coordinate(5, 5),
new Coordinate(15, 5),
new Coordinate(15, 15),
new Coordinate(5, 15),
new Coordinate(5, 5)
});
// 缓冲区
Geometry buffer = poly1.buffer(2);
System.out.println("缓冲区面积: " + buffer.getArea());
// 合并
Geometry union = poly1.union(poly2);
System.out.println("合并面积: " + union.getArea());
// 相交
Geometry intersection = poly1.intersection(poly2);
System.out.println("相交面积: " + intersection.getArea());
// 差集
Geometry difference = poly1.difference(poly2);
System.out.println("差集面积: " + difference.getArea());
// 凸包
Geometry convexHull = poly1.convexHull();
System.out.println("凸包: " + convexHull);
// 质心
Point centroid = poly1.getCentroid();
System.out.println("质心: " + centroid);
System.out.println();
}
private static void spatialRelations() {
System.out.println("【空间关系判断】");
Polygon outer = gf.createPolygon(new Coordinate[]{
new Coordinate(0, 0),
new Coordinate(20, 0),
new Coordinate(20, 20),
new Coordinate(0, 20),
new Coordinate(0, 0)
});
Point inside = gf.createPoint(new Coordinate(10, 10));
Point outside = gf.createPoint(new Coordinate(30, 30));
Polygon overlapping = gf.createPolygon(new Coordinate[]{
new Coordinate(15, 15),
new Coordinate(25, 15),
new Coordinate(25, 25),
new Coordinate(15, 25),
new Coordinate(15, 15)
});
// 空间关系判断
System.out.println("outer.contains(inside): " + outer.contains(inside));
System.out.println("outer.contains(outside): " + outer.contains(outside));
System.out.println("inside.within(outer): " + inside.within(outer));
System.out.println("outer.intersects(overlapping): " + outer.intersects(overlapping));
System.out.println("outer.disjoint(outside): " + outer.disjoint(outside));
System.out.println("outer.overlaps(overlapping): " + outer.overlaps(overlapping));
System.out.println();
}
private static void geometryMeasurements() {
System.out.println("【几何度量】");
Polygon polygon = gf.createPolygon(new Coordinate[]{
new Coordinate(0, 0),
new Coordinate(10, 0),
new Coordinate(10, 10),
new Coordinate(0, 10),
new Coordinate(0, 0)
});
LineString line = gf.createLineString(new Coordinate[]{
new Coordinate(0, 0),
new Coordinate(3, 4)
});
Point p1 = gf.createPoint(new Coordinate(0, 0));
Point p2 = gf.createPoint(new Coordinate(3, 4));
System.out.println("多边形面积: " + polygon.getArea());
System.out.println("多边形周长: " + polygon.getLength());
System.out.println("线长度: " + line.getLength());
System.out.println("两点距离: " + p1.distance(p2));
System.out.println("包围盒: " + polygon.getEnvelopeInternal());
}
}
2.4.2 读取 Shapefile 示例
package com.example.geotools;
import org.geotools.api.data.FileDataStore;
import org.geotools.api.data.FileDataStoreFinder;
import org.geotools.api.data.Query;
import org.geotools.api.data.SimpleFeatureSource;
import org.geotools.api.feature.simple.SimpleFeature;
import org.geotools.api.feature.simple.SimpleFeatureType;
import org.geotools.api.filter.Filter;
import org.geotools.api.filter.FilterFactory;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.factory.CommonFactoryFinder;
import org.locationtech.jts.geom.Geometry;
import java.io.File;
import java.io.IOException;
/**
* Shapefile 读取示例
*/
public class ShapefileReadExample {
public static void main(String[] args) {
File file = new File("data/sample/countries.shp");
if (!file.exists()) {
System.out.println("请准备示例 Shapefile 文件: " + file.getAbsolutePath());
return;
}
try {
// 基本读取
basicRead(file);
// 带过滤条件读取
filteredRead(file);
// 属性投影读取
projectedRead(file);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 基本读取
*/
private static void basicRead(File file) throws IOException {
System.out.println("=== 基本读取 ===\n");
// 打开数据源
FileDataStore store = FileDataStoreFinder.getDataStore(file);
SimpleFeatureSource source = store.getFeatureSource();
// 获取要素类型信息
SimpleFeatureType schema = source.getSchema();
System.out.println("要素类型名称: " + schema.getTypeName());
System.out.println("坐标参考系: " + schema.getCoordinateReferenceSystem().getName());
System.out.println("属性数量: " + schema.getAttributeCount());
System.out.println("几何属性: " + schema.getGeometryDescriptor().getLocalName());
// 打印所有属性
System.out.println("\n属性列表:");
schema.getAttributeDescriptors().forEach(attr -> {
System.out.printf(" - %s: %s%n",
attr.getLocalName(),
attr.getType().getBinding().getSimpleName());
});
// 读取要素
SimpleFeatureCollection collection = source.getFeatures();
System.out.println("\n要素总数: " + collection.size());
// 遍历前 5 个要素
System.out.println("\n前 5 个要素:");
int count = 0;
try (SimpleFeatureIterator features = collection.features()) {
while (features.hasNext() && count < 5) {
SimpleFeature feature = features.next();
Geometry geom = (Geometry) feature.getDefaultGeometry();
System.out.printf(" %s - 几何类型: %s, 顶点数: %d%n",
feature.getID(),
geom.getGeometryType(),
geom.getNumPoints());
count++;
}
}
// 关闭数据源
store.dispose();
System.out.println();
}
/**
* 带过滤条件读取
*/
private static void filteredRead(File file) throws IOException {
System.out.println("=== 过滤读取 ===\n");
FileDataStore store = FileDataStoreFinder.getDataStore(file);
SimpleFeatureSource source = store.getFeatureSource();
// 创建过滤器工厂
FilterFactory ff = CommonFactoryFinder.getFilterFactory();
// 创建属性过滤器(假设有 NAME 属性)
Filter filter = ff.equals(ff.property("NAME"), ff.literal("China"));
// 应用过滤器
SimpleFeatureCollection filtered = source.getFeatures(filter);
System.out.println("过滤后要素数: " + filtered.size());
try (SimpleFeatureIterator features = filtered.features()) {
while (features.hasNext()) {
SimpleFeature feature = features.next();
System.out.println("找到: " + feature.getAttribute("NAME"));
}
}
store.dispose();
System.out.println();
}
/**
* 属性投影读取(只读取部分属性)
*/
private static void projectedRead(File file) throws IOException {
System.out.println("=== 属性投影读取 ===\n");
FileDataStore store = FileDataStoreFinder.getDataStore(file);
SimpleFeatureSource source = store.getFeatureSource();
// 创建查询,只读取指定属性
Query query = new Query(source.getSchema().getTypeName());
query.setPropertyNames("the_geom", "NAME"); // 只读取几何和 NAME 属性
query.setMaxFeatures(10); // 限制返回数量
SimpleFeatureCollection collection = source.getFeatures(query);
System.out.println("查询返回要素数: " + collection.size());
try (SimpleFeatureIterator features = collection.features()) {
while (features.hasNext()) {
SimpleFeature feature = features.next();
System.out.printf(" %s: %s%n",
feature.getID(),
feature.getAttribute("NAME"));
}
}
store.dispose();
}
}
2.4.3 坐标转换示例
package com.example.geotools;
import org.geotools.api.referencing.FactoryException;
import org.geotools.api.referencing.crs.CoordinateReferenceSystem;
import org.geotools.api.referencing.operation.MathTransform;
import org.geotools.api.referencing.operation.TransformException;
import org.geotools.geometry.jts.JTS;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.geotools.referencing.CRS;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Point;
/**
* 坐标转换示例
*/
public class CRSTransformExample {
public static void main(String[] args) {
try {
// 1. 基本坐标转换
basicTransform();
// 2. 几何对象转换
geometryTransform();
// 3. 常用坐标系信息
crsInfo();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 基本坐标转换
*/
private static void basicTransform() throws FactoryException, TransformException {
System.out.println("=== 基本坐标转换 ===\n");
// 定义源和目标坐标系
CoordinateReferenceSystem sourceCRS = CRS.decode("EPSG:4326"); // WGS84
CoordinateReferenceSystem targetCRS = CRS.decode("EPSG:3857"); // Web Mercator
System.out.println("源坐标系: " + sourceCRS.getName());
System.out.println("目标坐标系: " + targetCRS.getName());
// 创建转换器
MathTransform transform = CRS.findMathTransform(sourceCRS, targetCRS, true);
// 转换坐标(北京)
double[] srcCoord = {116.4074, 39.9042}; // 经度, 纬度
double[] dstCoord = new double[2];
transform.transform(srcCoord, 0, dstCoord, 0, 1);
System.out.println("\n北京坐标转换:");
System.out.printf(" WGS84: (%.4f, %.4f)%n", srcCoord[0], srcCoord[1]);
System.out.printf(" Web Mercator: (%.2f, %.2f)%n", dstCoord[0], dstCoord[1]);
// 反向转换
MathTransform inverseTransform = transform.inverse();
double[] backCoord = new double[2];
inverseTransform.transform(dstCoord, 0, backCoord, 0, 1);
System.out.printf(" 反向转换: (%.4f, %.4f)%n", backCoord[0], backCoord[1]);
System.out.println();
}
/**
* 几何对象转换
*/
private static void geometryTransform() throws FactoryException, TransformException {
System.out.println("=== 几何对象转换 ===\n");
GeometryFactory gf = JTSFactoryFinder.getGeometryFactory();
// 创建 WGS84 坐标的点
Point wgs84Point = gf.createPoint(new Coordinate(116.4074, 39.9042));
// 获取转换器
CoordinateReferenceSystem sourceCRS = CRS.decode("EPSG:4326");
CoordinateReferenceSystem targetCRS = CRS.decode("EPSG:32650"); // UTM Zone 50N
MathTransform transform = CRS.findMathTransform(sourceCRS, targetCRS, true);
// 转换几何
Geometry utmPoint = JTS.transform(wgs84Point, transform);
System.out.println("WGS84 点: " + wgs84Point);
System.out.println("UTM Zone 50N 点: " + utmPoint);
// 转换坐标
Coordinate srcCoord = new Coordinate(116.4074, 39.9042);
Coordinate dstCoord = JTS.transform(srcCoord, null, transform);
System.out.printf("\n坐标转换: (%.4f, %.4f) -> (%.2f, %.2f)%n",
srcCoord.x, srcCoord.y, dstCoord.x, dstCoord.y);
System.out.println();
}
/**
* 常用坐标系信息
*/
private static void crsInfo() throws FactoryException {
System.out.println("=== 常用坐标系信息 ===\n");
String[] epsgCodes = {"EPSG:4326", "EPSG:3857", "EPSG:4490", "EPSG:32650"};
for (String code : epsgCodes) {
CoordinateReferenceSystem crs = CRS.decode(code);
System.out.println(code + ":");
System.out.println(" 名称: " + crs.getName());
System.out.println(" WKT 前100字符: " + crs.toWKT().substring(0,
Math.min(100, crs.toWKT().length())) + "...");
System.out.println();
}
}
}
2.4.4 地图显示示例
package com.example.geotools;
import org.geotools.api.data.FileDataStore;
import org.geotools.api.data.FileDataStoreFinder;
import org.geotools.api.data.SimpleFeatureSource;
import org.geotools.api.style.Style;
import org.geotools.map.FeatureLayer;
import org.geotools.map.Layer;
import org.geotools.map.MapContent;
import org.geotools.styling.SLD;
import org.geotools.swing.JMapFrame;
import java.awt.Color;
import java.io.File;
/**
* 地图显示示例
*/
public class MapDisplayExample {
public static void main(String[] args) throws Exception {
// 打开 Shapefile
File file = new File("data/sample/countries.shp");
if (!file.exists()) {
System.out.println("请准备示例数据文件: " + file.getAbsolutePath());
System.out.println("可以从 Natural Earth (naturalearthdata.com) 下载国家边界数据");
return;
}
FileDataStore store = FileDataStoreFinder.getDataStore(file);
SimpleFeatureSource featureSource = store.getFeatureSource();
// 创建地图内容
MapContent map = new MapContent();
map.setTitle("GeoTools 地图显示示例");
// 创建样式
Style style = SLD.createPolygonStyle(
Color.BLUE, // 边框颜色
Color.CYAN, // 填充颜色
0.5f // 透明度
);
// 创建图层并添加到地图
Layer layer = new FeatureLayer(featureSource, style);
map.addLayer(layer);
// 显示地图窗口
JMapFrame.showMap(map);
}
}
2.5 常见问题排查
2.5.1 依赖下载问题
问题:无法下载 GeoTools 依赖
Could not resolve dependencies for project: Could not find artifact
org.geotools:gt-main:jar:31.0 in central
解决方案:
- 确认
pom.xml中添加了 OSGeo 仓库 - 检查网络连接
- 清理本地仓库缓存:
mvn dependency:purge-local-repository
mvn clean install
2.5.2 EPSG 数据库问题
问题:找不到 EPSG 代码
org.geotools.referencing.factory.FactoryNotFoundException:
No factory found for EPSG:4326
解决方案:
添加 EPSG 数据库依赖:
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-epsg-hsql</artifactId>
</dependency>
2.5.3 SPI 服务加载问题
问题:打成 JAR 后无法运行
java.lang.IllegalArgumentException: No DataStoreFactory found for parameters
解决方案:
使用 maven-shade-plugin 并配置 ServicesResourceTransformer:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
</configuration>
</plugin>
2.5.4 内存问题
问题:OutOfMemoryError
解决方案:
增加 JVM 内存:
# 运行时
java -Xms512m -Xmx2g -jar your-app.jar
# Maven 编译时
export MAVEN_OPTS="-Xms512m -Xmx2g"
mvn clean install
2.5.5 日志配置
添加 log4j2.xml 配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Logger name="org.geotools" level="INFO"/>
<Logger name="org.geotools.data" level="DEBUG"/>
<Root level="INFO">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
2.6 本章小结
本章介绍了 GeoTools 开发环境的搭建:
-
环境准备
- JDK 17+ 安装配置
- Maven 3.8.6+ 安装配置
- OSGeo 仓库配置
-
项目创建
- Maven 项目结构
- pom.xml 完整配置
- 模块选择指南
-
快速示例
- 几何操作
- Shapefile 读取
- 坐标转换
- 地图显示
-
问题排查
- 依赖问题
- EPSG 问题
- 内存配置
关键要点
- 使用 Maven BOM 统一管理 GeoTools 版本
- 必须配置 OSGeo Maven 仓库
- 根据需求选择必要的模块
- 使用 gt-epsg-hsql 提供坐标系支持
- 注意 SPI 服务文件的合并
下一步
在下一章中,我们将深入了解 GeoTools 的核心架构和模块设计。

浙公网安备 33010602011771号