本文档定义了车辆服务(Vehicle Service)与外部 TSP(Telematics Service Provider)平台对接的完整链路设计,包括同步/异步场景划分、调用路径选择等。
适用场景:需要业务逻辑处理、数据聚合、权限校验等
适用场景:纯车辆操作,无需业务逻辑,性能要求高
| 场景 | 接口路径 | 调用链路 | TSP 指令 | 说明 |
|---|---|---|---|---|
| 开锁 | /app/vehicle/control/unlock |
路径一 | UNLOCK |
用户点击开锁,需立即反馈成功/失败 |
| 关锁 | /app/vehicle/control/lock |
路径一 | LOCK |
用户点击关锁,需立即反馈 |
| 启动 | /app/vehicle/control/start |
路径一 | START |
远程启动车辆,需立即反馈 |
| 熄火 | /app/vehicle/control/stop |
路径一 | STOP |
远程熄火,需立即反馈 |
| 鸣笛 | /app/vehicle/control/horn |
路径一 | HORN |
寻车鸣笛,需立即反馈 |
| 灯光 | /app/vehicle/control/light |
路径一 | LIGHT |
灯光控制,需立即反馈 |
实现方式:
// Vehicle Service 中实现
@Service
public class VehicleControlServiceImpl {
@Resource
private TspApiClient tspApiClient; // Feign 客户端
public CommonResult<Boolean> controlVehicle(VehicleControlReqDTO reqDTO) {
// 1. 同步调用 TSP
TspControlResponse response = tspApiClient.sendControlCommand(
convertToTspRequest(reqDTO)
);
// 2. 处理响应(立即返回)
if (response.isSuccess()) {
// 更新本地状态
updateLocalStatus(reqDTO.getVehicleId(), response);
return success(true);
} else {
// 记录失败原因
log.error("TSP控制失败: {}", response.getErrorMsg());
return error(response.getErrorCode(), response.getErrorMsg());
}
}
}
链路图:
客户端 → Gateway → Business Service → Vehicle Service → [HTTP同步] → TSP平台
↓
立即返回结果
↓
客户端 ← Gateway ← Business Service ← Vehicle Service ← [直接返回]
| 场景 | 接口路径 | 调用链路 | TSP 接口 | 说明 |
|---|---|---|---|---|
| 查询实时状态 | /app/vehicle/status |
路径一 | GET_STATUS |
查询电量、里程、速度等,需实时返回 |
| 查询位置信息 | /app/vehicle/location |
路径一 | GET_LOCATION |
查询车辆GPS位置,需实时返回 |
| 查询车辆信息 | /app/vehicle/get |
路径一 | GET_VEHICLE_INFO |
查询车辆基本信息,可能从TSP获取 |
实现方式:
@Service
public class VehicleStatusServiceImpl {
@Resource
private TspApiClient tspApiClient;
public VehicleStatusRespDTO getVehicleStatus(Long vehicleId) {
// 1. 先查本地缓存(如果有)
VehicleStatusDO localStatus = vehicleStatusMapper.selectByVehicleId(vehicleId);
// 2. 如果本地数据过期(>5分钟),从TSP实时查询
if (localStatus == null || isExpired(localStatus)) {
TspStatusResponse tspResponse = tspApiClient.getRealTimeStatus(vehicleId);
// 更新本地并返回
return updateAndConvert(tspResponse);
}
return convert(localStatus);
}
}
链路图:
客户端 → Gateway → Business Service → Vehicle Service → [HTTP同步] → TSP平台
↓
实时状态数据
↓
客户端 ← Gateway ← Business Service ← Vehicle Service ← [立即返回]
| 场景 | 接口路径 | 调用链路 | TSP 接口 | 说明 |
|---|---|---|---|---|
| 绑定车辆 | /app/vehicle/bind |
路径一 | BIND_VEHICLE |
绑定车辆到TSP,需立即确认 |
| 解绑车辆 | /app/vehicle/unbind |
路径一 | UNBIND_VEHICLE |
解绑车辆,需立即确认 |
说明:绑定/解绑操作需要 TSP 立即返回结果,因为涉及权限变更。
| 场景类型 | 数量 | 特点 | 超时时间 |
|---|---|---|---|
| 车辆控制 | 6个 | 用户操作,需立即反馈 | 5秒 |
| 状态查询 | 3个 | 实时数据,需立即返回 | 3秒 |
| 绑定操作 | 2个 | 权限变更,需立即确认 | 5秒 |
| 总计 | 11个 | - | - |
| 场景 | 触发方式 | Kafka Topic | 说明 |
|---|---|---|---|
| 车辆状态上报 | TSP 定时推送 | tsp-status-report |
电量、里程、速度等状态变化 |
| 位置信息上报 | TSP GPS推送 | tsp-location-report |
车辆位置实时更新 |
| 报警信息上报 | TSP 异常检测 | tsp-alarm-report |
车辆异常、故障报警 |
| 车辆事件上报 | TSP 事件触发 | tsp-event-report |
开门、关门、启动等事件 |
实现方式:
// Vehicle Service 中实现 Kafka 消费者
@Component
public class TspStatusReportConsumer {
@Resource
private VehicleStatusService vehicleStatusService;
@Resource
private RedisMQTemplate redisMQTemplate; // 推送给客户端
@KafkaListener(topics = "tsp-status-report")
public void handleStatusReport(TspStatusReportMessage message) {
// 1. 更新本地数据库
vehicleStatusService.updateStatus(message.getVehicleId(), message);
// 2. 推送给客户端(通过 Redis MQ → Message Service → WebSocket)
VehicleStatusMessage pushMessage = convert(message);
redisMQTemplate.send("vehicle-status-push", pushMessage);
log.info("车辆状态已更新并推送: vehicleId={}", message.getVehicleId());
}
}
链路图:
TSP平台 → [Kafka Producer] → Kafka Topic: tsp-status-report
↓
Vehicle Service (Kafka Consumer)
↓
更新本地数据库
↓
Redis MQ → Message Service
↓
WebSocket → 客户端(实时推送)
| 场景 | 触发方式 | Kafka Topic | 说明 |
|---|---|---|---|
| 历史轨迹上报 | TSP 批量推送 | tsp-track-report |
车辆历史行驶轨迹 |
| 统计数据上报 | TSP 定时汇总 | tsp-statistics-report |
日/周/月统计数据 |
| 诊断数据上报 | TSP 诊断完成 | tsp-diagnosis-report |
车辆诊断报告 |
说明:这些数据量大,处理时间长,必须异步处理。
| 场景 | 接口路径 | 调用链路 | 说明 |
|---|---|---|---|
| OTA升级 | /app/vehicle/ota/upgrade |
路径一 | 固件升级,可能需要10-30分钟 |
| 远程诊断 | /app/vehicle/diagnosis |
路径一 | 车辆诊断,可能需要5-10分钟 |
实现方式:
@Service
public class VehicleOtaServiceImpl {
public CommonResult<String> startOtaUpgrade(VehicleOtaReqDTO reqDTO) {
// 1. 发送升级请求到 TSP(异步,不等待)
String taskId = UUID.randomUUID().toString();
kafkaTemplate.send("tsp-ota-request", new TspOtaRequestMessage(taskId, reqDTO));
// 2. 立即返回任务ID
return success(taskId);
}
// TSP 通过 Kafka 回调升级结果
@KafkaListener(topics = "tsp-ota-result")
public void handleOtaResult(TspOtaResultMessage message) {
// 更新升级状态
updateOtaStatus(message.getTaskId(), message);
// 推送结果到客户端
pushOtaResultToClient(message);
}
}
链路图:
客户端 → Gateway → Business Service → Vehicle Service → [Kafka发送] → TSP平台
↓
立即返回任务ID
↓
客户端 ← Gateway ← Business Service ← Vehicle Service ← [返回taskId]
(后续)
TSP平台处理完成 → [Kafka回调] → Vehicle Service → 推送结果到客户端
| 场景类型 | 数量 | 特点 | Kafka Topic |
|---|---|---|---|
| 状态上报 | 4个 | TSP主动推送,高并发 | tsp-status-report 等 |
| 批量数据 | 3个 | 数据量大,处理时间长 | tsp-track-report 等 |
| 长时间任务 | 2个 | 处理时间>5分钟 | tsp-ota-result 等 |
| 总计 | 9个 | - | - |
| 场景 | 接口路径 | 调用链路 | 说明 |
|---|---|---|---|
| 查询车辆状态 | /app-api/vehicle/status |
路径二 | 直接查询,无需业务逻辑 |
| 查询车辆位置 | /app-api/vehicle/location |
路径二 | 直接查询GPS位置 |
Gateway 路由配置:
spring:
cloud:
gateway:
routes:
# 车辆状态查询直接走 Vehicle Service
- id: vehicle-status-direct
uri: lb://xdz-vehicle
predicates:
- Path=/app-api/vehicle/status,/app-api/vehicle/location
filters:
- StripPrefix=1
链路图:
客户端 → Gateway → Vehicle Service → TSP平台
↓
直接返回
↓
客户端 ← Gateway ← Vehicle Service
| 场景 | 接口路径 | 调用链路 | 说明 |
|---|---|---|---|
| 快速开锁 | /app-api/vehicle/control/unlock |
路径二 | 紧急情况,需要最快响应 |
| 快速关锁 | /app-api/vehicle/control/lock |
路径二 | 紧急情况,需要最快响应 |
说明:这些是紧急操作,需要最快响应,不走 Business Service 可以减少延迟。
| 场景 | 接口路径 | 调用链路 | 说明 |
|---|---|---|---|
| TSP HTTP回调 | /tsp/callback/** |
路径二 | TSP 直接回调 Vehicle Service |
| TSP Webhook | /tsp/webhook/** |
路径二 | TSP 事件推送 |
说明:TSP 的回调接口应该直接暴露在 Vehicle Service,不需要经过 Business Service。
实现方式:
@RestController
@RequestMapping("/tsp")
public class TspCallbackController {
@PostMapping("/callback/status")
public CommonResult<Boolean> handleStatusCallback(@RequestBody TspStatusCallback callback) {
// 直接处理 TSP 回调,更新状态
vehicleStatusService.updateFromTsp(callback);
return success(true);
}
}
| 场景类型 | 数量 | 特点 | 路由前缀 |
|---|---|---|---|
| 状态查询 | 2个 | 实时查询,性能要求高 | /app-api/vehicle/status |
| 快速控制 | 2个 | 紧急操作,延迟要求低 | /app-api/vehicle/control |
| TSP回调 | 2个 | 外部系统回调 | /tsp/callback |
| 总计 | 6个 | - | - |
| 序号 | 场景 | 接口路径 | 调用链路 | TSP接口 | 超时时间 |
|---|---|---|---|---|---|
| 1 | 开锁 | /app/vehicle/control/unlock |
路径一 | UNLOCK |
5秒 |
| 2 | 关锁 | /app/vehicle/control/lock |
路径一 | LOCK |
5秒 |
| 3 | 启动 | /app/vehicle/control/start |
路径一 | START |
5秒 |
| 4 | 熄火 | /app/vehicle/control/stop |
路径一 | STOP |
5秒 |
| 5 | 鸣笛 | /app/vehicle/control/horn |
路径一 | HORN |
5秒 |
| 6 | 灯光 | /app/vehicle/control/light |
路径一 | LIGHT |
5秒 |
| 7 | 查询状态 | /app/vehicle/status |
路径一 | GET_STATUS |
3秒 |
| 8 | 查询位置 | /app/vehicle/location |
路径一 | GET_LOCATION |
3秒 |
| 9 | 查询信息 | /app/vehicle/get |
路径一 | GET_VEHICLE_INFO |
3秒 |
| 10 | 绑定车辆 | /app/vehicle/bind |
路径一 | BIND_VEHICLE |
5秒 |
| 11 | 解绑车辆 | /app/vehicle/unbind |
路径一 | UNBIND_VEHICLE |
5秒 |
| 序号 | 场景 | 触发方式 | Kafka Topic | 说明 |
|---|---|---|---|---|
| 1 | 状态上报 | TSP推送 | tsp-status-report |
电量、里程、速度 |
| 2 | 位置上报 | TSP推送 | tsp-location-report |
GPS位置更新 |
| 3 | 报警上报 | TSP推送 | tsp-alarm-report |
车辆异常报警 |
| 4 | 事件上报 | TSP推送 | tsp-event-report |
开门、关门等事件 |
| 5 | 轨迹上报 | TSP批量 | tsp-track-report |
历史行驶轨迹 |
| 6 | 统计上报 | TSP定时 | tsp-statistics-report |
日/周/月统计 |
| 7 | 诊断上报 | TSP完成 | tsp-diagnosis-report |
诊断报告 |
| 8 | OTA升级 | 客户端触发 | tsp-ota-result |
固件升级结果 |
| 9 | 远程诊断 | 客户端触发 | tsp-diagnosis-result |
诊断结果 |
| 序号 | 场景 | 接口路径 | 调用链路 | 说明 |
|---|---|---|---|---|
| 1 | 快速状态查询 | /app-api/vehicle/status |
路径二 | 直接查询,不走业务服务 |
| 2 | 快速位置查询 | /app-api/vehicle/location |
路径二 | 直接查询,不走业务服务 |
| 3 | 快速开锁 | /app-api/vehicle/control/unlock |
路径二 | 紧急操作,最快响应 |
| 4 | 快速关锁 | /app-api/vehicle/control/lock |
路径二 | 紧急操作,最快响应 |
| 5 | TSP HTTP回调 | /tsp/callback/** |
路径二 | TSP直接回调 |
| 6 | TSP Webhook | /tsp/webhook/** |
路径二 | TSP事件推送 |
使用 Feign 客户端:
@FeignClient(name = "tsp-platform", url = "${tsp.url}")
public interface TspApiClient {
@PostMapping("/api/v1/vehicle/control")
TspControlResponse sendControlCommand(@RequestBody TspControlRequest request);
@GetMapping("/api/v1/vehicle/{vehicleId}/status")
TspStatusResponse getRealTimeStatus(@PathVariable("vehicleId") Long vehicleId);
}
配置超时时间:
feign:
client:
config:
tsp-platform:
connectTimeout: 3000
readTimeout: 5000
Kafka 配置:
spring:
kafka:
bootstrap-servers: ${kafka.servers}
producer:
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
consumer:
group-id: vehicle-service-group
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
消费者实现:
@Component
@Slf4j
public class TspMessageConsumer {
@KafkaListener(topics = "tsp-status-report")
public void consumeStatusReport(TspStatusReportMessage message) {
// 处理消息
}
}
spring:
cloud:
gateway:
routes:
# 直接调用 Vehicle Service 的路由
- id: vehicle-direct
uri: lb://xdz-vehicle
predicates:
- Path=/app-api/vehicle/**,/tsp/**
filters:
- StripPrefix=0
# 通过 Business Service 的路由
- id: vehicle-via-business
uri: lb://xdz-business
predicates:
- Path=/app/vehicle/**
filters:
- StripPrefix=0
| 类型 | 数量 | 占比 |
|---|---|---|
| 同步场景 | 11个 | 42% |
| 异步场景 | 9个 | 35% |
| 直接调用 | 6个 | 23% |
| 总计 | 26个 | 100% |
docs/tsp-api.mddocs/kafka-topics.mddocs/gateway-routes.md文档版本:v1.0
最后更新:2025-01-XX
维护人:Vehicle Service Team