zhouhn
2026-02-27 70c0cc7ac8a9580b3fdcc8465cfb2e09a98cf471
增加座舱RTInfo使用的接口
8个文件已添加
7个文件已修改
334 ■■■■■ 已修改文件
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/account/XpOperationsUserNotification.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/pom.xml 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/config/KafkaConfig.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/config/WebMvcConfigurer.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/KafkaTestController.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/OrderMissionController.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/VehicleRtInfoController.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/dto/RobotaxiSmsCodeRequest.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/dto/RobotaxiSmsValidateRequest.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/dto/XpCommonResponse.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/enums/RobotaxiErrorEnum.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/service/VehicleRtInfoService.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/service/impl/VehicleRtInfoServiceImpl.java 136 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/resources/application-local.yml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-common/xp-common-redis/pom.xml 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/account/XpOperationsUserNotification.java
@@ -3,10 +3,6 @@
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import java.time.LocalDateTime;
import java.io.Serializable;
import com.sun.org.apache.bcel.internal.generic.INEG;
import com.xiaopeng.common.core.web.domain.BaseModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
xp-robotaxi-automatic-pilot-boot/pom.xml
@@ -133,13 +133,27 @@
            <artifactId>protobuf-java-util</artifactId>
            <version>3.19.4</version>
        </dependency>
        <dependency>
            <groupId>com.xiaopeng</groupId>
            <artifactId>unified-verification</artifactId>
            <version>1.5.2-v2</version>
        </dependency>
    </dependencies>
    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <argLine>
                        --add-opens java.base/java.lang=ALL-UNNAMED
                        --add-opens java.base/java.util=ALL-UNNAMED
                    </argLine>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/config/KafkaConfig.java
@@ -14,6 +14,7 @@
import java.util.HashMap;
import java.util.Map;
//TODO 这个配置类不生效的
/**
 * Kafka 配置类
 */
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/config/WebMvcConfigurer.java
New file
@@ -0,0 +1,26 @@
package com.xiaopeng.automaticPilot.config;
import com.xiaopeng.unifiedverification.interceptor.CheckForClientInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import javax.annotation.Resource;
@Slf4j
@Configuration
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
    @Resource
    private CheckForClientInterceptor checkForClientInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 统一验证服务拦截器
        registry.addInterceptor(checkForClientInterceptor).addPathPatterns("/vehicle/v1/**");
        super.addInterceptors(registry);
    }
}
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/KafkaTestController.java
@@ -6,7 +6,6 @@
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
public class KafkaTestController {
@@ -14,9 +13,7 @@
    @Autowired
    private KafkaConsumerService kafkaConsumerService;
    //TODO 少了factory属性声明
    /**
     * 消费消息 - XPU上报Robotaxi云端的消息topic(高优先级)
     *
@@ -28,6 +25,7 @@
        kafkaConsumerService.topicProdRobotaxiXpuHigh(message);
    }
    //TODO 少了factory属性声明
    /**
     * 消费消息 - XPU上报Robotaxi云端的消息topic(低优先级)
     *
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/OrderMissionController.java
@@ -34,7 +34,6 @@
    @Resource
    private XpVehicleClient xpVehicleClient;
    @PostMapping("/inner/pushOrder")
    public R<Boolean> pushOrder(@RequestBody PushOrderDto dto) {
        RtTask.Builder taskBuilder = RtTask.newBuilder();
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/VehicleRtInfoController.java
New file
@@ -0,0 +1,40 @@
package com.xiaopeng.automaticPilot.controller;
import com.xiaopeng.automaticPilot.dto.XpCommonResponse;
import com.xiaopeng.automaticPilot.dto.RobotaxiSmsCodeRequest;
import com.xiaopeng.automaticPilot.dto.RobotaxiSmsValidateRequest;
import com.xiaopeng.automaticPilot.service.VehicleRtInfoService;
import com.xiaopeng.unifiedverification.interceptor.XpClientCheck;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
 * @author zhouhn
 * 2026/2/27
 */
@RestController
@RequestMapping("/vehicle/v1/robotaxi")
@Api(tags = "座舱RTInfo接口")
public class VehicleRtInfoController {
    @Resource
    private VehicleRtInfoService vehicleRtInfoService;
    @XpClientCheck(checkToken = false)
    @PostMapping("/sms/code")
    public XpCommonResponse<?> getRobotaxiSmsCode(@RequestBody RobotaxiSmsCodeRequest request) {
        return vehicleRtInfoService.getRobotaxiSmsCode(request);
    }
    @XpClientCheck(checkToken = false)
    @PostMapping("/sms/validate")
    public XpCommonResponse<?> validateRobotaxiSmsCode(@RequestBody RobotaxiSmsValidateRequest request) {
        return vehicleRtInfoService.validateRobotaxiSmsCode(request);
    }
}
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/dto/RobotaxiSmsCodeRequest.java
New file
@@ -0,0 +1,10 @@
package com.xiaopeng.automaticPilot.dto;
import lombok.Data;
@Data
public class RobotaxiSmsCodeRequest {
    private String smsType;
    private String vin;
    private String mobile;
}
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/dto/RobotaxiSmsValidateRequest.java
New file
@@ -0,0 +1,11 @@
package com.xiaopeng.automaticPilot.dto;
import lombok.Data;
@Data
public class RobotaxiSmsValidateRequest {
    private String smsType;
    private String vin;
    private String mobile;
    private String code;
}
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/dto/XpCommonResponse.java
New file
@@ -0,0 +1,33 @@
package com.xiaopeng.automaticPilot.dto;
import lombok.Data;
import com.xiaopeng.automaticPilot.enums.RobotaxiErrorEnum;
@Data
public class XpCommonResponse<T> {
    private static final int SUCCESS_CODE = 0;
    private Integer code;
    private String msg;
    private T data;
    public static <T> XpCommonResponse<T> ok(T data) {
        XpCommonResponse<T> response = new XpCommonResponse<>();
        response.setCode(SUCCESS_CODE);
        response.setMsg("成功");
        response.setData(data);
        return response;
    }
    public static <T> XpCommonResponse<T> fail(int code, String msg) {
        XpCommonResponse<T> response = new XpCommonResponse<>();
        response.setCode(code);
        response.setMsg(msg);
        response.setData(null);
        return response;
    }
    public static <T> XpCommonResponse<T> fail(RobotaxiErrorEnum errorEnum) {
        return fail(errorEnum.getCode(), errorEnum.getMessage());
    }
}
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/enums/RobotaxiErrorEnum.java
New file
@@ -0,0 +1,18 @@
package com.xiaopeng.automaticPilot.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum RobotaxiErrorEnum {
    GENERAL_ERROR(20019999, "服务器开小差,请稍后重试"),
    MOBILE_VIN_MISMATCH(20011000, "安全员手机号和车辆不匹配"),
    VEHICLE_NOT_READY(20011001, "当前车辆状态未就绪,不能接单"),
    VERIFY_CODE_ERROR(20011002, "验证码错误");
    private final int code;
    private final String message;
}
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/service/VehicleRtInfoService.java
New file
@@ -0,0 +1,16 @@
package com.xiaopeng.automaticPilot.service;
import com.xiaopeng.automaticPilot.dto.XpCommonResponse;
import com.xiaopeng.automaticPilot.dto.RobotaxiSmsCodeRequest;
import com.xiaopeng.automaticPilot.dto.RobotaxiSmsValidateRequest;
public interface VehicleRtInfoService {
    XpCommonResponse<?> getRobotaxiSmsCode(RobotaxiSmsCodeRequest request);
    XpCommonResponse<?> validateRobotaxiSmsCode(RobotaxiSmsValidateRequest request);
    enum SmsType {
        ACCEPT_RIDES,
        STOP_ACCEPT_RIDES
    }
}
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/service/impl/VehicleRtInfoServiceImpl.java
New file
@@ -0,0 +1,136 @@
package com.xiaopeng.automaticPilot.service.impl;
import com.xiaopeng.automaticPilot.dto.XpCommonResponse;
import com.xiaopeng.automaticPilot.dto.RobotaxiSmsCodeRequest;
import com.xiaopeng.automaticPilot.dto.RobotaxiSmsValidateRequest;
import com.xiaopeng.automaticPilot.service.VehicleRtInfoService;
import com.xiaopeng.api.dto.vehicleConvoy.UpdateVehicleStateDto;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
import com.xiaopeng.common.core.utils.MsgUtil;
import com.xiaopeng.common.core.utils.StringUtils;
import com.xiaopeng.common.redis.service.RedisService;
import com.xiaopeng.automaticPilot.enums.RobotaxiErrorEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Slf4j
@Service
public class VehicleRtInfoServiceImpl implements VehicleRtInfoService {
    private static final long CODE_TTL_MINUTES = 5L;
    @Resource
    private RedisService redisService;
    @Resource
    private XpVehicleClient xpVehicleClient;
    @Value("#{'${robotaxi.sms.whitelist.mobiles:}'.split(',')}")
    private List<String> whitelistMobiles;
    @Override
    public XpCommonResponse<?> getRobotaxiSmsCode(RobotaxiSmsCodeRequest request) {
        XpCommonResponse<?> paramCheckError = validateSmsCodeRequest(request);
        if (paramCheckError != null) {
            return paramCheckError;
        }
        XpCommonResponse<?> vehicleCheckError = validateVehicleReadyIfNeeded(request.getSmsType(), request.getVin());
        if (vehicleCheckError != null) {
            return vehicleCheckError;
        }
        String code = MsgUtil.createCode();
        log.info("Robotaxi SMS code generated for mobile {}: {}", request.getMobile(), code);
        // TODO: Call SMS interface to send code when available
        // sendSms(request.getMobile(), code);
        String key = buildSmsCodeKey(request.getSmsType(), request.getVin(), request.getMobile());
        redisService.setCacheObject(key, code, CODE_TTL_MINUTES, TimeUnit.MINUTES);
        return XpCommonResponse.ok(Collections.emptyMap());
    }
    @Override
    public XpCommonResponse<?> validateRobotaxiSmsCode(RobotaxiSmsValidateRequest request) {
        XpCommonResponse<?> paramCheckError = validateSmsValidateRequest(request);
        if (paramCheckError != null) {
            return paramCheckError;
        }
        XpCommonResponse<?> vehicleCheckError = validateVehicleReadyIfNeeded(request.getSmsType(), request.getVin());
        if (vehicleCheckError != null) {
            return vehicleCheckError;
        }
        boolean isWhitelisted = whitelistMobiles != null && whitelistMobiles.contains(request.getMobile());
        String key = buildSmsCodeKey(request.getSmsType(), request.getVin(), request.getMobile());
        if (!isWhitelisted) {
            String cachedCode = redisService.getCacheObject(key);
            if (StringUtils.isEmpty(cachedCode)) {
                return XpCommonResponse.fail(RobotaxiErrorEnum.GENERAL_ERROR);
            }
            if (!cachedCode.equals(request.getCode())) {
                return XpCommonResponse.fail(RobotaxiErrorEnum.VERIFY_CODE_ERROR);
            }
            redisService.deleteObject(key);
        } else {
            redisService.deleteObject(key);
        }
        return XpCommonResponse.ok(Collections.emptyMap());
    }
    private XpCommonResponse<?> validateSmsCodeRequest(RobotaxiSmsCodeRequest request) {
        if (StringUtils.isAnyEmpty(request.getSmsType(), request.getVin(), request.getMobile())) {
            return XpCommonResponse.fail(RobotaxiErrorEnum.GENERAL_ERROR);
        }
        if (!isSupportedSmsType(request.getSmsType())) {
            return XpCommonResponse.fail(RobotaxiErrorEnum.GENERAL_ERROR);
        }
        return null;
    }
    private XpCommonResponse<?> validateSmsValidateRequest(RobotaxiSmsValidateRequest request) {
        if (StringUtils.isAnyEmpty(request.getSmsType(), request.getVin(), request.getMobile(), request.getCode())) {
            return XpCommonResponse.fail(RobotaxiErrorEnum.GENERAL_ERROR);
        }
        if (!isSupportedSmsType(request.getSmsType())) {
            return XpCommonResponse.fail(RobotaxiErrorEnum.GENERAL_ERROR);
        }
        return null;
    }
    private boolean isSupportedSmsType(String smsType) {
        return SmsType.ACCEPT_RIDES.name().equals(smsType) || SmsType.STOP_ACCEPT_RIDES.name().equals(smsType);
    }
    private XpCommonResponse<?> validateVehicleReadyIfNeeded(String smsType, String vin) {
        if (!SmsType.ACCEPT_RIDES.name().equals(smsType)) {
            return null;
        }
//        XpVehicle vehicle = xpVehicleClient.findByVehicleVin(vin).getData();
//        if (vehicle == null) {
//            return XpCommonResponse.fail(RobotaxiErrorEnum.MOBILE_VIN_MISMATCH);
//        }
//        Integer status = vehicle.getStatus();
//        Integer operatingStatus = vehicle.getOperatingStatus();
//        if (status == null || status != 2 || operatingStatus == null || operatingStatus != 1) {
//            return XpCommonResponse.fail(RobotaxiErrorEnum.VEHICLE_NOT_READY);
//        }
        return null;
    }
    private String buildSmsCodeKey(String smsType, String vin, String mobile) {
        return "ROBOTAXI_SMS_CODE:" + smsType + ":" + vin + ":" + mobile;
    }
}
xp-robotaxi-automatic-pilot-boot/src/main/resources/application-local.yml
@@ -237,3 +237,8 @@
      data-id: seata-server.properties
      username: nacos
      password: nacos
robotaxi:
  sms:
    whitelist:
      mobiles: 13800138000
xp-robotaxi-common/xp-common-redis/pom.xml
@@ -33,6 +33,17 @@
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>3.19.3</version>
            <exclusions>
                <exclusion>
                    <groupId>org.redisson</groupId>
                    <artifactId>redisson-spring-data-30</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-data-27</artifactId>
            <version>3.19.3</version>
        </dependency>
    </dependencies>
</project>