169 lines
5.6 KiB
Java
Raw Normal View History

2025-12-30 09:26:52 +08:00
package com.cdzy.operations.handler;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.LinearRing;
import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.io.WKTWriter;
import java.io.IOException;
/**
* JTS Polygon 序列化器 - Polygon 序列化为 JSON
* 生成与 PGpolygonSerializer 相同的 JSON 格式
*/
@Slf4j
public class PolygonSerializer extends JsonSerializer<Polygon> {
private final WKTWriter wktWriter = new WKTWriter();
@Override
2026-01-06 09:14:23 +08:00
public void serialize(Polygon polygon, JsonGenerator gen, SerializerProvider serializers)
2025-12-30 09:26:52 +08:00
throws IOException {
if (polygon == null) {
gen.writeNull();
return;
}
try {
// 获取多边形的外环坐标
Coordinate[] coordinates = getPolygonCoordinates(polygon);
if (coordinates.length == 0) {
log.warn("警告: 多边形没有有效坐标");
gen.writeNull();
return;
}
// 检查是否有无效坐标
for (int i = 0; i < coordinates.length; i++) {
Coordinate coord = coordinates[i];
if (coord == null || Double.isNaN(coord.x) || Double.isNaN(coord.y)) {
log.error("错误: 第 {} 个坐标无效: {}", i, coord);
}
}
// 序列化为自定义格式(与 PGpolygonSerializer 格式一致)
gen.writeStartObject();
gen.writeStringField("type", "polygon");
gen.writeArrayFieldStart("coordinates");
for (int i = 0; i < coordinates.length; i++) {
Coordinate coord = coordinates[i];
if (coord == null || Double.isNaN(coord.x) || Double.isNaN(coord.y)) {
continue;
}
try {
gen.writeStartArray();
// 使用格式化器避免科学计数法
gen.writeNumber(formatCoordinate(coord.x));
gen.writeNumber(formatCoordinate(coord.y));
gen.writeEndArray();
} catch (Exception e) {
throw new IOException("序列化坐标 " + i + " 失败", e);
}
}
gen.writeEndArray();
gen.writeEndObject();
} catch (Exception e) {
log.error("!!! PolygonSerializer 序列化失败 !!!");
log.error("错误信息: {}", e.getMessage());
// 尝试备用序列化方式
try {
serializeAsWKT(polygon, gen);
} catch (Exception e2) {
throw new IOException("Polygon 序列化失败: " + e.getMessage(), e);
}
}
}
@Override
public Class<Polygon> handledType() {
return Polygon.class;
}
/**
* 获取多边形的坐标仅外环忽略孔洞
*/
private Coordinate[] getPolygonCoordinates(Polygon polygon) throws IOException {
if (polygon == null || polygon.isEmpty()) {
return new Coordinate[0];
}
try {
// 获取外环
2026-01-06 09:14:23 +08:00
LinearRing exteriorRing = polygon.getExteriorRing();
2025-12-30 09:26:52 +08:00
if (exteriorRing == null) {
throw new IOException("多边形外环为空");
}
return exteriorRing.getCoordinates();
2026-01-06 09:14:23 +08:00
2025-12-30 09:26:52 +08:00
} catch (Exception e) {
throw new IOException("获取多边形坐标失败: " + e.getMessage(), e);
}
}
/**
* 格式化坐标值
*/
private double formatCoordinate(double value) {
// 返回原始值Jackson 会处理格式化
return value;
}
/**
* 备用序列化方式序列化为 WKT 字符串
*/
private void serializeAsWKT(Polygon polygon, JsonGenerator gen) throws IOException {
if (polygon == null) {
gen.writeNull();
return;
}
try {
String wkt = wktWriter.write(polygon);
2026-01-06 09:14:23 +08:00
2025-12-30 09:26:52 +08:00
if (wkt.startsWith("POLYGON")) {
// 提取坐标部分
String coordsPart = wkt.substring(wkt.indexOf("((") + 2, wkt.lastIndexOf("))"));
String[] points = coordsPart.split(", ");
2026-01-06 09:14:23 +08:00
2025-12-30 09:26:52 +08:00
gen.writeStartObject();
gen.writeStringField("type", "polygon");
2026-01-06 09:14:23 +08:00
2025-12-30 09:26:52 +08:00
gen.writeArrayFieldStart("coordinates");
for (String point : points) {
String[] xy = point.split(" ");
if (xy.length >= 2) {
try {
double x = Double.parseDouble(xy[0]);
double y = Double.parseDouble(xy[1]);
2026-01-06 09:14:23 +08:00
2025-12-30 09:26:52 +08:00
gen.writeStartArray();
gen.writeNumber(x);
gen.writeNumber(y);
gen.writeEndArray();
} catch (NumberFormatException e) {
log.warn("坐标解析失败: {}", point);
}
}
}
gen.writeEndArray();
gen.writeEndObject();
} else {
// 直接写 WKT 字符串
gen.writeString(wkt);
}
2026-01-06 09:14:23 +08:00
2025-12-30 09:26:52 +08:00
} catch (Exception e) {
log.error("WKT 序列化失败: {}", e.getMessage());
throw new IOException("Polygon 序列化失败", e);
}
}
}