使用GeoTools把Geojson转换成Shp文件 GeoTools‌ 是一个开源的 ‌Java GIS 工具包‌旨在提供符合 ‌开放地理空间联盟OGC规范‌ 的地理空间数据处理、访问和可视化方法其官方网站为 geotools.org 。作为开源地理信息领域的核心类库它被广泛用于构建 Web 服务、命令行工具及桌面应用程序支持多种数据格式与空间数据库的交互 。‌核心功能与技术特性GeoTools 的技术特性主要体现在对国际标准的全面支持、模块化架构以及丰富的空间数据处理能力上能够满足从数据存取到地图渲染的多种开发需求。‌标准规范支持‌GeoTools 完整遵循并实现了 ‌OGC 标准‌包括网络地图服务WMS、网络要素服务WFS、地理标记语言GML、样式化图层描述符SLD等确保不同地理信息系统间的数据共享与互操作性 。‌1百科‌‌数据处理能力‌提供了一套干净、统一的数据访问 APIDataStore支持读写多种 ‌矢量数据格式‌如 Shapefile、GeoJSON、CSV、DXF和 ‌栅格数据格式‌如 GeoTIFF、JPEG、PNG并能连接主流 ‌空间数据库‌如 PostGIS、Oracle、MySQL、SQL Server 。‌‌坐标与渲染引擎‌内置强大的 ‌坐标参考系统CRS支持‌能够处理复杂的地图投影并执行精确的坐标转换同时提供高效、无状态且低内存消耗的地图渲染引擎适合服务器端环境支持使用 SLD 定义复杂的地图样式 。‌1百科‌‌5‌依赖与架构‌基于 ‌Java 拓扑套件JTS‌ 定义空间数据结构并依赖 ‌GeoAPI‌ 接口规范采用模块化架构各组件间松散耦合允许开发者灵活选用所需功能或通过插件系统扩展新的数据格式支持应用场景与生态系统GeoTools 经过二十多年的发展已形成活跃的开源社区生态构成了从桌面应用到云端服务的广泛技术基础适用于多种地理信息系统开发场景。‌基础组件支撑‌作为核心底层库GeoTools 是多个知名开源 GIS 项目的基础例如 ‌GeoServer‌ 使用其作为核心数据访问和处理引擎‌uDig‌ 是基于其构建的开源桌面 GIS 客户端‌GeoMesa‌ 则通过扩展其数据源能力来处理大规模时空数据 。‌1百科‌‌7‌WebGIS 开发‌广泛用于构建互联网上的 GIS 应用软件通过实现 OGC 网络服务标准支持地图服务的快速发布、矢量数据的自适应渲染以及空间数据的在线查询与分析 。‌‌7‌‌8‌行业解决方案‌在电力、物流、城市规划等领域有具体应用如电网空间信息呈现、配送路线管理系统、城市积水面实时生成与可视化、等高线批量赋值等帮助解决数据解析、坐标计算及空间关系分析等常见问题 。‌‌7‌‌8‌大数据与云存储‌支持与非结构化数据库如 HBase结合提出矢量空间数据存储模型解决云存储技术中缺乏空间数据拓扑关系描述的问题适用于海量地理空间数据的管理 。‌‌8开发资源与架构说明对于有志于从事地理信息系统开发的人员GeoTools 提供了丰富的文档与社区支持但在使用时需注意其特定的技术限制与依赖关系。‌开源许可与维护‌项目基于 ‌GNU 宽通用公共许可证LGPL‌ 发布由开源社区维护隶属于 ‌开源地理空间基金会OSGeo‌ 旗下项目拥有活跃的贡献者与项目管理委员会 。‌‌技术局限性‌目前 GeoTools 主要基于 ‌2D 图形‌缺乏对 3D 空间数据算法和显示的原生支持在使用时需注意其与 JTS 和 GeoAPI 的代码实现差异有时需要进行相互转化 。‌‌‌‌获取与集成‌开发者可通过 Maven 构建系统引入相关 jar 包利用 DataStoreFinder 动态加载数据存储并通过 CQL公共查询语言创建过滤器进行空间查询官方文档与 OSGeo Live 应用程序提供了详细的入门指南与概述 。‌这里使用的Geotools的版本为geotools.version34.1/geotools.version需要加入依赖dependency groupIdorg.geotools/groupId artifactIdgt-main/artifactId version${geotools.version}/version /dependency dependency groupIdorg.geotools/groupId artifactIdgt-shapefile/artifactId version${geotools.version}/version /dependency dependency groupIdorg.geotools/groupId artifactIdgt-geojson/artifactId version${geotools.version}/version /dependencyGeoTools在Maven的镜像中可能不存在需要在pom.xml中加入GeoTools的仓库repositories repository idosgeo/id nameOSGeo Release Repository/name urlhttps://repo.osgeo.org/repository/release//url snapshotsenabledfalse/enabled/snapshots releasesenabledtrue/enabled/releases /repository repository idosgeo-snapshot/id nameOSGeo Snapshot Repository/name urlhttps://repo.osgeo.org/repository/snapshot//url snapshotsenabledtrue/enabled/snapshots releasesenabledfalse/enabled/releases /repository /repositories或者在settings.xml加入!-- 阿里云镜像配置 -- mirrors mirror idaliyunmaven/id name阿里云中央仓库/name urlhttps://maven.aliyun.com/repository/public/url mirrorOfcentral/mirrorOf /mirror mirror idaliyunmaven-spring/id name阿里云Spring仓库/name urlhttps://maven.aliyun.com/repository/spring/url mirrorOfspring-plugin/mirrorOf /mirror mirror idaliyunmaven-google/id name阿里云Google仓库/name urlhttps://maven.aliyun.com/repository/google/url mirrorOfgoogle/mirrorOf /mirror !-- osgeo伪镜像 -- mirror idmirror-osgeo/id mirrorOfosgeo/mirrorOf nameMirror Osgeo/name urlhttps://repo.osgeo.org/repository/release//url /mirror /mirrorsJava代码package com.haifang.utils; /** * author chenshixian **/ import cn.hutool.core.io.FileUtil; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.parser.Feature; import org.geotools.api.data.Transaction; import org.geotools.api.data.SimpleFeatureSource; import org.geotools.api.data.SimpleFeatureStore; import org.geotools.api.feature.simple.SimpleFeature; import org.geotools.api.feature.simple.SimpleFeatureType; import org.geotools.api.referencing.crs.CoordinateReferenceSystem; import org.geotools.data.DefaultTransaction; import org.geotools.data.shapefile.ShapefileDataStore; import org.geotools.data.shapefile.ShapefileDataStoreFactory; import org.geotools.feature.DefaultFeatureCollection; import org.geotools.feature.SchemaException; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; import org.geotools.geojson.feature.FeatureJSON; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.locationtech.jts.geom.Geometry; import java.io.*; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.*; public class GeoJsonToShpConverter { private static final CoordinateReferenceSystem DEFAULT_CRS DefaultGeographicCRS.WGS84; private static final Charset SHAPEFILE_CHARSET StandardCharsets.UTF_8; private static final String GEOMETRY_FIELD_NAME the_geom; // 标准几何字段名 private static final FeatureJSON featureJSON new FeatureJSON(); public static void main(String[] args) throws Exception { String[] geojsonList new String[]{output/ships_trajectory.geojson, output/ships_points.geojson}; for(String path: geojsonList) { // 输入GeoJSON文件路径 File inputFile new File(path); // 输出目录 File outputDir new File(inputFile.getParentFile(), shp); if (!outputDir.exists()) { outputDir.mkdirs(); } // 读取并转换GeoJSON convertGeoJsonToShapefiles(inputFile, outputDir); } } /** * 将GeoJSON文件转换为多个Shapefile */ public static void convertGeoJsonToShapefiles(File geoJsonFile, File outputDir) throws Exception { // 读取GeoJSON内容 String geoJsonContent FileUtil.readUtf8String(geoJsonFile); JSONObject geoJsonObject JSONObject.parseObject(geoJsonContent, Feature.OrderedField); JSONArray features geoJsonObject.getJSONArray(features); if (features null || features.isEmpty()) { System.out.println(GeoJSON文件中没有要素数据); return; } // 按几何类型分组 MapString, ListSimpleFeature geometryTypeMap new HashMap(); MapString, SetString allProperties new HashMap(); // 先收集所有要素和属性 for (int i 0; i features.size(); i) { JSONObject featureJson features.getJSONObject(i); JSONObject geometry featureJson.getJSONObject(geometry); String geometryType geometry.getString(type); // 修复只有一个点的LineString if (LineString.equals(geometryType)) { JSONArray coordinates geometry.getJSONArray(coordinates); if (coordinates ! null coordinates.size() 1) { // 复制该点使LineString有两个相同的点 coordinates.add(coordinates.getJSONArray(0)); } } // 转换为SimpleFeature String featureStr featureJson.toJSONString(); SimpleFeature feature featureJSON.readFeature(new StringReader(featureStr)); // 添加到对应类型的列表 ListSimpleFeature typeList geometryTypeMap.computeIfAbsent(geometryType, k - new ArrayList()); typeList.add(feature); // 收集属性字段 JSONObject properties featureJson.getJSONObject(properties); if (properties ! null) { SetString props allProperties.computeIfAbsent(geometryType, k - new HashSet()); props.addAll(properties.keySet()); } } // 获取文件名前缀 String fileNamePrefix FileUtil.getPrefix(geoJsonFile); // 为每种几何类型创建Shapefile for (Map.EntryString, ListSimpleFeature entry : geometryTypeMap.entrySet()) { String geometryType entry.getKey(); ListSimpleFeature featureList entry.getValue(); // 获取该类型的所有属性字段 SetString propertiesSet allProperties.getOrDefault(geometryType, new HashSet()); // 创建Shapefile File shpFile new File(outputDir, fileNamePrefix _ geometryType.toLowerCase() .shp); createShapefile(shpFile, featureList, geometryType, new ArrayList(propertiesSet)); System.out.println(已创建: shpFile.getName() , 包含 featureList.size() 个要素); } } /** * 创建Shapefile */ private static void createShapefile(File shpFile, ListSimpleFeature features, String geometryType, ListString propertyFields) throws Exception { // 创建要素类型 SimpleFeatureType featureType createFeatureType(shpFile, geometryType, propertyFields); // 创建FeatureCollection DefaultFeatureCollection featureCollection new DefaultFeatureCollection(); SimpleFeatureBuilder featureBuilder new SimpleFeatureBuilder(featureType); for (int i 0; i features.size(); i) { SimpleFeature originalFeature features.get(i); // 设置几何字段 Geometry geometry (Geometry) originalFeature.getDefaultGeometry(); featureBuilder.add(geometry); // 设置属性字段 for (String fieldName : propertyFields) { Object value originalFeature.getAttribute(fieldName); if (value null) { // 尝试从properties中获取 Object properties originalFeature.getAttribute(properties); if (properties instanceof Map) { value ((Map?, ?) properties).get(fieldName); } } featureBuilder.add(value ! null ? value.toString() : null); } // 设置FID featureBuilder.add(FID_ (i 1)); // 构建要素并添加到集合 SimpleFeature feature featureBuilder.buildFeature(null); featureCollection.add(feature); } // 写入Shapefile writeToShapefile(shpFile, featureCollection, featureType); createCpgFile(shpFile); } private static void createCpgFile(File shpFile) throws IOException { String basePath shpFile.getAbsolutePath(); String baseName basePath.substring(0, basePath.lastIndexOf(.)); File cpgFile new File(baseName .cpg); try (FileOutputStream fos new FileOutputStream(cpgFile)) { String charsetName SHAPEFILE_CHARSET.name(); fos.write(charsetName.getBytes(StandardCharsets.US_ASCII)); } System.out.println( 已创建CPG文件: cpgFile.getName() (编码: SHAPEFILE_CHARSET.name() )); } /** * 创建要素类型 */ private static SimpleFeatureType createFeatureType(File shpFile, String geometryType, ListString propertyFields) throws SchemaException { SimpleFeatureTypeBuilder builder new SimpleFeatureTypeBuilder(); builder.setName(FileUtil.getPrefix(shpFile)); builder.setCRS(DEFAULT_CRS); // 添加几何字段 builder.add(GEOMETRY_FIELD_NAME, getGeometryClass(geometryType)); builder.setDefaultGeometry(GEOMETRY_FIELD_NAME); // 添加属性字段 for (String fieldName : propertyFields) { // 处理字段名长度限制DBF字段名限制为10个字符 String dbfFieldName truncateFieldName(fieldName); builder.add(dbfFieldName, String.class); } // 添加ID字段 builder.add(fid, String.class); return builder.buildFeatureType(); } /** * 根据几何类型获取对应的Geometry类 */ private static Class? getGeometryClass(String geometryType) { switch (geometryType.toUpperCase()) { case POINT: return org.locationtech.jts.geom.Point.class; case LINESTRING: return org.locationtech.jts.geom.LineString.class; case POLYGON: return org.locationtech.jts.geom.Polygon.class; case MULTIPOINT: return org.locationtech.jts.geom.MultiPoint.class; case MULTILINESTRING: return org.locationtech.jts.geom.MultiLineString.class; case MULTIPOLYGON: return org.locationtech.jts.geom.MultiPolygon.class; case GEOMETRYCOLLECTION: return org.locationtech.jts.geom.GeometryCollection.class; default: throw new IllegalArgumentException(不支持的几何类型: geometryType); } } /** * 截断字段名以适应DBF文件格式限制最大10个字符 */ private static String truncateFieldName(String fieldName) { if (fieldName null || fieldName.length() 10) { return fieldName; } // 保留字段名的前10个字符 return fieldName.substring(0, 10); } /** * 将FeatureCollection写入Shapefile */ private static void writeToShapefile(File shpFile, DefaultFeatureCollection featureCollection, SimpleFeatureType featureType) throws IOException { ShapefileDataStoreFactory dataStoreFactory new ShapefileDataStoreFactory(); MapString, Serializable params new HashMap(); params.put(url, shpFile.toURI().toURL()); params.put(create spatial index, Boolean.TRUE); ShapefileDataStore newDataStore null; try { // 创建新的数据存储 newDataStore (ShapefileDataStore) dataStoreFactory.createNewDataStore(params); newDataStore.createSchema(featureType); newDataStore.setCharset(StandardCharsets.UTF_8); // 获取类型名称 String typeName newDataStore.getTypeNames()[0]; // 获取FeatureSource SimpleFeatureSource featureSource newDataStore.getFeatureSource(typeName); if (featureSource instanceof SimpleFeatureStore) { SimpleFeatureStore featureStore (SimpleFeatureStore) featureSource; // 设置事务 Transaction transaction new DefaultTransaction(create); featureStore.setTransaction(transaction); try { // 写入要素 featureStore.addFeatures(featureCollection); transaction.commit(); System.out.println(成功写入: featureCollection.size() 个要素到 shpFile.getName()); } catch (Exception e) { transaction.rollback(); throw e; } finally { transaction.close(); } } } finally { // 确保数据存储被正确关闭和清理 if (newDataStore ! null) { newDataStore.dispose(); } } } }