Commit b8dd5a8ba1be322462ae906bf76e3d49dfa3595a
1 parent
8a764994
完善以运输单创建轨迹的功能逻辑,新增路径规划、轨迹点解析及轨迹点上传功能
Showing
1 changed file
with
138 additions
and
27 deletions
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 | } | ... | ... |