GeoJSON 与 WKT 相互转换工具类(Java 实现)
·
在 GIS 开发中,经常会遇到 GeoJSON 与 WKT(Well-Known Text) 之间的互转需求。
比如地图绘制、空间数据存储、数据库操作(PostGIS)、或者系统对接时,都会需要这类转换工具。
本文分享一个自己实现的 GeoJSON ↔ WKT 工具类,支持常见几何类型,方便在项目中直接使用。
📌 支持的几何类型
-
Point
-
LineString
-
Polygon
-
MultiPoint
-
MultiLineString
-
MultiPolygon
-
兼容 Feature / FeatureCollection
📦 工具类代码
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
/**
* GeoJSON 工具类
* 提供 GeoJSON 与 WKT 的相互转换功能
* 支持的几何类型:Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon
*/
@Slf4j
public class GeoJsonWktUtils {
private static final ObjectMapper objectMapper = new ObjectMapper()
.enable(SerializationFeature.INDENT_OUTPUT);
/**
* 将 GeoJSON 字符串转换为 WKT 字符串
* 支持 FeatureCollection、Feature 及 Geometry
*/
public static String geoJsonToWkt(String geoJsonGeoStr) {
JSONObject root = JSON.parseObject(geoJsonGeoStr);
String rootType = root.getString("type");
if ("FeatureCollection".equalsIgnoreCase(rootType)) {
JSONArray features = root.getJSONArray("features");
if (features == null || features.isEmpty()) {
log.warn("FeatureCollection 中 features 为空");
return StringUtils.EMPTY;
}
JSONObject firstFeature = features.getJSONObject(0);
JSONObject geometry = firstFeature.getJSONObject("geometry");
if (geometry == null) {
log.warn("Feature 中无 geometry");
return StringUtils.EMPTY;
}
return geoJsonToWkt(geometry.toJSONString());
} else if ("Feature".equalsIgnoreCase(rootType)) {
JSONObject geometry = root.getJSONObject("geometry");
if (geometry == null) {
log.warn("Feature 不存在 geometry");
return StringUtils.EMPTY;
}
return geoJsonToWkt(geometry.toJSONString());
} else {
String type = root.getString("type");
JSONArray coordinates = root.getJSONArray("coordinates");
return switch (type) {
case "Point" -> pointToWkt(coordinates);
case "LineString" -> lineStringToWkt(coordinates);
case "Polygon" -> polygonToWkt(coordinates);
case "MultiPoint" -> multiPointToWkt(coordinates);
case "MultiLineString" -> multiLineStringToWkt(coordinates);
case "MultiPolygon" -> multiPolygonToWkt(coordinates);
default -> {
log.warn("不支持的数据类型: {}", type);
yield StringUtils.EMPTY;
}
};
}
}
/** 判断字符串是否是有效的 GeoJSON 格式 */
public static boolean isValidGeoJson(String json) {
if (StringUtils.isBlank(json)){
return false;
}
try {
objectMapper.readTree(json);
return true;
} catch (IOException e) {
return false;
}
}
/** 将 GeoJSON 字符串格式化输出 */
public static String formatGeoJson(String json) {
try {
Object obj = objectMapper.readValue(json, Object.class);
return objectMapper.writeValueAsString(obj);
} catch (IOException e) {
throw new RuntimeException("GeoJSON格式化失败: " + e.getMessage(), e);
}
}
/** 将任意对象序列化为 GeoJSON 字符串 */
public static String toGeoJson(Object obj) {
try {
return objectMapper.writeValueAsString(obj);
} catch (IOException e) {
throw new RuntimeException("对象转GeoJSON失败: " + e.getMessage(), e);
}
}
/** Point 类型坐标转 WKT */
private static String pointToWkt(JSONArray coords) {
return "POINT(" + coords.getDouble(0) + " " + coords.getDouble(1) + ")";
}
/** LineString 类型坐标转 WKT */
private static String lineStringToWkt(JSONArray coords) {
StringBuilder sb = new StringBuilder("LINESTRING(");
for (int i = 0; i < coords.size(); i++) {
JSONArray point = coords.getJSONArray(i);
sb.append(point.getDouble(0)).append(" ").append(point.getDouble(1));
if (i < coords.size() - 1) sb.append(", ");
}
sb.append(")");
return sb.toString();
}
/** Polygon 类型坐标转 WKT */
private static String polygonToWkt(JSONArray coords) {
StringBuilder sb = new StringBuilder("POLYGON(");
for (int i = 0; i < coords.size(); i++) {
JSONArray ring = coords.getJSONArray(i);
sb.append("(");
for (int j = 0; j < ring.size(); j++) {
JSONArray point = ring.getJSONArray(j);
sb.append(point.getDouble(0)).append(" ").append(point.getDouble(1));
if (j < ring.size() - 1) sb.append(", ");
}
sb.append(")");
if (i < coords.size() - 1) sb.append(", ");
}
sb.append(")");
return sb.toString();
}
/** MultiPoint 类型坐标转 WKT */
private static String multiPointToWkt(JSONArray coords) {
StringBuilder sb = new StringBuilder("MULTIPOINT(");
for (int i = 0; i < coords.size(); i++) {
JSONArray point = coords.getJSONArray(i);
sb.append("(").append(point.getDouble(0)).append(" ").append(point.getDouble(1)).append(")");
if (i < coords.size() - 1) sb.append(", ");
}
sb.append(")");
return sb.toString();
}
/** MultiLineString 类型坐标转 WKT */
private static String multiLineStringToWkt(JSONArray coords) {
StringBuilder sb = new StringBuilder("MULTILINESTRING(");
for (int i = 0; i < coords.size(); i++) {
JSONArray line = coords.getJSONArray(i);
sb.append("(");
for (int j = 0; j < line.size(); j++) {
JSONArray point = line.getJSONArray(j);
sb.append(point.getDouble(0)).append(" ").append(point.getDouble(1));
if (j < line.size() - 1) sb.append(", ");
}
sb.append(")");
if (i < coords.size() - 1) sb.append(", ");
}
sb.append(")");
return sb.toString();
}
/** MultiPolygon 类型坐标转 WKT */
private static String multiPolygonToWkt(JSONArray coords) {
StringBuilder sb = new StringBuilder("MULTIPOLYGON(");
for (int i = 0; i < coords.size(); i++) {
JSONArray polygon = coords.getJSONArray(i);
sb.append("(");
for (int j = 0; j < polygon.size(); j++) {
JSONArray ring = polygon.getJSONArray(j);
sb.append("(");
for (int k = 0; k < ring.size(); k++) {
JSONArray point = ring.getJSONArray(k);
sb.append(point.getDouble(0)).append(" ").append(point.getDouble(1));
if (k < ring.size() - 1) sb.append(", ");
}
sb.append(")");
if (j < polygon.size() - 1) sb.append(", ");
}
sb.append(")");
if (i < coords.size() - 1) sb.append(", ");
}
sb.append(")");
return sb.toString();
}
/** WKT 转 GeoJSON */
public static String wktToGeoJson(String wkt) {
wkt = wkt.trim();
if (wkt.startsWith("POINT")) return pointWktToGeoJson(wkt);
if (wkt.startsWith("LINESTRING")) return lineStringWktToGeoJson(wkt);
if (wkt.startsWith("POLYGON")) return polygonWktToGeoJson(wkt);
if (wkt.startsWith("MULTIPOINT")) return multiPointWktToGeoJson(wkt);
if (wkt.startsWith("MULTILINESTRING")) return multiLineStringWktToGeoJson(wkt);
if (wkt.startsWith("MULTIPOLYGON")) return multiPolygonWktToGeoJson(wkt);
throw new UnsupportedOperationException("不支持的WKT类型: " + wkt);
}
/** WKT Point 转 GeoJSON */
private static String pointWktToGeoJson(String wkt) {
String[] parts = extractCoordinates(wkt);
JSONObject geo = new JSONObject();
geo.put("type", "Point");
geo.put("coordinates", new double[]{Double.parseDouble(parts[0]), Double.parseDouble(parts[1])});
return geo.toJSONString();
}
/** WKT LineString 转 GeoJSON */
private static String lineStringWktToGeoJson(String wkt) {
String[] parts = extractMultiCoordinates(wkt);
JSONArray coords = toJsonCoordinates(parts);
JSONObject geo = new JSONObject();
geo.put("type", "LineString");
geo.put("coordinates", coords);
return geo.toJSONString();
}
/** WKT Polygon 转 GeoJSON */
private static String polygonWktToGeoJson(String wkt) {
return buildPolygonGeoJson(wkt, "Polygon");
}
/** WKT MultiPoint 转 GeoJSON */
private static String multiPointWktToGeoJson(String wkt) {
return buildSimpleMultiGeoJson(wkt, "MultiPoint");
}
/** WKT MultiLineString 转 GeoJSON */
private static String multiLineStringWktToGeoJson(String wkt) {
return buildPolygonGeoJson(wkt, "MultiLineString");
}
/** WKT MultiPolygon 转 GeoJSON */
private static String multiPolygonWktToGeoJson(String wkt) {
return buildPolygonGeoJson(wkt, "MultiPolygon");
}
/** 提取单点坐标 */
private static String[] extractCoordinates(String wkt) {
String content = wkt.substring(wkt.indexOf('(') + 1, wkt.lastIndexOf(')')).trim();
return content.split(" ");
}
/** 提取多点/线坐标 */
private static String[] extractMultiCoordinates(String wkt) {
String content = wkt.substring(wkt.indexOf('(') + 1, wkt.lastIndexOf(')')).trim();
return content.split(",");
}
/** 转换为坐标数组 */
private static JSONArray toJsonCoordinates(String[] parts) {
JSONArray arr = new JSONArray();
for (String part : parts) {
String[] xy = part.trim().split(" ");
arr.add(new double[]{Double.parseDouble(xy[0]), Double.parseDouble(xy[1])});
}
return arr;
}
/** 构建简单的 Multi 类型 GeoJSON(如 MultiPoint) */
private static String buildSimpleMultiGeoJson(String wkt, String type) {
String content = wkt.substring(wkt.indexOf('('), wkt.lastIndexOf(')') + 1);
content = content.replace("(", "").replace(")", "");
String[] points = content.split(",");
JSONArray arr = new JSONArray();
for (String p : points) {
String[] xy = p.trim().split(" ");
arr.add(new double[]{Double.parseDouble(xy[0]), Double.parseDouble(xy[1])});
}
JSONObject geo = new JSONObject();
geo.put("type", type);
geo.put("coordinates", arr);
return geo.toJSONString();
}
/** 构建 Polygon/MultiPolygon 类型 GeoJSON */
private static String buildPolygonGeoJson(String wkt, String type) {
String content = wkt.substring(wkt.indexOf('('), wkt.lastIndexOf(')') + 1);
content = content.replaceAll("^\\(+|\\)+$", "");
String[] polygonParts = content.split("\\)\\s*,\\s*\\(");
JSONArray polygons = new JSONArray();
for (String part : polygonParts) {
String[] rings = part.split("\\)\\s*,\\s*\\(");
JSONArray ringsArr = new JSONArray();
for (String ring : rings) {
ring = ring.replace("(", "").replace(")", "");
String[] points = ring.split(",");
JSONArray coords = new JSONArray();
for (String p : points) {
String[] xy = p.trim().split(" ");
coords.add(new double[]{Double.parseDouble(xy[0]), Double.parseDouble(xy[1])});
}
ringsArr.add(coords);
}
polygons.add(ringsArr);
}
JSONObject geo = new JSONObject();
geo.put("type", type);
geo.put("coordinates", type.equals("Polygon") ? polygons.get(0) : polygons);
return geo.toJSONString();
}
}
功能介绍
-
GeoJSON → WKT
-
支持直接传入 FeatureCollection、Feature 或 Geometry 格式
-
自动识别类型,生成对应的 WKT 字符串
String geoJson = "{ \"type\": \"Point\", \"coordinates\": [120.2, 30.3] }"; String wkt = GeoJsonWktUtils.geoJsonToWkt(geoJson); // 输出: POINT(120.2 30.3) -
-
WKT → GeoJSON
-
识别几何类型
-
转换为标准的 GeoJSON 字符串
String wkt = "LINESTRING(120.1 30.2, 120.5 30.8)"; String geoJson = GeoJsonWktUtils.wktToGeoJson(wkt); // 输出: {"type":"LineString","coordinates":[[120.1,30.2],[120.5,30.8]]}
-
-
格式化 GeoJSON
-
使用 Jackson 美化输出
String prettyGeoJson = GeoJsonWktUtils.formatGeoJson(geoJson); System.out.println(prettyGeoJson); -
-
校验 GeoJSON 是否有效
boolean valid = GeoJsonWktUtils.isValidGeoJson(geoJson);
⚡ 使用场景
-
数据库交互:
-
PostGIS 常用
WKT存储空间数据,接口则可能返回GeoJSON
-
-
地图渲染:
-
前端地图组件(如 OpenLayers、Leaflet、Mapbox)更偏向 GeoJSON
-
-
系统对接:
-
第三方接口可能格式不一致,工具类能快速统一
-
🎯 总结
-
本文实现了一个通用的 GeoJSON ↔ WKT 工具类
-
在 水利、测绘、GIS、地理信息系统 等项目中很实用
-
支持常见几何类型,兼容 Feature / FeatureCollection
更多推荐


所有评论(0)