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 { private final WKTWriter wktWriter = new WKTWriter(); @Override public void serialize(Polygon polygon, JsonGenerator gen, SerializerProvider serializers) 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 handledType() { return Polygon.class; } /** * 获取多边形的坐标(仅外环,忽略孔洞) */ private Coordinate[] getPolygonCoordinates(Polygon polygon) throws IOException { if (polygon == null || polygon.isEmpty()) { return new Coordinate[0]; } try { // 获取外环 LinearRing exteriorRing = polygon.getExteriorRing(); if (exteriorRing == null) { throw new IOException("多边形外环为空"); } return exteriorRing.getCoordinates(); } 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); if (wkt.startsWith("POLYGON")) { // 提取坐标部分 String coordsPart = wkt.substring(wkt.indexOf("((") + 2, wkt.lastIndexOf("))")); String[] points = coordsPart.split(", "); gen.writeStartObject(); gen.writeStringField("type", "polygon"); 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]); 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); } } catch (Exception e) { log.error("WKT 序列化失败: {}", e.getMessage()); throw new IOException("Polygon 序列化失败", e); } } }