270 lines
9.0 KiB
Java
Raw Normal View History

package com.cdzy.operations.handler;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
import org.postgresql.geometric.PGpoint;
import org.postgresql.geometric.PGpolygon;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* PGpolygon 反序列化器 - JSON 反序列化为 PGpolygon
*/
@Slf4j
public class PGpolygonDeserializer extends JsonDeserializer<PGpolygon> {
@Override
public PGpolygon deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
JsonNode node = p.getCodec().readTree(p);
if (node.isNull()) {
return null;
}
try {
PGpolygon result = null;
// 格式1: 自定义格式 {"type": "polygon", "coordinates": [[x1,y1], [x2,y2], ...]}
if (node.isObject() && node.has("type")) {
String type = node.get("type").asText();
if ("polygon".equals(type)) {
result = parseFromCustomFormat(node);
} else if ("Polygon".equals(type)) {
result = parseFromGeoJSON(node);
}
}
// 格式2: 直接坐标数组 [[x1,y1], [x2,y2], ...]
else if (node.isArray()) {
result = parseFromArray(node);
}
// 格式3: 字符串格式 "((x1 y1, x2 y2, ...))"
else if (node.isTextual()) {
result = parseFromString(node.asText());
}
// 格式4: 对象格式但没有 type 字段,尝试解析 coordinates
else if (node.isObject() && node.has("coordinates")) {
result = parseFromCustomFormat(node);
}
if (result == null) {
throw new IOException("""
不支持的 PGpolygon JSON 格式支持的格式包括
1. 自定义格式: {"type":"polygon","coordinates":[[x1,y1],[x2,y2],...]}
2. GeoJSON格式: {"type":"Polygon","coordinates":[[[x1,y1],[x2,y2],...]]}
3. 坐标数组: [[x1,y1],[x2,y2],...]
4. 字符串格式: "((x1 y1, x2 y2, ...))\"""");
}
return result;
} catch (Exception e) {
System.err.println("!!! PGpolygonDeserializer 反序列化失败 !!!");
System.err.println("错误信息: " + e.getMessage());
System.err.println("输入 JSON: " + node);
throw new IOException("PGpolygon 反序列化失败: " + e.getMessage(), e);
}
}
@Override
public Class<PGpolygon> handledType() {
return PGpolygon.class;
}
/**
* 解析自定义格式
*/
private PGpolygon parseFromCustomFormat(JsonNode node) throws IOException {
JsonNode coordinatesNode = node.get("coordinates");
if (coordinatesNode == null) {
throw new IOException("coordinates 字段缺失");
}
if (!coordinatesNode.isArray()) {
throw new IOException("coordinates 字段必须是数组类型");
}
List<PGpoint> points = new ArrayList<>();
for (int i = 0; i < coordinatesNode.size(); i++) {
JsonNode coordNode = coordinatesNode.get(i);
if (!coordNode.isArray()) {
throw new IOException("坐标 " + i + " 必须是数组格式");
}
if (coordNode.size() < 2) {
throw new IOException("坐标 " + i + " 至少需要2个值经度和纬度");
}
try {
double x = coordNode.get(0).asDouble();
double y = coordNode.get(1).asDouble();
PGpoint point = new PGpoint(x, y);
points.add(point);
} catch (NumberFormatException e) {
throw new IOException("坐标 " + i + " 格式错误: " + coordNode, e);
}
}
return createPGpolygonFromPoints(points);
}
/**
* 解析 GeoJSON 格式
*/
private PGpolygon parseFromGeoJSON(JsonNode node) throws IOException {
JsonNode coordinatesNode = node.get("coordinates");
if (coordinatesNode == null) {
throw new IOException("coordinates 字段缺失");
}
if (!coordinatesNode.isArray() || coordinatesNode.isEmpty()) {
throw new IOException("coordinates 字段必须是非空数组");
}
// GeoJSON 格式: coordinates 是三维数组 [[[x1,y1], [x2,y2], ...]]
List<PGpoint> points = new ArrayList<>();
for (int i = 0; i < coordinatesNode.size(); i++) {
JsonNode ringNode = coordinatesNode.get(i);
if (!ringNode.isArray()) {
throw new IOException("GeoJSON coordinates 第一环必须是数组");
}
if (!ringNode.isArray()) {
throw new IOException("GeoJSON 坐标 " + i + " 必须是数组格式");
}
if (ringNode.size() < 2) {
throw new IOException("GeoJSON 坐标 " + i + " 至少需要2个值经度和纬度");
}
try {
double x = ringNode.get(0).asDouble();
double y = ringNode.get(1).asDouble();
PGpoint point = new PGpoint(x, y);
points.add(point);
} catch (NumberFormatException e) {
throw new IOException("GeoJSON 坐标 " + i + " 格式错误: " + ringNode, e);
}
}
return createPGpolygonFromPoints(points);
}
/**
* 解析坐标数组格式
*/
private PGpolygon parseFromArray(JsonNode node) throws IOException {
List<PGpoint> points = new ArrayList<>();
for (int i = 0; i < node.size(); i++) {
JsonNode coordNode = node.get(i);
if (!coordNode.isArray()) {
throw new IOException("坐标 " + i + " 必须是数组格式");
}
if (coordNode.size() < 2) {
throw new IOException("坐标 " + i + " 至少需要2个值经度和纬度");
}
try {
double x = coordNode.get(0).asDouble();
double y = coordNode.get(1).asDouble();
PGpoint point = new PGpoint(x, y);
points.add(point);
} catch (NumberFormatException e) {
throw new IOException("坐标 " + i + " 格式错误: " + coordNode, e);
}
}
return createPGpolygonFromPoints(points);
}
/**
* 解析字符串格式
*/
private PGpolygon parseFromString(String polygonString) throws IOException {
if (polygonString == null || polygonString.trim().isEmpty()) {
throw new IOException("多边形字符串为空");
}
try {
PGpolygon polygon = new PGpolygon(polygonString);
System.out.println("字符串解析成功");
return polygon;
} catch (Exception e) {
throw new IOException("PGpolygon 字符串格式解析失败: " + polygonString, e);
}
}
/**
* 从点列表创建 PGpolygon
*/
private PGpolygon createPGpolygonFromPoints(List<PGpoint> points) throws IOException {
if (points == null) {
throw new IOException("点列表为 null");
}
if (points.size() < 3) {
throw new IOException("多边形至少需要3个点当前只有 " + points.size() + " 个点");
}
// 检查点是否为 null
for (int i = 0; i < points.size(); i++) {
if (points.get(i) == null) {
throw new IOException("" + i + " 个点为 null");
}
}
try {
// 构建正确的多边形字符串格式
StringBuilder sb = new StringBuilder();
for (int i = 0; i < points.size(); i++) {
PGpoint point = points.get(i);
if (i == 0) {
sb.append("("); // 开始内括号
}
sb.append("(").append(point.x).append(",").append(point.y).append(")");
if (i < points.size() - 1) {
sb.append(",");
} else {
sb.append(")"); // 结束内括号
}
}
// 确保多边形闭合
PGpoint firstPoint = points.get(0);
PGpoint lastPoint = points.get(points.size() - 1);
if (firstPoint.x != lastPoint.x || firstPoint.y != lastPoint.y) {
log.info("多边形未闭合,添加首点以闭合");
sb.append(",(").append(firstPoint.x).append(",").append(firstPoint.y).append(")");
}
String polygonString = sb.toString();
return new PGpolygon(polygonString);
} catch (Exception e) {
throw new IOException("创建 PGpolygon 失败: " + e.getMessage(), e);
}
}
}