区域数据序列化与反序列化bug修复
This commit is contained in:
parent
22d64a6111
commit
547f7ff50d
@ -0,0 +1,13 @@
|
|||||||
|
package com.cdzy.operations.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author attiya
|
||||||
|
* @since 2025-10-22
|
||||||
|
*/
|
||||||
|
public interface RegionStatus {
|
||||||
|
int UN_OPERATION = 0;
|
||||||
|
|
||||||
|
int OPERATION = 1;
|
||||||
|
|
||||||
|
int STOP_OPERATION = 2;
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@ import com.fasterxml.jackson.core.JsonParser;
|
|||||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.postgresql.geometric.PGpoint;
|
import org.postgresql.geometric.PGpoint;
|
||||||
import org.postgresql.geometric.PGpolygon;
|
import org.postgresql.geometric.PGpolygon;
|
||||||
|
|
||||||
@ -14,42 +15,62 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* PGpolygon 反序列化器 - 将 JSON 反序列化为 PGpolygon
|
* PGpolygon 反序列化器 - 将 JSON 反序列化为 PGpolygon
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
public class PGpolygonDeserializer extends JsonDeserializer<PGpolygon> {
|
public class PGpolygonDeserializer extends JsonDeserializer<PGpolygon> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PGpolygon deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
|
public PGpolygon deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
|
||||||
JsonNode node = p.getCodec().readTree(p);
|
JsonNode node = p.getCodec().readTree(p);
|
||||||
|
|
||||||
if (node.isNull()) {
|
if (node.isNull()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 支持多种 JSON 格式
|
|
||||||
|
PGpolygon result = null;
|
||||||
|
|
||||||
// 格式1: 自定义格式 {"type": "polygon", "coordinates": [[x1,y1], [x2,y2], ...]}
|
// 格式1: 自定义格式 {"type": "polygon", "coordinates": [[x1,y1], [x2,y2], ...]}
|
||||||
if (node.isObject() && node.has("type") && "polygon".equals(node.get("type").asText())) {
|
if (node.isObject() && node.has("type")) {
|
||||||
return parseFromCustomFormat(node);
|
String type = node.get("type").asText();
|
||||||
|
|
||||||
|
if ("polygon".equals(type)) {
|
||||||
|
result = parseFromCustomFormat(node);
|
||||||
|
} else if ("Polygon".equals(type)) {
|
||||||
|
result = parseFromGeoJSON(node);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 格式2: GeoJSON 格式 {"type": "Polygon", "coordinates": [[[x1,y1], [x2,y2], ...]]}
|
// 格式2: 直接坐标数组 [[x1,y1], [x2,y2], ...]
|
||||||
if (node.isObject() && node.has("type") && "Polygon".equals(node.get("type").asText())) {
|
else if (node.isArray()) {
|
||||||
return parseFromGeoJSON(node);
|
result = parseFromArray(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 格式3: 直接坐标数组 [[x1,y1], [x2,y2], ...]
|
// 格式3: 字符串格式 "((x1 y1, x2 y2, ...))"
|
||||||
if (node.isArray()) {
|
else if (node.isTextual()) {
|
||||||
return parseFromArray(node);
|
result = parseFromString(node.asText());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 格式4: 字符串格式 "((x1 y1, x2 y2, ...))"
|
// 格式4: 对象格式但没有 type 字段,尝试解析 coordinates
|
||||||
if (node.isTextual()) {
|
else if (node.isObject() && node.has("coordinates")) {
|
||||||
return parseFromString(node.asText());
|
result = parseFromCustomFormat(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new IOException("不支持的 PGpolygon JSON 格式");
|
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) {
|
} catch (Exception e) {
|
||||||
|
System.err.println("!!! PGpolygonDeserializer 反序列化失败 !!!");
|
||||||
|
System.err.println("错误信息: " + e.getMessage());
|
||||||
|
System.err.println("输入 JSON: " + node);
|
||||||
throw new IOException("PGpolygon 反序列化失败: " + e.getMessage(), e);
|
throw new IOException("PGpolygon 反序列化失败: " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,20 +84,38 @@ public class PGpolygonDeserializer extends JsonDeserializer<PGpolygon> {
|
|||||||
* 解析自定义格式
|
* 解析自定义格式
|
||||||
*/
|
*/
|
||||||
private PGpolygon parseFromCustomFormat(JsonNode node) throws IOException {
|
private PGpolygon parseFromCustomFormat(JsonNode node) throws IOException {
|
||||||
|
|
||||||
JsonNode coordinatesNode = node.get("coordinates");
|
JsonNode coordinatesNode = node.get("coordinates");
|
||||||
if (coordinatesNode == null || !coordinatesNode.isArray()) {
|
if (coordinatesNode == null) {
|
||||||
throw new IOException("coordinates 字段缺失或格式错误");
|
throw new IOException("coordinates 字段缺失");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!coordinatesNode.isArray()) {
|
||||||
|
throw new IOException("coordinates 字段必须是数组类型");
|
||||||
|
}
|
||||||
|
|
||||||
List<PGpoint> points = new ArrayList<>();
|
List<PGpoint> points = new ArrayList<>();
|
||||||
for (JsonNode coordNode : coordinatesNode) {
|
for (int i = 0; i < coordinatesNode.size(); i++) {
|
||||||
if (coordNode.isArray() && coordNode.size() >= 2) {
|
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 x = coordNode.get(0).asDouble();
|
||||||
double y = coordNode.get(1).asDouble();
|
double y = coordNode.get(1).asDouble();
|
||||||
points.add(new PGpoint(x, y));
|
PGpoint point = new PGpoint(x, y);
|
||||||
|
points.add(point);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new IOException("坐标 " + i + " 格式错误: " + coordNode, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return createPGpolygonFromPoints(points);
|
return createPGpolygonFromPoints(points);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,26 +123,40 @@ public class PGpolygonDeserializer extends JsonDeserializer<PGpolygon> {
|
|||||||
* 解析 GeoJSON 格式
|
* 解析 GeoJSON 格式
|
||||||
*/
|
*/
|
||||||
private PGpolygon parseFromGeoJSON(JsonNode node) throws IOException {
|
private PGpolygon parseFromGeoJSON(JsonNode node) throws IOException {
|
||||||
|
|
||||||
JsonNode coordinatesNode = node.get("coordinates");
|
JsonNode coordinatesNode = node.get("coordinates");
|
||||||
if (coordinatesNode == null || !coordinatesNode.isArray() || coordinatesNode.isEmpty()) {
|
if (coordinatesNode == null) {
|
||||||
throw new IOException("coordinates 字段缺失或格式错误");
|
throw new IOException("coordinates 字段缺失");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!coordinatesNode.isArray() || coordinatesNode.isEmpty()) {
|
||||||
|
throw new IOException("coordinates 字段必须是非空数组");
|
||||||
|
}
|
||||||
|
|
||||||
// GeoJSON 格式: coordinates 是三维数组 [[[x1,y1], [x2,y2], ...]]
|
// GeoJSON 格式: coordinates 是三维数组 [[[x1,y1], [x2,y2], ...]]
|
||||||
JsonNode ringNode = coordinatesNode.get(0);
|
|
||||||
if (!ringNode.isArray()) {
|
|
||||||
throw new IOException("GeoJSON coordinates 格式错误");
|
|
||||||
}
|
|
||||||
|
|
||||||
List<PGpoint> points = new ArrayList<>();
|
List<PGpoint> points = new ArrayList<>();
|
||||||
for (JsonNode coordNode : ringNode) {
|
for (int i = 0; i < coordinatesNode.size(); i++) {
|
||||||
if (coordNode.isArray() && coordNode.size() >= 2) {
|
JsonNode ringNode = coordinatesNode.get(i);
|
||||||
double x = coordNode.get(0).asDouble();
|
if (!ringNode.isArray()) {
|
||||||
double y = coordNode.get(1).asDouble();
|
throw new IOException("GeoJSON coordinates 第一环必须是数组");
|
||||||
points.add(new PGpoint(x, y));
|
}
|
||||||
|
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);
|
return createPGpolygonFromPoints(points);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,15 +164,29 @@ public class PGpolygonDeserializer extends JsonDeserializer<PGpolygon> {
|
|||||||
* 解析坐标数组格式
|
* 解析坐标数组格式
|
||||||
*/
|
*/
|
||||||
private PGpolygon parseFromArray(JsonNode node) throws IOException {
|
private PGpolygon parseFromArray(JsonNode node) throws IOException {
|
||||||
|
|
||||||
List<PGpoint> points = new ArrayList<>();
|
List<PGpoint> points = new ArrayList<>();
|
||||||
for (JsonNode coordNode : node) {
|
for (int i = 0; i < node.size(); i++) {
|
||||||
if (coordNode.isArray() && coordNode.size() >= 2) {
|
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 x = coordNode.get(0).asDouble();
|
||||||
double y = coordNode.get(1).asDouble();
|
double y = coordNode.get(1).asDouble();
|
||||||
points.add(new PGpoint(x, y));
|
PGpoint point = new PGpoint(x, y);
|
||||||
|
points.add(point);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new IOException("坐标 " + i + " 格式错误: " + coordNode, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return createPGpolygonFromPoints(points);
|
return createPGpolygonFromPoints(points);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,8 +194,15 @@ public class PGpolygonDeserializer extends JsonDeserializer<PGpolygon> {
|
|||||||
* 解析字符串格式
|
* 解析字符串格式
|
||||||
*/
|
*/
|
||||||
private PGpolygon parseFromString(String polygonString) throws IOException {
|
private PGpolygon parseFromString(String polygonString) throws IOException {
|
||||||
|
|
||||||
|
if (polygonString == null || polygonString.trim().isEmpty()) {
|
||||||
|
throw new IOException("多边形字符串为空");
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return new PGpolygon(polygonString);
|
PGpolygon polygon = new PGpolygon(polygonString);
|
||||||
|
System.out.println("字符串解析成功");
|
||||||
|
return polygon;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new IOException("PGpolygon 字符串格式解析失败: " + polygonString, e);
|
throw new IOException("PGpolygon 字符串格式解析失败: " + polygonString, e);
|
||||||
}
|
}
|
||||||
@ -138,34 +212,59 @@ public class PGpolygonDeserializer extends JsonDeserializer<PGpolygon> {
|
|||||||
* 从点列表创建 PGpolygon
|
* 从点列表创建 PGpolygon
|
||||||
*/
|
*/
|
||||||
private PGpolygon createPGpolygonFromPoints(List<PGpoint> points) throws IOException {
|
private PGpolygon createPGpolygonFromPoints(List<PGpoint> points) throws IOException {
|
||||||
if (points == null || points.size() < 3) {
|
|
||||||
throw new IOException("多边形至少需要3个点");
|
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 {
|
try {
|
||||||
// 构建多边形字符串格式:((x1 y1, x2 y2, x3 y3, x1 y1))
|
// 构建正确的多边形字符串格式
|
||||||
StringBuilder sb = new StringBuilder("((");
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
|
||||||
for (int i = 0; i < points.size(); i++) {
|
for (int i = 0; i < points.size(); i++) {
|
||||||
PGpoint point = points.get(i);
|
PGpoint point = points.get(i);
|
||||||
sb.append(point.x).append(" ").append(point.y);
|
if (i == 0) {
|
||||||
|
sb.append("("); // 开始内括号
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.append("(").append(point.x).append(",").append(point.y).append(")");
|
||||||
|
|
||||||
if (i < points.size() - 1) {
|
if (i < points.size() - 1) {
|
||||||
sb.append(", ");
|
sb.append(",");
|
||||||
|
} else {
|
||||||
|
sb.append(")"); // 结束内括号
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 确保多边形闭合(首尾点相同)
|
// 确保多边形闭合
|
||||||
PGpoint firstPoint = points.get(0);
|
PGpoint firstPoint = points.get(0);
|
||||||
PGpoint lastPoint = points.get(points.size() - 1);
|
PGpoint lastPoint = points.get(points.size() - 1);
|
||||||
|
|
||||||
if (firstPoint.x != lastPoint.x || firstPoint.y != lastPoint.y) {
|
if (firstPoint.x != lastPoint.x || firstPoint.y != lastPoint.y) {
|
||||||
sb.append(", ").append(firstPoint.x).append(" ").append(firstPoint.y);
|
log.info("多边形未闭合,添加首点以闭合");
|
||||||
|
sb.append(",(").append(firstPoint.x).append(",").append(firstPoint.y).append(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.append("))");
|
|
||||||
|
String polygonString = sb.toString();
|
||||||
return new PGpolygon(sb.toString());
|
|
||||||
|
return new PGpolygon(polygonString);
|
||||||
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new IOException("创建 PGpolygon 失败", e);
|
throw new IOException("创建 PGpolygon 失败: " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -42,7 +42,7 @@ public class PGpolygonSerializer extends JsonSerializer<PGpolygon> {
|
|||||||
if (points[i] == null) {
|
if (points[i] == null) {
|
||||||
log.error("错误: 第 {} 个点为 null", i);
|
log.error("错误: 第 {} 个点为 null", i);
|
||||||
} else {
|
} else {
|
||||||
log.error("点 {}: ({}, {})", i, points[i].x, points[i].y);
|
log.info("点 {}: ({}, {})", i, points[i].x, points[i].y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,13 +246,10 @@ public class PGpolygonSerializer extends JsonSerializer<PGpolygon> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<PGpoint> filtered = new ArrayList<>();
|
List<PGpoint> filtered = new ArrayList<>();
|
||||||
int nullCount = 0;
|
|
||||||
|
|
||||||
for (PGpoint point : points) {
|
for (PGpoint point : points) {
|
||||||
if (point != null) {
|
if (point != null) {
|
||||||
filtered.add(point);
|
filtered.add(point);
|
||||||
} else {
|
|
||||||
nullCount++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -57,9 +57,4 @@ public class EbikeRegionVo implements Serializable {
|
|||||||
@JsonDeserialize(using = PGpolygonDeserializer.class)
|
@JsonDeserialize(using = PGpolygonDeserializer.class)
|
||||||
private PGpolygon regionPolygon;
|
private PGpolygon regionPolygon;
|
||||||
|
|
||||||
/**
|
|
||||||
* 运营区状态:0-未运营 1-运营中 2-停止运营
|
|
||||||
*/
|
|
||||||
private Integer status;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,17 @@
|
|||||||
package com.cdzy.operations.service.impl;
|
package com.cdzy.operations.service.impl;
|
||||||
|
|
||||||
import com.cdzy.operations.model.vo.EbikeRegionVo;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import com.mybatisflex.spring.service.impl.ServiceImpl;
|
import com.cdzy.operations.enums.RegionStatus;
|
||||||
import com.cdzy.operations.model.entity.EbikeRegion;
|
|
||||||
import com.cdzy.operations.mapper.EbikeRegionMapper;
|
import com.cdzy.operations.mapper.EbikeRegionMapper;
|
||||||
|
import com.cdzy.operations.model.entity.EbikeRegion;
|
||||||
|
import com.cdzy.operations.model.vo.EbikeRegionVo;
|
||||||
import com.cdzy.operations.service.EbikeRegionService;
|
import com.cdzy.operations.service.EbikeRegionService;
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
|
import com.mybatisflex.spring.service.impl.ServiceImpl;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import static com.cdzy.operations.model.entity.table.EbikeRegionTableDef.EBIKE_REGION;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 运营区域表 服务层实现。
|
* 运营区域表 服务层实现。
|
||||||
*
|
*
|
||||||
@ -14,15 +19,30 @@ import org.springframework.stereotype.Service;
|
|||||||
* @since 2025-10-22
|
* @since 2025-10-22
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class EbikeRegionServiceImpl extends ServiceImpl<EbikeRegionMapper, EbikeRegion> implements EbikeRegionService{
|
public class EbikeRegionServiceImpl extends ServiceImpl<EbikeRegionMapper, EbikeRegion> implements EbikeRegionService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void save(EbikeRegionVo ebikeRegion) {
|
public void save(EbikeRegionVo ebikeRegion) {
|
||||||
|
EbikeRegion entity = EbikeRegion.builder()
|
||||||
|
.operatorId(ebikeRegion.getOperatorId())
|
||||||
|
.regionPolygon(ebikeRegion.getRegionPolygon())
|
||||||
|
.regionName(ebikeRegion.getRegionName())
|
||||||
|
.regionSimpleName(ebikeRegion.getRegionSimpleName())
|
||||||
|
.status(RegionStatus.UN_OPERATION)
|
||||||
|
.createdBy(StpUtil.getLoginIdAsLong())
|
||||||
|
.build();
|
||||||
|
this.mapper.insert(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(EbikeRegionVo ebikeRegion) {
|
public void update(EbikeRegionVo ebikeRegion) {
|
||||||
|
QueryWrapper queryWrapper = QueryWrapper.create()
|
||||||
|
.where(EBIKE_REGION.REGION_ID.eq(ebikeRegion.getRegionId()));
|
||||||
|
EbikeRegion region = this.mapper.selectOneByQuery(queryWrapper);
|
||||||
|
region.setOperatorId(ebikeRegion.getOperatorId());
|
||||||
|
region.setRegionPolygon(ebikeRegion.getRegionPolygon());
|
||||||
|
region.setRegionName(ebikeRegion.getRegionName());
|
||||||
|
region.setRegionSimpleName(ebikeRegion.getRegionSimpleName());
|
||||||
|
this.mapper.update(region);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user