diff --git a/ebike-operations/src/main/java/com/cdzy/operations/enums/RegionStatus.java b/ebike-operations/src/main/java/com/cdzy/operations/enums/RegionStatus.java new file mode 100644 index 0000000..1b97577 --- /dev/null +++ b/ebike-operations/src/main/java/com/cdzy/operations/enums/RegionStatus.java @@ -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; +} diff --git a/ebike-operations/src/main/java/com/cdzy/operations/handler/PGpolygonDeserializer.java b/ebike-operations/src/main/java/com/cdzy/operations/handler/PGpolygonDeserializer.java index 8a55795..9c3cada 100644 --- a/ebike-operations/src/main/java/com/cdzy/operations/handler/PGpolygonDeserializer.java +++ b/ebike-operations/src/main/java/com/cdzy/operations/handler/PGpolygonDeserializer.java @@ -4,6 +4,7 @@ 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; @@ -14,42 +15,62 @@ import java.util.List; /** * PGpolygon 反序列化器 - 将 JSON 反序列化为 PGpolygon */ +@Slf4j public class PGpolygonDeserializer extends JsonDeserializer { @Override public PGpolygon deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { JsonNode node = p.getCodec().readTree(p); - + if (node.isNull()) { return null; } try { - // 支持多种 JSON 格式 - + + PGpolygon result = null; + // 格式1: 自定义格式 {"type": "polygon", "coordinates": [[x1,y1], [x2,y2], ...]} - if (node.isObject() && node.has("type") && "polygon".equals(node.get("type").asText())) { - return parseFromCustomFormat(node); + 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: GeoJSON 格式 {"type": "Polygon", "coordinates": [[[x1,y1], [x2,y2], ...]]} - if (node.isObject() && node.has("type") && "Polygon".equals(node.get("type").asText())) { - return parseFromGeoJSON(node); + + // 格式2: 直接坐标数组 [[x1,y1], [x2,y2], ...] + else if (node.isArray()) { + result = parseFromArray(node); } - - // 格式3: 直接坐标数组 [[x1,y1], [x2,y2], ...] - if (node.isArray()) { - return parseFromArray(node); + + // 格式3: 字符串格式 "((x1 y1, x2 y2, ...))" + else if (node.isTextual()) { + result = parseFromString(node.asText()); } - - // 格式4: 字符串格式 "((x1 y1, x2 y2, ...))" - if (node.isTextual()) { - return parseFromString(node.asText()); + + // 格式4: 对象格式但没有 type 字段,尝试解析 coordinates + else if (node.isObject() && node.has("coordinates")) { + 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) { + System.err.println("!!! PGpolygonDeserializer 反序列化失败 !!!"); + System.err.println("错误信息: " + e.getMessage()); + System.err.println("输入 JSON: " + node); throw new IOException("PGpolygon 反序列化失败: " + e.getMessage(), e); } } @@ -63,20 +84,38 @@ public class PGpolygonDeserializer extends JsonDeserializer { * 解析自定义格式 */ private PGpolygon parseFromCustomFormat(JsonNode node) throws IOException { + JsonNode coordinatesNode = node.get("coordinates"); - if (coordinatesNode == null || !coordinatesNode.isArray()) { - throw new IOException("coordinates 字段缺失或格式错误"); + if (coordinatesNode == null) { + throw new IOException("coordinates 字段缺失"); } - + + if (!coordinatesNode.isArray()) { + throw new IOException("coordinates 字段必须是数组类型"); + } + List points = new ArrayList<>(); - for (JsonNode coordNode : coordinatesNode) { - if (coordNode.isArray() && coordNode.size() >= 2) { + 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(); - 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); } @@ -84,26 +123,40 @@ public class PGpolygonDeserializer extends JsonDeserializer { * 解析 GeoJSON 格式 */ private PGpolygon parseFromGeoJSON(JsonNode node) throws IOException { + JsonNode coordinatesNode = node.get("coordinates"); - if (coordinatesNode == null || !coordinatesNode.isArray() || coordinatesNode.isEmpty()) { - throw new IOException("coordinates 字段缺失或格式错误"); + if (coordinatesNode == null) { + throw new IOException("coordinates 字段缺失"); } - + + if (!coordinatesNode.isArray() || coordinatesNode.isEmpty()) { + throw new IOException("coordinates 字段必须是非空数组"); + } + // GeoJSON 格式: coordinates 是三维数组 [[[x1,y1], [x2,y2], ...]] - JsonNode ringNode = coordinatesNode.get(0); - if (!ringNode.isArray()) { - throw new IOException("GeoJSON coordinates 格式错误"); - } - + List points = new ArrayList<>(); - for (JsonNode coordNode : ringNode) { - if (coordNode.isArray() && coordNode.size() >= 2) { - double x = coordNode.get(0).asDouble(); - double y = coordNode.get(1).asDouble(); - points.add(new PGpoint(x, y)); + 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); } @@ -111,15 +164,29 @@ public class PGpolygonDeserializer extends JsonDeserializer { * 解析坐标数组格式 */ private PGpolygon parseFromArray(JsonNode node) throws IOException { + List points = new ArrayList<>(); - for (JsonNode coordNode : node) { - if (coordNode.isArray() && coordNode.size() >= 2) { + 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(); - 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); } @@ -127,8 +194,15 @@ public class PGpolygonDeserializer extends JsonDeserializer { * 解析字符串格式 */ private PGpolygon parseFromString(String polygonString) throws IOException { + + if (polygonString == null || polygonString.trim().isEmpty()) { + throw new IOException("多边形字符串为空"); + } + try { - return new PGpolygon(polygonString); + PGpolygon polygon = new PGpolygon(polygonString); + System.out.println("字符串解析成功"); + return polygon; } catch (Exception e) { throw new IOException("PGpolygon 字符串格式解析失败: " + polygonString, e); } @@ -138,34 +212,59 @@ public class PGpolygonDeserializer extends JsonDeserializer { * 从点列表创建 PGpolygon */ private PGpolygon createPGpolygonFromPoints(List 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 { - // 构建多边形字符串格式:((x1 y1, x2 y2, x3 y3, x1 y1)) - StringBuilder sb = new StringBuilder("(("); + // 构建正确的多边形字符串格式 + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < points.size(); 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) { - sb.append(", "); + 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) { - sb.append(", ").append(firstPoint.x).append(" ").append(firstPoint.y); + log.info("多边形未闭合,添加首点以闭合"); + sb.append(",(").append(firstPoint.x).append(",").append(firstPoint.y).append(")"); } - - sb.append("))"); - - return new PGpolygon(sb.toString()); - + + + String polygonString = sb.toString(); + + return new PGpolygon(polygonString); + + } catch (Exception e) { - throw new IOException("创建 PGpolygon 失败", e); + throw new IOException("创建 PGpolygon 失败: " + e.getMessage(), e); } } } \ No newline at end of file diff --git a/ebike-operations/src/main/java/com/cdzy/operations/handler/PGpolygonSerializer.java b/ebike-operations/src/main/java/com/cdzy/operations/handler/PGpolygonSerializer.java index 5a90b87..9f7713e 100644 --- a/ebike-operations/src/main/java/com/cdzy/operations/handler/PGpolygonSerializer.java +++ b/ebike-operations/src/main/java/com/cdzy/operations/handler/PGpolygonSerializer.java @@ -42,7 +42,7 @@ public class PGpolygonSerializer extends JsonSerializer { if (points[i] == null) { log.error("错误: 第 {} 个点为 null", i); } 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 { } List filtered = new ArrayList<>(); - int nullCount = 0; for (PGpoint point : points) { if (point != null) { filtered.add(point); - } else { - nullCount++; } } diff --git a/ebike-operations/src/main/java/com/cdzy/operations/model/vo/EbikeRegionVo.java b/ebike-operations/src/main/java/com/cdzy/operations/model/vo/EbikeRegionVo.java index c588375..527d47a 100644 --- a/ebike-operations/src/main/java/com/cdzy/operations/model/vo/EbikeRegionVo.java +++ b/ebike-operations/src/main/java/com/cdzy/operations/model/vo/EbikeRegionVo.java @@ -57,9 +57,4 @@ public class EbikeRegionVo implements Serializable { @JsonDeserialize(using = PGpolygonDeserializer.class) private PGpolygon regionPolygon; - /** - * 运营区状态:0-未运营 1-运营中 2-停止运营 - */ - private Integer status; - } diff --git a/ebike-operations/src/main/java/com/cdzy/operations/service/impl/EbikeRegionServiceImpl.java b/ebike-operations/src/main/java/com/cdzy/operations/service/impl/EbikeRegionServiceImpl.java index f99407b..ea67412 100644 --- a/ebike-operations/src/main/java/com/cdzy/operations/service/impl/EbikeRegionServiceImpl.java +++ b/ebike-operations/src/main/java/com/cdzy/operations/service/impl/EbikeRegionServiceImpl.java @@ -1,12 +1,17 @@ package com.cdzy.operations.service.impl; -import com.cdzy.operations.model.vo.EbikeRegionVo; -import com.mybatisflex.spring.service.impl.ServiceImpl; -import com.cdzy.operations.model.entity.EbikeRegion; +import cn.dev33.satoken.stp.StpUtil; +import com.cdzy.operations.enums.RegionStatus; 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.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; 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 */ @Service -public class EbikeRegionServiceImpl extends ServiceImpl implements EbikeRegionService{ +public class EbikeRegionServiceImpl extends ServiceImpl implements EbikeRegionService { @Override 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 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); } }