270 lines
9.0 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
}
}
}