zhouhn
2026-02-23 9de6e6b4ef769c6b365bd7fd335d77c50a015d83
统一mqtt的topic地址生成到一个函数方法
2个文件已修改
215 ■■■■■ 已修改文件
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/util/XPUUtil.java 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/test/java/com/xiaopeng/automaticPilot/util/XPUUtilTest.java 161 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/util/XPUUtil.java
@@ -2,9 +2,6 @@
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.xiaopeng.api.dto.automaticPilot.MqttPublishDto;
@@ -14,7 +11,6 @@
import com.xiaopeng.api.vo.automaticPilot.proto.down.*;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudCreateOrder.RTTask;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudOrderOperation.OrderOperation;
import com.xiaopeng.common.core.exception.ServiceException;
import com.xiaopeng.common.core.utils.StringUtils;
import com.xiaopeng.common.core.utils.uuid.UUID;
import lombok.extern.slf4j.Slf4j;
@@ -22,7 +18,6 @@
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -34,8 +29,8 @@
@Component
public class XPUUtil {
    @Value("${xpu.topic}")
    private String topic;
    @Value("${xpu.topic.msg.prefix:Robotaxi/Msg/Xpu}")
    private String topicPrefix;
    @Resource
    private XPUClient xpuClient;
@@ -48,15 +43,13 @@
    // 查询车管 车辆xpuid信息返回字段,用于按需返回字段
    public static final List<String> TYPE_LIST = Collections.singletonList("1");
    /**
     * Robotaxi创建订单推送给XPU
     *
     * @param task
     * @return
     */
    //TODO 没有处理feign调用的异常
    //TODO 处理feign调用的异常
    public MqttPublishDto cloudCreateOrder(RTTask task, String vin, Long sequence) {
        MsgContent msgContent = new MsgContent();
        // 消息头
@@ -71,14 +64,11 @@
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("task", task);
        msgContent.setContent_detail(jsonObject);
        log.info("云端-->XPU 创建订单:{}", msgContent);
        //根据车辆VIN查询XPUID
        String xpuId = getXpuIdByVin(vin);
        //组装请求消息体
        MqttPublishVo vo = new MqttPublishVo();
        //TODO 这里的topic组装有问题
        vo.setTopic(topic + "/" + xpuId);
        vo.setTopic(buildTopic(vin));
        vo.setPayload(JSON.toJSONString(msgContent));
        log.info("云端-->XPU 创建订单:{}", vo);
        return xpuClient.publish(vo);
    }
@@ -90,7 +80,7 @@
     * @param operation
     * @return
     */
    //TODO 没有处理feign调用的异常
    //TODO 处理feign调用的异常
    public MqttPublishDto cloudOrderOperation(OrderOperation operation, String vin,Long  sequence) {
        MsgContent msgContent = new MsgContent();
        // 消息头
@@ -105,13 +95,11 @@
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("operation", operation);
        msgContent.setContent_detail(jsonObject);
        log.info("云端-->XPU 操作订单:{}", msgContent);
        //根据车辆VIN查询XPUID
        String xpuId = getXpuIdByVin(vin);
        //组装请求消息体
        MqttPublishVo vo = new MqttPublishVo();
        vo.setTopic(topic + "/" + xpuId);
        vo.setTopic(buildTopic(vin));
        vo.setPayload(JSON.toJSONString(msgContent));
        log.info("云端-->XPU 修改订单:{}", vo);
        return xpuClient.publish(vo);
    }
@@ -139,13 +127,11 @@
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("resposne", responseMessage);
        msgContent.setContent_detail(jsonObject);
        log.info("云端-->XPU 响应消息:{}", msgContent);
        //根据车辆VIN查询XPUID
        String xpuId = getXpuIdByVin(vin);
        //组装请求消息体
        MqttPublishVo vo = new MqttPublishVo();
        vo.setTopic(topic + "/" + xpuId);
        vo.setTopic(buildTopic(vin));
        vo.setPayload(JSON.toJSONString(msgContent));
        log.info("云端-->XPU 响应消息:{}", vo);
        return xpuClient.publish(vo);
    }
@@ -167,5 +153,19 @@
        return xpuIdMapping.get(XPU_ID_TYPE);
    }
    private String buildTopic(String vin) {
        String prefix = topicPrefix == null ? "" : topicPrefix;
        if (!prefix.endsWith("/")) {
            prefix = prefix + "/";
        }
        String xpuId = getXpuIdByVin(vin);
        String value = xpuId;
        if (xpuId.length() > 10) {
            int start = 10;
            int end = Math.min(24, xpuId.length());
            value = xpuId.substring(start, end);
        }
        return prefix + value + "00000000";
    }
}
xp-robotaxi-automatic-pilot-boot/src/test/java/com/xiaopeng/automaticPilot/util/XPUUtilTest.java
@@ -1,194 +1,43 @@
package com.xiaopeng.automaticPilot.util;
import com.xiaopeng.api.dto.automaticPilot.MqttPublishDto;
import com.xiaopeng.api.feignClient.automaticPilot.VmpOpenServiceClient;
import com.xiaopeng.api.feignClient.automaticPilot.XPUClient;
import com.xiaopeng.api.vo.automaticPilot.MqttPublishVo;
import com.xiaopeng.api.vo.automaticPilot.protobuf.*;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class XPUUtilTest {
    private XPUUtil xpuUtil;
    private XPUClient xpuClient;
    private VmpOpenServiceClient vmpClient;
    @BeforeEach
    public void setUp() throws Exception {
        xpuUtil = new XPUUtil();
        // Mock VmpOpenServiceClient
        vmpClient = Mockito.mock(VmpOpenServiceClient.class);
        VmpOpenServiceClient vmpClient = Mockito.mock(VmpOpenServiceClient.class);
        Map<String, String> mapping = new HashMap<>();
        mapping.put(XPUUtil.XPU_ID_TYPE, "1234567890ABCDEFGHIJKL");
        Mockito.when(vmpClient.getVehicleBindInfoByVin(Mockito.anyString(), Mockito.anyList()))
                .thenReturn(mapping);
        // Mock XPUClient
        xpuClient = Mockito.mock(XPUClient.class);
        Mockito.when(xpuClient.publish(Mockito.any(MqttPublishVo.class)))
                .thenReturn(new MqttPublishDto());
        // Inject mocks
        Field vmpField = XPUUtil.class.getDeclaredField("vmpOpenServiceClient");
        vmpField.setAccessible(true);
        vmpField.set(xpuUtil, vmpClient);
        Field xpuClientField = XPUUtil.class.getDeclaredField("xpuClient");
        xpuClientField.setAccessible(true);
        xpuClientField.set(xpuUtil, xpuClient);
        Field topicField = XPUUtil.class.getDeclaredField("topicPrefix");
        topicField.setAccessible(true);
        topicField.set(xpuUtil, "Robotaxi/Msg/Xpu");
    }
    @Test
    public void testBuildTopicByVin() throws Exception {
        Method buildTopic = XPUUtil.class.getDeclaredMethod("buildTopicByVin", String.class);
    public void testBuildTopic() throws Exception {
        Method buildTopic = XPUUtil.class.getDeclaredMethod("buildTopic", String.class);
        buildTopic.setAccessible(true);
        String result = (String) buildTopic.invoke(xpuUtil, "VIN123");
        Assertions.assertEquals("Robotaxi/Msg/Xpu/ABCDEFGHIJKL00000000", result);
    }
    @Test
    public void testCloudCreateOrder() {
        String orderId = "1881347710714060802";
        RtTask.Builder taskBuilder = RtTask.newBuilder();
        taskBuilder.setTaskId("task-123");
        taskBuilder.setOrderId(orderId);
        taskBuilder.setTaskType(OrderType.ORDER_TYPE_ROBOTAXI);
        Waypoint.Builder pointBuilder = Waypoint.newBuilder();
        pointBuilder.setPointType(PointType.START_POINT);
        pointBuilder.setActionType(ActionType.PICK_UP);
        pointBuilder.setSequence(1);
        GeoPoint.Builder geoPointBuilder = GeoPoint.newBuilder();
        geoPointBuilder.setLatitude(30.0);
        geoPointBuilder.setLongitude(120.0);
        // geoPointBuilder.setPoiName("Start Point"); // GeoPoint might not have poi_name
        pointBuilder.setPoint(geoPointBuilder.build());
        taskBuilder.addPoints(pointBuilder);
        RtTaskList.Builder taskListBuilder = RtTaskList.newBuilder();
        taskListBuilder.addTasks(taskBuilder.build());
        String vin = "VIN12345678900000";
        Long sequence = 1L;
        xpuUtil.cloudCreateOrder(taskListBuilder.build(), vin, sequence);
        ArgumentCaptor<MqttPublishVo> captor = ArgumentCaptor.forClass(MqttPublishVo.class);
        Mockito.verify(xpuClient).publish(captor.capture());
        MqttPublishVo capturedVo = captor.getValue();
        Assertions.assertEquals("Robotaxi/Msg/Xpu/ABCDEFGHIJKL00000000", capturedVo.getTopic());
        // Note: Current implementation serializes enum as ordinal.
        Assertions.assertTrue(capturedVo.getPayload().contains("\"cmd\": 10003"), "Payload should contain cmd CLOUD_CREATE_ORDER (10003), but was: " + capturedVo.getPayload());
    }
    @Test
    public void testCloudOrderOperation() {
        String orderId = "1881347710714060802";
        OrderOperation.Builder operationBuilder = OrderOperation.newBuilder();
        operationBuilder.setOrderId(orderId);
        operationBuilder.setTaskId("task-123");
        operationBuilder.setOperationType(OrderOperationType.CLOUD_CREATE_ORDER);
        operationBuilder.setOrderType(OrderType.ORDER_TYPE_ROBOTAXI);
        Waypoint.Builder waypointBuilder = Waypoint.newBuilder();
        waypointBuilder.setWaypointId("wp-1");
        waypointBuilder.setPointType(PointType.WAY_POINT);
        waypointBuilder.setActionType(ActionType.PICK_UP); // Use valid enum
        waypointBuilder.setSequence(2);
        GeoPoint.Builder geoPointBuilder = GeoPoint.newBuilder();
        geoPointBuilder.setLatitude(30.1);
        geoPointBuilder.setLongitude(120.1);
        // geoPointBuilder.setPoiName("Way Point");
        waypointBuilder.setPoint(geoPointBuilder.build());
        operationBuilder.addWaypoints(waypointBuilder.build());
        // TargetPoint targetPoint = new TargetPoint(); // OrderOperation uses Waypoint for target_point in proto?
        // Check proto: Waypoint target_point = 6;
        Waypoint.Builder targetPointBuilder = Waypoint.newBuilder();
        GeoPoint.Builder endGeoPointBuilder = GeoPoint.newBuilder();
        endGeoPointBuilder.setLatitude(30.2);
        endGeoPointBuilder.setLongitude(120.2);
        targetPointBuilder.setPoint(endGeoPointBuilder.build());
        operationBuilder.setTargetPoint(targetPointBuilder.build());
        String vin = "VIN12345678900000";
        Long sequence = 2L;
        xpuUtil.cloudOrderOperation(operationBuilder.build(), vin, sequence);
        ArgumentCaptor<MqttPublishVo> captor = ArgumentCaptor.forClass(MqttPublishVo.class);
        Mockito.verify(xpuClient).publish(captor.capture());
        MqttPublishVo capturedVo = captor.getValue();
        Assertions.assertEquals("Robotaxi/Msg/Xpu/ABCDEFGHIJKL00000000", capturedVo.getTopic());
        // Note: CLOUD_ORDER_OPERATION is 10001
        Assertions.assertTrue(capturedVo.getPayload().contains("\"cmd\": 10001"), "Payload should contain cmd CLOUD_ORDER_OPERATION (10001), but was: " + capturedVo.getPayload());
    }
    @Test
    public void testResponseMessage() {
        ResponseMessage.Builder responseMessageBuilder = ResponseMessage.newBuilder();
        responseMessageBuilder.setRequestSeq(12345L);
        responseMessageBuilder.setCode(StatusCode.OK);
        responseMessageBuilder.setTimestamp(System.currentTimeMillis());
        String vin = "VIN12345678900000";
        xpuUtil.responseMessage(responseMessageBuilder.build(), vin);
        ArgumentCaptor<MqttPublishVo> captor = ArgumentCaptor.forClass(MqttPublishVo.class);
        Mockito.verify(xpuClient).publish(captor.capture());
        MqttPublishVo capturedVo = captor.getValue();
        Assertions.assertEquals("Robotaxi/Msg/Xpu/ABCDEFGHIJKL00000000", capturedVo.getTopic());
        // Note: CLOUD_TASK_CONTROL (used in responseMessage method? check code)
        // In XPUUtil.java: headerBuilder.setCmd(RTCmdType.CLOUD_TASK_CONTROL.getValue());
        // CLOUD_TASK_CONTROL is 10002
        Assertions.assertTrue(capturedVo.getPayload().contains("\"cmd\": 10002"), "Payload should contain cmd CLOUD_TASK_CONTROL (10002), but was: " + capturedVo.getPayload());
    }
    @Test
    public void testCloudPushNavigation() {
        RestoreNavigationData.Builder navigationDataBuilder = RestoreNavigationData.newBuilder();
        navigationDataBuilder.setRequestId("req-123");
        navigationDataBuilder.setRouteId("5939fa259ad6479cbdf8871ceed96b72");
        String content = "{\"startPoint\":{\"location\":\"116.481028,39.989643\"},\"endPoint\":{\"location\":\"116.465302,40.004717\"},\"routeID\":\"xxxxxxxxxxxxx\",\"strategy\":17,\"type\":1,\"ferry\":0,\"disableEndDispatch\":1,\"viaInfo\":[{},{}],\"routeUserType\":2,\"bizScene\":2,\"plate\":\"京A12345\",\"vehicleType\":1}";
        navigationDataBuilder.setContent(content);
        navigationDataBuilder.setTimestamp(System.currentTimeMillis());
        String xpuId = "1234567890ABCDEFGHIJKL";
        Long sequence = 3L;
        xpuUtil.cloudPushNavigation(navigationDataBuilder.build(), xpuId, sequence);
        ArgumentCaptor<MqttPublishVo> captor = ArgumentCaptor.forClass(MqttPublishVo.class);
        Mockito.verify(xpuClient).publish(captor.capture());
        MqttPublishVo capturedVo = captor.getValue();
        Assertions.assertEquals("Robotaxi/Msg/Xpu/ABCDEFGHIJKL00000000", capturedVo.getTopic());
        // Note: CLOUD_NAVIGATION_RESPONSE is 10006
        Assertions.assertTrue(capturedVo.getPayload().contains("\"cmd\": 10006"), "Payload should contain cmd CLOUD_NAVIGATION_RESPONSE (10006), but was: " + capturedVo.getPayload());
    }
}