一、系统架构设计
1. 整体架构
- 前端:用户端小程序/APP + 骑手端APP + 管理后台
- 后端:微服务架构(订单服务、用户服务、配送服务、通知服务等)
- 数据库:MySQL(关系型数据) + Redis(缓存) + MongoDB(日志/轨迹数据)
- 实时通信:WebSocket + MQTT协议
- 地图服务:高德/百度地图API
2. 核心组件
- 订单服务:处理订单创建、状态变更等核心逻辑
- 实时追踪服务:处理位置数据接收、处理和分发
- 通知服务:推送订单状态变更和位置更新
- API网关:统一接口管理和鉴权
二、订单实时追踪实现方案
1. 数据采集层
```java
// 骑手位置上报示例(骑手端APP)
public class RiderLocationUploader {
public void uploadLocation(String orderId, double latitude, double longitude) {
// 1. 校验骑手和订单关联
// 2. 构建位置数据对象
LocationData data = new LocationData(orderId, latitude, longitude, System.currentTimeMillis());
// 3. 通过MQTT上报到服务端
MqttClient client = getMqttClient();
client.publish("/orders/" + orderId + "/location", data.toJson());
// 4. 同时缓存到Redis,设置5秒过期
redisTemplate.opsForValue().set("order:location:" + orderId, data.toJson(), 5, TimeUnit.SECONDS);
}
}
```
2. 实时处理层
```java
// WebSocket消息处理示例
@ServerEndpoint("/ws/order/{orderId}")
public class OrderTrackingWebSocket {
@OnMessage
public void onMessage(String message, Session session, @PathParam("orderId") String orderId) {
// 处理WebSocket消息(主要用于客户端订阅)
}
// 内部方法:推送位置更新
public void pushLocationUpdate(String orderId, LocationData newLocation) {
Set sessions = WebSocketSessionManager.getSessions(orderId);
for (Session session : sessions) {
if (session.isOpen()) {
session.getAsyncRemote().sendText(newLocation.toJson());
}
}
}
}
// MQTT消息监听服务
@Service
public class LocationMqttListener {
@Autowired
private OrderTrackingWebSocket webSocketService;
@MqttListener(topic = "/orders/+/location")
public void handleLocationUpdate(String topic, String payload) {
// 解析订单ID
String orderId = topic.split("/")[2];
LocationData data = LocationData.fromJson(payload);
// 1. 更新数据库中的最后位置
orderRepository.updateLastLocation(orderId, data);
// 2. 计算配送进度(基于起点、终点和当前位置)
double progress = calculateDeliveryProgress(orderId, data);
// 3. 推送更新到所有订阅的客户端
webSocketService.pushLocationUpdate(orderId, data);
// 4. 触发状态变更检查(如到达商家、送达客户等)
checkOrderStatusChange(orderId, data);
}
}
```
3. 数据库设计
```sql
-- 订单表
CREATE TABLE orders (
id VARCHAR(32) PRIMARY KEY,
user_id VARCHAR(32) NOT NULL,
rider_id VARCHAR(32),
status TINYINT NOT NULL COMMENT 1:待接单 2:已接单 3:配送中 4:已完成 5:已取消,
start_address VARCHAR(255) NOT NULL,
end_address VARCHAR(255) NOT NULL,
start_lat DECIMAL(10,6),
start_lng DECIMAL(10,6),
end_lat DECIMAL(10,6),
end_lng DECIMAL(10,6),
create_time DATETIME NOT NULL,
update_time DATETIME NOT NULL
);
-- 订单位置轨迹表(MongoDB更适合)
-- 在MySQL中简化设计
CREATE TABLE order_locations (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
order_id VARCHAR(32) NOT NULL,
rider_id VARCHAR(32) NOT NULL,
latitude DECIMAL(10,6) NOT NULL,
longitude DECIMAL(10,6) NOT NULL,
speed DECIMAL(10,2),
bearing DECIMAL(10,2),
accuracy DECIMAL(10,2),
recorded_at DATETIME NOT NULL,
INDEX idx_order_id (order_id),
INDEX idx_recorded_at (recorded_at)
);
```
三、前端实现要点
1. 用户端小程序实现
```javascript
// 小程序WebSocket连接
Page({
data: {
orderId: 12345,
locationPoints: [],
riderInfo: null
},
onLoad() {
this.connectWebSocket();
},
connectWebSocket() {
const orderId = this.data.orderId;
wx.connectSocket({
url: `wss://yourdomain.com/ws/order/${orderId}`,
success: () => {
console.log(WebSocket连接成功);
}
});
wx.onSocketMessage((res) => {
const data = JSON.parse(res.data);
this.updateOrderTracking(data);
});
},
updateOrderTracking(data) {
// 更新骑手位置
this.setData({
locationPoints: [...this.data.locationPoints, data.location],
riderInfo: data.riderInfo
});
// 重新绘制地图轨迹
this.drawRouteOnMap();
},
drawRouteOnMap() {
// 使用高德/百度地图API绘制骑手轨迹
// ...
}
});
```
2. 骑手端APP实现
```java
// 骑手端位置上报服务(Android示例)
public class LocationUpdateService extends Service {
private FusedLocationProviderClient fusedLocationClient;
private LocationCallback locationCallback;
@Override
public void onCreate() {
super.onCreate();
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
locationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult == null) return;
for (Location location : locationResult.getLocations()) {
uploadRiderLocation(location);
}
}
};
startLocationUpdates();
}
private void startLocationUpdates() {
LocationRequest request = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(5000) // 每5秒更新一次
.setFastestInterval(1000);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
fusedLocationClient.requestLocationUpdates(request, locationCallback, null);
}
}
private void uploadRiderLocation(Location location) {
// 获取当前订单ID(从骑手APP上下文)
String orderId = getCurrentOrderId();
// 构建位置数据
RiderLocationData data = new RiderLocationData(
orderId,
location.getLatitude(),
location.getLongitude(),
location.getSpeed(),
location.getBearing(),
location.getAccuracy(),
System.currentTimeMillis()
);
// 通过MQTT或HTTP上报
LocationUploader.upload(data);
}
}
```
四、关键技术点
1. 实时通信方案
- WebSocket:用于用户端实时接收位置更新
- MQTT协议:骑手端轻量级位置上报(适合移动网络环境)
- HTTP轮询:作为降级方案(当WebSocket不可用时)
2. 位置数据处理
- 数据平滑:使用卡尔曼滤波或均值滤波处理GPS噪声
- 轨迹压缩:采用Douglas-Peucker算法减少数据量
- 位置预测:基于历史轨迹和当前速度预测到达时间
3. 性能优化
- Redis缓存:存储最新位置减少数据库查询
- 空间索引:使用GeoHash或R-Tree加速附近订单查询
- 批量写入:位置数据批量插入提高吞吐量
五、扩展功能
1. 智能预警
```java
// 异常停留检测
public class DeliveryMonitor {
public void checkAbnormalStop(String orderId) {
LocationData lastLocation = orderRepository.getLastLocation(orderId);
if (lastLocation == null) return;
long stopDuration = calculateStopDuration(orderId);
if (stopDuration > 10 * 60 * 1000) { // 停留超过10分钟
// 触发预警
alertService.triggerAlert(orderId, "骑手异常停留");
}
}
private long calculateStopDuration(String orderId) {
// 实现基于位置历史的时间计算
// ...
}
}
```
2. 配送路线优化
- 集成高德/百度地图路径规划API
- 实时交通状况考虑
- 多订单合并配送算法
六、部署方案
1. 容器化部署:使用Docker + Kubernetes实现弹性伸缩
2. 分布式追踪:集成SkyWalking或Zipkin进行链路追踪
3. 监控告警:Prometheus + Grafana监控系统指标
4. 数据持久化:位置数据存储到Elasticsearch便于回溯
七、测试要点
1. 压力测试:模拟万级并发订单追踪
2. 弱网测试:验证2G/3G网络下的表现
3. 位置模拟:使用Mock GPS数据验证轨迹显示
4. 异常场景:测试WebSocket断开重连机制
八、安全考虑
1. 数据加密:位置数据传输使用TLS加密
2. 权限控制:骑手只能上报自己订单的位置
3. 隐私保护:用户地址脱敏显示
4. 防篡改机制:位置数据签名验证
通过以上方案,小象买菜系统可以实现高可靠的订单实时追踪功能,提升用户体验和配送效率。