Commit b8dd5a8ba1be322462ae906bf76e3d49dfa3595a

Authored by alexyang
1 parent 8a764994

完善以运输单创建轨迹的功能逻辑,新增路径规划、轨迹点解析及轨迹点上传功能

sl-express-ms-track-service/src/main/java/com/sl/ms/track/service/impl/TrackServiceImpl.java
1 1 package com.sl.ms.track.service.impl;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.hutool.core.convert.Convert;
4 5 import cn.hutool.core.map.MapUtil;
5 6 import cn.hutool.core.util.StrUtil;
... ... @@ -18,9 +19,15 @@ import com.sl.ms.track.service.TrackService;
18 19 import com.sl.ms.work.api.TransportOrderFeign;
19 20 import com.sl.ms.work.domain.dto.TransportOrderDTO;
20 21 import org.springframework.beans.factory.annotation.Autowired;
  22 +import org.springframework.data.geo.Point;
21 23 import org.springframework.data.mongodb.core.MongoTemplate;
  24 +import org.springframework.data.mongodb.core.geo.GeoJsonLineString;
  25 +import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
  26 +import org.springframework.data.mongodb.core.query.Criteria;
  27 +import org.springframework.data.mongodb.core.query.Query;
22 28 import org.springframework.stereotype.Service;
23 29  
  30 +import java.util.ArrayList;
24 31 import java.util.List;
25 32 import java.util.Map;
26 33  
... ... @@ -39,49 +46,115 @@ public class TrackServiceImpl implements TrackService {
39 46 @Autowired
40 47 private EagleMapTemplate eagleMapTemplate;
41 48  
  49 + /**
  50 + * 创建运输轨迹
  51 + * 根据运输单ID获取起止位置,调用高德地图API规划路线,并保存轨迹信息到MongoDB
  52 + *
  53 + * @param transportOrderId 运输单ID
  54 + * @return 创建成功返回true,失败返回false
  55 + */
42 56 @Override
43 57 public boolean create(String transportOrderId) {
  58 + // 1. 获取运输单和订单位置信息
44 59 TransportOrderDTO transportOrderDTO = transportOrderFeign.findById(transportOrderId);
45   -
46 60 OrderLocationDTO orderLocationDTO = orderFeign.findOrderLocationByOrderId(transportOrderDTO.getOrderId());
47 61  
48   - TrackEntity trackEntity = new TrackEntity();
49   - trackEntity.setTransportOrderId(transportOrderId);
50   -
51   - String sendLocation = orderLocationDTO.getSendLocation();
52   - String receiveLocation = orderLocationDTO.getReceiveLocation();
  62 + // 2. 解析起止坐标(格式:经度,纬度)
  63 + Coordinate origin = parseCoordinate(orderLocationDTO.getSendLocation());
  64 + Coordinate destination = parseCoordinate(orderLocationDTO.getReceiveLocation());
53 65  
54   - double sendLnt = Double.parseDouble(sendLocation.split(",")[0]);
55   - double sendLat = Double.parseDouble(sendLocation.split(",")[1]);
  66 + // 3. 调用高德地图API进行路径规划
  67 + Map<String, Object> param = MapUtil.<String, Object>builder()
  68 + .put("show_fields", "polyline") // 返回详细路径坐标
  69 + .build();
  70 + String driving = this.eagleMapTemplate.opsForDirection()
  71 + .driving(ProviderEnum.AMAP, origin, destination, param);
56 72  
57   -
58   - double receiveLnt = Double.parseDouble(receiveLocation.split(",")[0]);
59   - double receiveLat = Double.parseDouble(receiveLocation.split(",")[1]);
60   -
61   - Coordinate origin = new Coordinate(sendLnt, sendLat);
62   - Coordinate destination = new Coordinate(receiveLnt, receiveLat);
63   -
64   - //设置高德地图参数,默认是不返回预计耗时的,需要额外设置参数
65   - Map<String, Object> param = MapUtil.<String, Object>builder().put("show_fields", "polyline").build();
66   - String driving = this.eagleMapTemplate.opsForDirection().driving(ProviderEnum.AMAP, origin, destination, param);
  73 + // 如果路径规划失败,直接返回
67 74 if (StrUtil.isEmpty(driving)) {
68 75 return false;
69 76 }
70   - JSONObject jsonObject = JSONUtil.parseObj(driving);
71 77  
72   - //距离,单位:米
73   - Double distance = Convert.toDouble(jsonObject.getByPath("route.paths[0].distance"), -1d);
  78 + // 4. 解析高德地图返回的路径数据
  79 + JSONObject routeData = JSONUtil.parseObj(driving);
  80 + Double distance = Convert.toDouble(routeData.getByPath("route.paths[0].distance"), -1d);
  81 + JSONArray steps = routeData.getByPath("route.paths[0].steps", JSONArray.class);
  82 +
  83 + // 5. 从路径数据中提取所有轨迹点
  84 + List<Point> trackPoints = collectTrackPoints(steps);
  85 +
  86 + // 6. 构建轨迹实体对象
  87 + TrackEntity trackEntity = new TrackEntity();
  88 + trackEntity.setTransportOrderId(transportOrderId);
74 89 trackEntity.setDistance(distance);
75 90 trackEntity.setStatus(TrackStatusEnum.NEW);
76 91 trackEntity.setType(TrackTypeEnum.COURIER);
77 92  
78   - JSONArray steps = jsonObject.getByPath("route.paths[0].steps", JSONArray.class);
  93 + // 7. 如果轨迹点足够(至少2个点),设置规划路线
  94 + if (trackPoints.size() >= 2) {
  95 + trackEntity.setPlanGeoJsonLine(new GeoJsonLineString(trackPoints));
  96 + trackEntity.setLastPoint((GeoJsonPoint) trackPoints.get(0));
  97 + }
  98 +
  99 + // 8. 保存轨迹信息到MongoDB
  100 + mongoTemplate.save(trackEntity);
  101 + return true;
  102 + }
  103 +
  104 + /**
  105 + * 解析坐标字符串
  106 + * 将"经度,纬度"格式的字符串转换为Coordinate对象
  107 + *
  108 + * @param location 位置字符串,格式:经度,纬度(例如:116.397128,39.916527)
  109 + * @return Coordinate对象
  110 + */
  111 + private Coordinate parseCoordinate(String location) {
  112 + String[] parts = location.split(",");
  113 + double lng = Double.parseDouble(parts[0]);
  114 + double lat = Double.parseDouble(parts[1]);
  115 + return new Coordinate(lng, lat);
  116 + }
  117 +
  118 + /**
  119 + * 从高德地图路径steps中收集所有轨迹点
  120 + * 遍历每个step的polyline字段,解析出所有坐标点
  121 + *
  122 + * @param steps 高德地图返回的路径步骤数组
  123 + * @return 轨迹点列表
  124 + */
  125 + private List<Point> collectTrackPoints(JSONArray steps) {
  126 + List<Point> points = new ArrayList<>();
  127 +
79 128 for (int i = 0; i < steps.size(); i++) {
80   - JSONObject entries = steps.getJSONObject(i);
81   - String polyline = entries.getStr("polyline");
  129 + JSONObject step = steps.getJSONObject(i);
  130 + String polyline = step.getStr("polyline");
  131 +
  132 + if (StrUtil.isEmpty(polyline)) {
  133 + continue;
  134 + }
  135 +
  136 + // polyline格式:经度1,纬度1;经度2,纬度2;经度3,纬度3...
  137 + String[] coordPairs = polyline.split(";");
  138 + for (String coordPair : coordPairs) {
  139 + if (StrUtil.isEmpty(coordPair)) {
  140 + continue;
  141 + }
  142 +
  143 + // 解析单个坐标点
  144 + String[] coords = coordPair.split(",");
  145 + if (coords.length == 2) {
  146 + try {
  147 + double lng = Double.parseDouble(coords[0].trim());
  148 + double lat = Double.parseDouble(coords[1].trim());
  149 + points.add(new GeoJsonPoint(lng, lat));
  150 + } catch (NumberFormatException e) {
  151 + // 忽略无法解析的坐标点
  152 + }
  153 + }
  154 + }
82 155 }
83 156  
84   - return false;
  157 + return points;
85 158 }
86 159  
87 160 @Override
... ... @@ -91,16 +164,54 @@ public class TrackServiceImpl implements TrackService {
91 164  
92 165 @Override
93 166 public TrackEntity queryByTransportOrderId(String transportOrderId) {
94   - return null;
  167 + Query query = Query.query(Criteria.where("transportOrderId").is(transportOrderId));
  168 + return mongoTemplate.findOne(query, TrackEntity.class);
95 169 }
96 170  
  171 + /**
  172 + * 上传车辆轨迹点信息
  173 + *
  174 + * @param transportTaskId 运输任务id
  175 + * @param lng 经度
  176 + * @param lat 纬度
  177 + * @return 上传成功返回true,失败返回false
  178 + */
97 179 @Override
98 180 public boolean uploadFromTruck(Long transportTaskId, double lng, double lat) {
99 181 return false;
100 182 }
101 183  
  184 + /**
  185 + * 从快递员上传轨迹点信息
  186 + *
  187 + * @param transportOrderIds 运输单ID列表
  188 + * @param lng 经度
  189 + * @param lat 纬度
  190 + * @return 上传成功返回true,失败返回false
  191 + */
102 192 @Override
103 193 public boolean uploadFromCourier(List<String> transportOrderIds, double lng, double lat) {
104   - return false;
  194 + // 1. 校验运输单ID列表是否为空
  195 + if (CollUtil.isEmpty(transportOrderIds)) {
  196 + return false;
  197 + }
  198 +
  199 + // 2. 查询运输单对应的轨迹信息
  200 + Query query = Query.query(Criteria.where("transportOrderId").in(transportOrderIds));
  201 + List<TrackEntity> tracks = mongoTemplate.find(query, TrackEntity.class);
  202 +
  203 + // 3. 如果没有找到对应的轨迹信息,返回false
  204 + if (tracks.isEmpty()) {
  205 + return false;
  206 + }
  207 +
  208 + // 4. 创建新的轨迹点并更新所有轨迹的最新位置
  209 + GeoJsonPoint newPoint = new GeoJsonPoint(lng, lat);
  210 + for (TrackEntity track : tracks) {
  211 + track.setLastPoint(newPoint);
  212 + mongoTemplate.save(track);
  213 + }
  214 +
  215 + return true;
105 216 }
106 217 }
... ...