第03章 - 核心架构解析
第03章 - 核心架构解析
3.1 项目结构概览
3.1.1 包结构
OGU4J采用清晰的分层架构,各包职责明确:
com.znlgis.ogu4j
├── datasource # 数据源工具层
│ ├── OguLayerUtil # 统一的图层读写工具
│ └── GtTxtUtil # 国土TXT格式工具
├── engine # GIS引擎核心层
│ ├── enums # 枚举类型定义
│ ├── io # 读写器接口
│ ├── model # 数据模型
│ │ └── layer # 图层模型
│ └── util # 引擎工具类
├── exception # 异常处理层
├── geometry # 几何处理层
└── utils # 通用工具层
3.1.2 层次依赖关系
┌─────────────────────────────────────────────────────────────┐
│ datasource (数据源工具层) │
│ OguLayerUtil, GtTxtUtil │
├─────────────────────────────────────────────────────────────┤
│ engine (引擎核心层) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ GisEngine │ │ LayerReader│ │ LayerWriter │ │
│ │ Factory │ │ Interface │ │ Interface │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ model (数据模型) │ │
│ │ OguLayer, OguFeature, OguField, OguFieldValue │ │
│ └─────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ util (引擎工具) │ │
│ │ CrsUtil, ShpUtil, PostgisUtil, OgrUtil │ │
│ └─────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ geometry (几何处理) │ exception (异常) │ utils (工具) │
│ GeometryUtil │ OguException │ ZipUtil │
│ │ 及其子类 │ EncodingUtil │
└─────────────────────────────────────────────────────────────┘
3.2 核心模块详解
3.2.1 datasource - 数据源工具层
这是面向开发者的顶层API,提供最简洁的数据访问接口。
OguLayerUtil
统一的图层读写工具类,是使用OGU4J最常用的入口:
/**
* 数据源工具类,提供统一的图层读写接口
* 屏蔽底层引擎差异,简化开发者调用
*/
public class OguLayerUtil {
/**
* 读取图层
* @param dataFormatType 数据格式类型
* @param path 数据路径(文件路径或连接字符串)
* @param layerName 图层名称
* @param attributeFilter 属性过滤条件(CQL表达式)
* @param spatialFilter 空间过滤条件(WKT格式)
* @param engineType 使用的GIS引擎
* @return 统一的OguLayer对象
*/
public static OguLayer readLayer(
DataFormatType dataFormatType,
String path,
String layerName,
String attributeFilter,
String spatialFilter,
GisEngineType engineType
);
/**
* 写入图层
* @param dataFormatType 数据格式类型
* @param layer 要写入的图层
* @param path 输出路径
* @param layerName 图层名称
* @param options 额外选项
* @param engineType 使用的GIS引擎
*/
public static void writeLayer(
DataFormatType dataFormatType,
OguLayer layer,
String path,
String layerName,
Map<String, Object> options,
GisEngineType engineType
);
}
设计思想:
- 统一入口:所有格式读写都通过同一方法
- 参数标准化:使用枚举确保类型安全
- 引擎透明:开发者无需了解底层引擎细节
GtTxtUtil
专门处理国土TXT坐标格式的工具类:
/**
* 国土TXT坐标文件处理工具
* 支持自然资源部门的标准TXT格式
*/
public class GtTxtUtil {
/**
* 读取TXT文件
* @param txtPath TXT文件路径
* @param options 读取选项
* @return 图层对象
*/
public static OguLayer loadTxt(String txtPath, Map<String, Object> options);
/**
* 保存为TXT文件
* @param layer 图层对象
* @param txtPath 输出路径
* @param metadata 元数据信息
* @param options 保存选项
* @param zoneNumber 带号
*/
public static void saveTxt(
OguLayer layer,
String txtPath,
OguLayerMetadata metadata,
Map<String, Object> options,
int zoneNumber
);
}
3.2.2 engine - 引擎核心层
引擎层是OGU4J的核心,实现了双引擎架构。
引擎接口设计
/**
* GIS引擎接口
* 定义了所有引擎必须实现的操作
*/
public interface GisEngine {
/**
* 获取图层读取器
*/
LayerReader getReader();
/**
* 获取图层写入器
*/
LayerWriter getWriter();
/**
* 获取引擎类型
*/
GisEngineType getEngineType();
/**
* 检查引擎是否可用
*/
boolean isAvailable();
}
引擎工厂
/**
* GIS引擎工厂
* 负责创建和管理引擎实例
*/
public class GisEngineFactory {
// 引擎缓存
private static final Map<GisEngineType, GisEngine> engines = new HashMap<>();
/**
* 获取引擎实例
* @param engineType 引擎类型
* @return 引擎实例
*/
public static GisEngine getEngine(GisEngineType engineType) {
return engines.computeIfAbsent(engineType, type -> {
switch (type) {
case GEOTOOLS:
return new GeoToolsEngine();
case GDAL:
return new GdalEngine();
default:
throw new EngineNotSupportedException("不支持的引擎类型: " + type);
}
});
}
/**
* 获取默认引擎
*/
public static GisEngine getDefaultEngine() {
return getEngine(GisEngineType.GEOTOOLS);
}
}
GeoTools引擎实现
/**
* GeoTools引擎实现
*/
public class GeoToolsEngine implements GisEngine {
private final GeoToolsLayerReader reader;
private final GeoToolsLayerWriter writer;
public GeoToolsEngine() {
this.reader = new GeoToolsLayerReader();
this.writer = new GeoToolsLayerWriter();
}
@Override
public LayerReader getReader() {
return reader;
}
@Override
public LayerWriter getWriter() {
return writer;
}
@Override
public GisEngineType getEngineType() {
return GisEngineType.GEOTOOLS;
}
@Override
public boolean isAvailable() {
return true; // GeoTools是纯Java实现,始终可用
}
}
GDAL引擎实现
/**
* GDAL引擎实现
*/
public class GdalEngine implements GisEngine {
private static boolean initialized = false;
public GdalEngine() {
initGdal();
}
private synchronized void initGdal() {
if (!initialized) {
try {
gdal.AllRegister();
initialized = true;
} catch (Exception e) {
throw new EngineNotSupportedException("GDAL初始化失败", e);
}
}
}
@Override
public boolean isAvailable() {
return initialized;
}
// ... 其他实现
}
3.2.3 model - 数据模型层
数据模型是OGU4J的核心抽象,位于engine.model包中。
模型类关系图
┌─────────────────────────────────────────────────────────────────┐
│ OguLayer │
│ - name: String │
│ - wkid: Integer │
│ - geometryType: GeometryType │
│ - fields: List<OguField> │
│ - features: List<OguFeature> │
│ - metadata: OguLayerMetadata │
├─────────────────────────────────────────────────────────────────┤
│ + validate(): void │
│ + filter(OguFeatureFilter): List<OguFeature> │
│ + getFeatureCount(): int │
│ + toJSON(): String │
│ + fromJSON(String): OguLayer │
└─────────────────────────────────────────────────────────────────┘
│
│ 1:n
▼
┌─────────────────────────────────────────────────────────────────┐
│ OguFeature │
│ - fid: String │
│ - wkt: String │
│ - attributes: Map<String, OguFieldValue> │
├─────────────────────────────────────────────────────────────────┤
│ + getValue(String): Object │
│ + setValue(String, Object): void │
│ + getAttribute(String): OguFieldValue │
└─────────────────────────────────────────────────────────────────┘
│
│ 1:n
▼
┌─────────────────────────────────────────────────────────────────┐
│ OguFieldValue │
│ - value: Object │
├─────────────────────────────────────────────────────────────────┤
│ + getStringValue(): String │
│ + getIntValue(): Integer │
│ + getDoubleValue(): Double │
│ + getDateValue(): Date │
└─────────────────────────────────────────────────────────────────┘
为什么使用WKT存储几何
OGU4J选择使用WKT(Well-Known Text)格式存储几何数据,这是一个深思熟虑的设计决策:
| 方案 | 优点 | 缺点 |
|---|---|---|
| JTS Geometry对象 | 直接使用,无需转换 | 与JTS强耦合 |
| 二进制WKB | 存储效率高 | 不便调试 |
| WKT字符串 | 跨库兼容、易读、易于序列化 | 存储稍大 |
WKT作为国际标准格式,可以轻松与任何GIS库交互。
3.2.4 geometry - 几何处理层
GeometryUtil是几何处理的核心类,提供两套API:
/**
* 几何处理工具类
* 基于JTS和ESRI Geometry API
*/
public class GeometryUtil {
// ========== 基于JTS Geometry对象的方法 ==========
// 格式转换
public static Geometry wkt2Geometry(String wkt);
public static String geometry2Wkt(Geometry geom);
// 空间关系
public static boolean intersects(Geometry a, Geometry b);
public static boolean contains(Geometry a, Geometry b);
// 空间分析
public static Geometry buffer(Geometry geom, double distance);
public static Geometry intersection(Geometry a, Geometry b);
// ========== 基于WKT字符串的方法(使用ESRI API) ==========
// 空间关系
public static boolean intersectsWkt(String wktA, String wktB, int wkid);
public static boolean containsWkt(String wktA, String wktB, int wkid);
// 空间分析
public static String bufferWkt(String wkt, int wkid, double distance);
public static String intersectionWkt(String wktA, String wktB, int wkid);
}
两套API的设计理由:
- JTS方法:适合需要多次操作几何对象的场景
- WKT方法:适合简单场景,避免对象转换开销
3.2.5 exception - 异常处理层
OGU4J设计了层次化的异常体系:
/**
* OGU4J基础异常
*/
public class OguException extends RuntimeException {
public OguException(String message) {
super(message);
}
public OguException(String message, Throwable cause) {
super(message, cause);
}
}
/**
* 数据源异常 - 数据读写相关错误
*/
public class DataSourceException extends OguException {
// 文件不存在、连接失败等
}
/**
* 格式解析异常 - 数据格式相关错误
*/
public class FormatParseException extends OguException {
// WKT解析错误、JSON格式错误等
}
/**
* 引擎不支持异常 - 引擎功能限制
*/
public class EngineNotSupportedException extends OguException {
// GDAL未安装、格式不支持等
}
/**
* 图层验证异常 - 数据完整性错误
*/
public class LayerValidationException extends OguException {
// 字段缺失、几何无效等
}
/**
* 拓扑异常 - 几何拓扑错误
*/
public class TopologyException extends OguException {
// 自相交、环未闭合等
}
3.2.6 utils - 通用工具层
提供与GIS无关的通用工具:
// ZIP工具
public class ZipUtil {
public static void zip(File folder, String zipPath);
public static void zip(File folder, String zipPath, Charset charset);
public static void unzip(String zipPath, String destPath);
public static void unzip(String zipPath, String destPath, Charset charset);
}
// 编码检测工具
public class EncodingUtil {
public static Charset getFileEncoding(File file);
}
// 自然排序工具
public class SortUtil {
public static int compareString(String s1, String s2);
}
// 数字工具
public class NumUtil {
public static String getPlainString(double value);
}
3.3 设计模式应用
3.3.1 工厂模式
GisEngineFactory使用工厂模式创建引擎实例:
// 工厂模式 - 根据类型创建对应的引擎
GisEngine engine = GisEngineFactory.getEngine(GisEngineType.GEOTOOLS);
优点:
- 封装对象创建逻辑
- 支持引擎缓存复用
- 便于扩展新引擎
3.3.2 策略模式
引擎切换使用策略模式:
// 策略模式 - 不同策略(引擎)可互换
OguLayer layer = OguLayerUtil.readLayer(
DataFormatType.SHP,
path,
null, null, null,
GisEngineType.GEOTOOLS // 策略1
// GisEngineType.GDAL // 策略2
);
优点:
- 算法(引擎实现)与使用分离
- 运行时动态切换
- 符合开闭原则
3.3.3 模板方法模式
Reader和Writer使用模板方法:
// LayerReader接口定义了读取模板
public interface LayerReader {
OguLayer read(DataFormatType format, String path,
String layerName, String attrFilter,
String spatialFilter);
}
// 各实现类提供具体实现
public class GeoToolsLayerReader implements LayerReader {
@Override
public OguLayer read(...) {
// GeoTools特定实现
}
}
3.3.4 建造者模式
OguLayer支持链式构建:
// 建造者模式示例
OguLayer layer = new OguLayer();
layer.setName("示例图层")
.setWkid(4490)
.setGeometryType(GeometryType.POLYGON);
3.4 扩展点设计
3.4.1 添加新引擎
要添加新的GIS引擎,需要:
- 实现
GisEngine接口 - 实现
LayerReader和LayerWriter - 在
GisEngineFactory中注册
// 1. 实现引擎接口
public class NewEngine implements GisEngine {
@Override
public LayerReader getReader() { ... }
@Override
public LayerWriter getWriter() { ... }
@Override
public GisEngineType getEngineType() {
return GisEngineType.NEW_ENGINE;
}
}
// 2. 在工厂中注册
case NEW_ENGINE:
return new NewEngine();
3.4.2 添加新数据格式
要支持新的数据格式:
- 在
DataFormatType中添加枚举值 - 在对应引擎的Reader/Writer中实现处理逻辑
// 1. 添加格式枚举
public enum DataFormatType {
SHP, GEOJSON, FILEGDB, POSTGIS,
NEW_FORMAT // 新格式
}
// 2. 在Reader中处理
case NEW_FORMAT:
return readNewFormat(path, layerName);
3.4.3 添加新几何操作
在GeometryUtil中添加新方法:
/**
* 新增几何操作
*/
public static Geometry newOperation(Geometry geom, Object params) {
// 使用JTS或ESRI API实现
}
/**
* WKT版本
*/
public static String newOperationWkt(String wkt, Object params) {
// WKT版本实现
}
3.5 线程安全性
3.5.1 线程安全的类
- GeometryUtil:所有方法都是无状态的静态方法,线程安全
- CrsUtil:使用synchronized确保线程安全
- GisEngineFactory:使用ConcurrentHashMap,线程安全
3.5.2 非线程安全的类
- OguLayer:数据容器,不保证线程安全
- OguFeature:数据容器,不保证线程安全
- GeoToolsLayerReader/Writer:非线程安全,建议每次操作创建新实例
3.5.3 并发使用建议
// 推荐:在多线程环境中为每个任务创建独立的Layer
ExecutorService executor = Executors.newFixedThreadPool(4);
for (String shpFile : shpFiles) {
executor.submit(() -> {
// 每个线程读取自己的图层
OguLayer layer = OguLayerUtil.readLayer(
DataFormatType.SHP, shpFile,
null, null, null,
GisEngineType.GEOTOOLS
);
// 处理...
});
}
3.6 性能考量
3.6.1 引擎选择
| 场景 | 推荐引擎 | 理由 |
|---|---|---|
| 一般用途 | GeoTools | 稳定、纯Java |
| 大量数据 | GDAL | 性能更好 |
| FileGDB | GDAL | GeoTools不支持 |
| 跨平台部署 | GeoTools | 无需本地库 |
3.6.2 内存优化
- 大文件处理:使用流式读取,避免一次性加载
- 几何缓存:避免重复创建Geometry对象
- 及时释放:处理完成后置空引用
3.6.3 IO优化
- 批量写入:使用事务批量提交
- 合理过滤:在读取时使用过滤条件减少数据量
- 连接池:PostGIS操作时使用连接池

浙公网安备 33010602011771号