如何使用GeoTools API创建并填充shp文件
没问题!在Java里创建并填充Shapefile,GeoTools库是业内最常用的工具——它提供了一套完整的API来处理GIS数据的创建、读写操作。下面我给你一个完整的示例,从搭建依赖到实现核心逻辑的全流程:
1. 添加GeoTools依赖(Maven为例)
GeoTools的包不在默认Maven中央仓库,所以得先配置仓库,再引入核心依赖:
<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> <dependencies> <!-- GeoTools核心依赖 --> <dependency> <groupId>org.geotools</groupId> <artifactId>gt-shapefile</artifactId> <version>28.2</version> <!-- 可以替换为最新稳定版 --> </dependency> <dependency> <groupId>org.geotools</groupId> <artifactId>gt-data</artifactId> <version>28.2</version> </dependency> <dependency> <groupId>org.geotools</groupId> <artifactId>gt-epsg-wkt</artifactId> <version>28.2</version> </dependency> </dependencies>
2. 定义业务数据实体类
假设你的Java集合里存的是带坐标的点位数据,先定义一个实体类来封装这些信息:
public class PointData { private String name; // 自定义属性:点位名称 private double lat; // 纬度 private double lon; // 经度 private int value; // 自定义属性:关联数值 // 构造器、getter方法 public PointData(String name, double lat, double lon, int value) { this.name = name; this.lat = lat; this.lon = lon; this.value = value; } public String getName() { return name; } public double getLat() { return lat; } public double getLon() { return lon; } public int getValue() { return value; } }
3. 核心实现:创建并填充Shapefile
下面是核心代码,包含创建空Shapefile、定义要素结构、遍历集合写入数据的完整逻辑:
import org.geotools.data.DataStore; import org.geotools.data.DataStoreFinder; import org.geotools.data.DefaultTransaction; import org.geotools.data.Transaction; import org.geotools.data.shapefile.ShapefileDataStore; import org.geotools.data.simple.SimpleFeatureCollection; import org.geotools.data.simple.SimpleFeatureSource; import org.geotools.data.simple.SimpleFeatureStore; import org.geotools.feature.DefaultFeatureCollection; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.GeometryFactory; import org.locationtech.jts.geom.Point; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import java.io.File; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.List; import java.util.Map; public class ShapefileCreator { public static void createAndFillShapefile(List<PointData> dataList, String outputPath) throws Exception { // 1. 定义Shapefile的要素类型(结构:自定义属性+几何图形) SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder(); typeBuilder.setName("PointLayer"); typeBuilder.setCRS(DefaultGeographicCRS.WGS84); // 设置坐标系为WGS84(经纬度) // 添加自定义属性 typeBuilder.add("name", String.class); typeBuilder.add("value", Integer.class); // 添加几何属性(Point类型,对应点位数据) typeBuilder.add("the_geom", Point.class); SimpleFeatureType featureType = typeBuilder.buildFeatureType(); // 2. 创建Shapefile数据存储 File shapefile = new File(outputPath); Map<String, Object> params = new HashMap<>(); params.put("url", shapefile.toURI().toURL()); params.put("create spatial index", Boolean.TRUE); DataStore dataStore = DataStoreFinder.getDataStore(params); if (dataStore instanceof ShapefileDataStore) { ((ShapefileDataStore) dataStore).setCharset(StandardCharsets.UTF_8); // 设置UTF-8避免中文乱码 } dataStore.createSchema(featureType); // 3. 将Java集合数据转换为GIS要素 DefaultFeatureCollection featureCollection = new DefaultFeatureCollection("internal", featureType); GeometryFactory geometryFactory = new GeometryFactory(); SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(featureType); for (PointData data : dataList) { // 创建JTS Point对象:注意顺序是「经度, 纬度」 Coordinate coordinate = new Coordinate(data.getLon(), data.getLat()); Point point = geometryFactory.createPoint(coordinate); // 填充要素属性 featureBuilder.set("name", data.getName()); featureBuilder.set("value", data.getValue()); featureBuilder.set("the_geom", point); // 构建要素(ID用索引生成,也可以自定义唯一标识) SimpleFeature feature = featureBuilder.buildFeature(String.valueOf(dataList.indexOf(data))); featureCollection.add(feature); } // 4. 将要素写入Shapefile 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(featureCollection); transaction.commit(); System.out.println("Shapefile创建并填充成功!路径:" + outputPath); } catch (Exception e) { transaction.rollback(); throw new RuntimeException("写入数据失败", e); } finally { transaction.close(); dataStore.dispose(); // 释放资源,避免内存泄漏 } } } // 测试方法:模拟业务数据并执行创建 public static void main(String[] args) throws Exception { // 模拟你的Java集合数据 List<PointData> dataList = List.of( new PointData("北京", 39.9042, 116.4074, 100), new PointData("上海", 31.2304, 121.4737, 200), new PointData("广州", 23.1291, 113.2644, 300) ); // 输出路径:当前目录下的test.shp String outputPath = "./test.shp"; createAndFillShapefile(dataList, outputPath); } }
关键注意点
- 坐标系: 示例用了WGS84(EPSG:4326),如果你的数据是投影坐标系(比如墨卡托),需要替换对应的CRS参数。
- 几何顺序: JTS库创建Point时,必须是「经度在前,纬度在后」,别搞反了!
- 编码设置: 一定要设置UTF-8编码,否则属性中的中文会出现乱码。
- 资源释放: 操作完成后要关闭
Transaction和DataStore,避免资源泄漏。
内容的提问来源于stack exchange,提问作者J. L. Pacheco




