xuhy
2026-03-24 6f963ae4a20a8b569a424b6a36d932b979271969
埋点消息推送封装
7个文件已添加
1个文件已修改
376 ■■■■■ 已修改文件
xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/automaticPilot/VehicleEventDTO.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/automaticPilot/VehicleBuriedPointClientFallbackFactory.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/automaticPilot/VehicleBuriedPointClient.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/VehicleBuriedPointController.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/util/KafkaSendUtils.java 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/util/VehicleBuriedPointProducer.java 161 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automatic-pilot-boot/src/main/resources/gio.properties 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/automaticPilot/VehicleEventDTO.java
New file
@@ -0,0 +1,22 @@
package com.xiaopeng.api.dto.automaticPilot;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Map;
@Data
public class VehicleEventDTO {
    @ApiModelProperty(value = "车辆VIN")
    private String vin;
    @ApiModelProperty(value = "XPU ID")
    private String xpuId;
    @ApiModelProperty(value = "订单ID")
    private String orderId;
    @ApiModelProperty(value = "事件标识")
    private String eventKey;
    @ApiModelProperty(value = "事件时间")
    private Long eventTime;
    @ApiModelProperty(value = "事件属性")
    private Map<String,Object> attributes;
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/automaticPilot/VehicleBuriedPointClientFallbackFactory.java
New file
@@ -0,0 +1,23 @@
package com.xiaopeng.api.factory.automaticPilot;
import com.xiaopeng.api.dto.automaticPilot.VehicleEventDTO;
import com.xiaopeng.api.feignClient.automaticPilot.VehicleBuriedPointClient;
import com.xiaopeng.api.feignClient.automaticPilot.XpuVinClient;
import com.xiaopeng.common.core.domain.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.FallbackFactory;
@Slf4j
public class VehicleBuriedPointClientFallbackFactory implements FallbackFactory<VehicleBuriedPointClient> {
    @Override
    public VehicleBuriedPointClient create(Throwable cause) {
        return new VehicleBuriedPointClient() {
            @Override
            public R<String> sendVehicleEvent(VehicleEventDTO event) {
                log.error("推送埋点数据失败: {}", cause.getMessage());
                return R.fail("推送埋点数据失败");
            }
        };
    }
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/automaticPilot/VehicleBuriedPointClient.java
New file
@@ -0,0 +1,27 @@
package com.xiaopeng.api.feignClient.automaticPilot;
import com.xiaopeng.api.dto.automaticPilot.VehicleEventDTO;
import com.xiaopeng.api.factory.automaticPilot.VehicleBuriedPointClientFallbackFactory;
import com.xiaopeng.api.factory.automaticPilot.XpuVimClientFallbackFactory;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.dto.ServiceNameConstantsEnum;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(contextId = "VehicleBuriedPointClient",
        value = ServiceNameConstantsEnum.XP_AUTOMATIC_PILOT_SERVICE,
        fallbackFactory = VehicleBuriedPointClientFallbackFactory.class)
public interface VehicleBuriedPointClient {
    /**
     * 推送埋点信息
     * @param event
     * @return
     */
    @PostMapping("/inner/vehicleBuriedPoint/sendVehicleEvent")
    R<String> sendVehicleEvent(@RequestBody VehicleEventDTO event);
}
xp-robotaxi-api/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -32,8 +32,8 @@
com.xiaopeng.api.factory.automaticPilot.XPUClientFallbackFactory
com.xiaopeng.api.factory.automaticPilot.XpuVimClientFallbackFactory
com.xiaopeng.api.factory.automaticPilot.OrderMissionClientFallbackFactory
com.xiaopeng.api.factory.automaticPilot.VehicleBuriedPointClientFallbackFactory
com.xiaopeng.api.factory.maintenance.XpCheckLocationClientFallbackFactory
com.xiaopeng.api.factory.automaticPilot.OrderMissionClientFallbackFactory
com.xiaopeng.api.factory.maintenance.XpClockInClientFallbackFactory
com.xiaopeng.api.factory.account.SysGroupMenuClientFallbackFactory
com.xiaopeng.api.factory.order.XpCruiseOrderClientFallbackFactory
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/VehicleBuriedPointController.java
New file
@@ -0,0 +1,31 @@
package com.xiaopeng.automaticPilot.controller;
import com.xiaopeng.api.dto.automaticPilot.VehicleEventDTO;
import com.xiaopeng.automaticPilot.util.VehicleBuriedPointProducer;
import com.xiaopeng.common.core.domain.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@Slf4j
@RestController
@RequestMapping("")
public class VehicleBuriedPointController {
    @Autowired
    private VehicleBuriedPointProducer vehicleBuriedPointProducer;
    /**
     * 推送埋点信息
     * @param event
     * @return
     */
    @PostMapping("/inner/vehicleBuriedPoint/sendVehicleEvent")
    public R<String> sendVehicleEvent(@RequestBody VehicleEventDTO event){
        vehicleBuriedPointProducer.sendVehicleEvent(event);
        return R.ok();
    }
}
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/util/KafkaSendUtils.java
New file
@@ -0,0 +1,84 @@
package com.xiaopeng.automaticPilot.util;
import io.growing.sdk.java.GrowingAPI;
import io.growing.sdk.java.dto.GIOMessage;
import io.growing.sdk.java.dto.GioCdpEventMessage;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class KafkaSendUtils {
    private static final GrowingAPI project = new GrowingAPI.Builder().setProjectKey("89a922449121f7c2").setDataSourceId("9365c3d2f397f172").build();
    /**
     *
     * 车辆状态变更   触发时机:车辆主状态或子状态发生变化的瞬间。
     * 发送数据到GrowingIO
     *
     * @param map
     */
    public static void sendVehicleStatusChanged(Map<String, Object> map) {
        // Config GrowingIO
        // 参数需要从CDP增长平台上,创建新应用,或从已创建的数据源中获取, 如不清楚请联系您的专属项目经理
        // YourAccountId eg: 89a922449121f7c2
        // YourDatasourceId eg: 9365c3d2f397f172
        //事件行为消息体,anonymousId 和 loginUserId 参数,不能同时为空
        GioCdpEventMessage eventMessage = new GioCdpEventMessage.Builder()
                .eventTime(System.currentTimeMillis())            // 默认为系统当前时间 (选填)
                .eventKey("RT_web_vehicle_status_changed")                             // 事件标识 (必填)
//                .domain("com.growingio.app")                      // App包名或H5域名(选填)
//                .urlScheme("growing.123c12fb12f123cc")            // 链接协议(选填)
//                .deviceBrand("google")                            // 设备品牌(选填)
//                .deviceModel("Nexus 5")                           // 设备型号(选填)
//                .deviceType("PHONE")                              // 设备类型(选填)
//                .appVersion("1.2.4")                              // App版本(选填)
//                .appName("看数助手")                               // App名称(选填)
                .language("zh_CN")                                // 语言(选填)
                .anonymousId("device_id")                         // 访问用户ID (选填)
//                .loginUserKey("account")  // 登录用户KEY (选填,需有规划并在平台配置后再上报)
                .loginUserId("417abcabcabcbac")                   // 登录用户ID (选填)
//                .addEventVariable("product_name", "cdp苹果")       // 事件属性 (选填)
//                .addEventVariable("product_classify", Arrays.asList("苹果", "香蕉"))       // 事件属性 (选填)
                .addEventVariables(map)                           // 事件属性集合 (选填)
//                .addItem("itemId", "itemKey")                     // 物品模型ID, KEY (选填)
                .build();
        //上传事件行为消息到服务器
        project.send(eventMessage);
    }
    /**
     *
     * 订单状态变更
     * 开始接单,上报一次
     * 订单结束,上报一次
     * 发送数据到GrowingIO
     *
     * @param map
     */
    public static void sendVehicleTraceUpload(Map<String, Object> map) {
        //事件行为消息体,anonymousId 和 loginUserId 参数,不能同时为空
        GioCdpEventMessage eventMessage = new GioCdpEventMessage.Builder()
                .eventTime(System.currentTimeMillis())            // 默认为系统当前时间 (选填)
                .eventKey("RT_xpu_vehicle_trace_upload")                             // 事件标识 (必填)
                .language("zh_CN")                                // 语言(选填)
                .addEventVariables(map)                           // 事件属性集合 (选填)
                .build();
        //上传事件行为消息到服务器
        project.send(eventMessage);
    }
    public static void main(String[] args) {
        Map<String, Object> map = new HashMap<>();
        map.put("vin", "L1NSPGHB7SB018421");
        map.put("order_id", "");
        map.put("timestamp", System.currentTimeMillis());
        map.put("sub_status", "");
        map.put("prev_sub_status", "");
        sendVehicleStatusChanged(map);
    }
}
xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/util/VehicleBuriedPointProducer.java
New file
@@ -0,0 +1,161 @@
package com.xiaopeng.automaticPilot.util;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xiaopeng.api.dto.automaticPilot.VehicleEventDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.producer.*;
import org.apache.kafka.common.serialization.StringSerializer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Future;
@Slf4j
@Component
public class VehicleBuriedPointProducer {
    // 预发环境 Kafka 集群
    @Value("${spring.kafka.bootstrap-servers}")
    private String bootstrapServers;
    // 目标 Topic
    private static final String TOPIC = "topic-robotaxi-vehicle-buriedPoint";
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    private Properties kafkaProperties;
    @PostConstruct
    public void init() {
        kafkaProperties = buildProperties();
    }
    /**
     * 发送埋点消息
     *
     * @param event
     * @throws Exception
     */
    public void sendVehicleEvent(VehicleEventDTO event){
        if (kafkaProperties == null) {
            kafkaProperties = buildProperties();
        }
        KafkaProducer<String, String> producer = new KafkaProducer<>(kafkaProperties);
        try {
            // 转 JSON
            String messageBody = OBJECT_MAPPER.writeValueAsString(event);
            // 建议用 vin 作为 key(保证同车有序)
            ProducerRecord<String, String> record =
                    new ProducerRecord<>(TOPIC, event.getVin(), messageBody);
            Future<RecordMetadata> future = producer.send(record);
            RecordMetadata metadata = future.get();
            log.info("发送成功:");
            log.info("Topic: " + metadata.topic());
            log.info("Partition: " + metadata.partition());
            log.info("Offset: " + metadata.offset());
        } catch (Exception e) {
            log.error("发送失败:{}", e.getMessage());
            e.printStackTrace();
        } finally {
            producer.close();
        }
    }
    /**
     * 构造埋点消息体
     *
     * @param vin
     * @param orderId
     * @param xpuId
     * @param eventKey
     * @param eventTime
     * @param extraAttributes
     * @return
     */
    public VehicleEventDTO buildVehicleEvent(String vin, String orderId, String xpuId,
                                          String eventKey, Long eventTime,
                                          Map<String, Object> extraAttributes) {
        VehicleEventDTO event = new VehicleEventDTO();
        event.setVin(vin);
        event.setXpuId(xpuId != null ? xpuId : "");
        event.setOrderId(orderId != null ? orderId : "");
        event.setEventKey(eventKey);
        event.setEventTime(eventTime != null ? eventTime : System.currentTimeMillis());
        Map<String, Object> attributes = new HashMap<>();
        attributes.put("vin", vin);
        attributes.put("order_id", orderId != null ? orderId : "");
        attributes.put("timestamp", event.getEventTime());
        if (extraAttributes != null) {
            attributes.putAll(extraAttributes);
        }
        event.setAttributes(attributes);
        return event;
    }
    private Properties buildProperties() {
        Properties props = new Properties();
        props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
        props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
        props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
        // 生产建议配置
        props.put(ProducerConfig.ACKS_CONFIG, "all");
        props.put(ProducerConfig.RETRIES_CONFIG, 3);
        props.put(ProducerConfig.LINGER_MS_CONFIG, 5);
        props.put(ProducerConfig.BATCH_SIZE_CONFIG, 16384);
        props.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true);
        return props;
    }
//    public static void main(String[] args) throws Exception {
//
//        long timeMillis = System.currentTimeMillis();
//
//        // 构造埋点消息体(示例)
//        VehicleEvent event = new VehicleEvent();
//        event.setVin("L1NSPGHB7SB018421");
//        event.setXpuId("");
//        event.setOrderId("");
//        event.setEventKey("RT_web_vehicle_status_changed");
//        event.setEventTime(timeMillis);
//
//        Map<String, Object> attributes = new HashMap<>();
//        attributes.put("vin", "L1NSPGHB7SB018421");
//        attributes.put("order_id", "");
//        attributes.put("timestamp", timeMillis);
//        attributes.put("sub_status", "");
//        attributes.put("prev_sub_status", "");
//        event.setAttributes(attributes);
//
//        // 转 JSON
//        String messageBody = OBJECT_MAPPER.writeValueAsString(event);
//
//        // 建议用 vin 作为 key(保证同车有序)
//        ProducerRecord<String, String> record =
//                new ProducerRecord<>(TOPIC, event.getVin(), messageBody);
//
//        try {
//            Future<RecordMetadata> future = producer.send(record);
//            RecordMetadata metadata = future.get();
//
//            System.out.println("发送成功:");
//            System.out.println("Topic: " + metadata.topic());
//            System.out.println("Partition: " + metadata.partition());
//            System.out.println("Offset: " + metadata.offset());
//
//        } catch (Exception e) {
//            e.printStackTrace();
//        } finally {
//            producer.close();
//        }
//    }
}
xp-robotaxi-automatic-pilot-boot/src/main/resources/gio.properties
New file
@@ -0,0 +1,26 @@
#项目采集端地址
api.host=https://collect.test.xiaopeng.com
#消息发送间隔时间,单位ms(默认 100)
send.msg.interval=100
#消息发送线程数量 (默认 3)
send.msg.thread=3
#消息队列大小 (默认 500)
msg.store.queue.size=500
#日志级别输出 (debug | error)
logger.level=debug
#自定义日志输出实现类
logger.implementation=io.growing.sdk.java.logger.GioLoggerImpl
#运行模式,test:仅输出消息体,不发送消息,production: 发送消息
#run.mode=test
run.mode=production
# 设置代理, 如果不设置,默认为不使用代理
#proxy.host=127.0.0.1
#proxy.port=3128
# 设置代理认证用户密码, 如果不设置,默认为不使用用户验证
#proxy.user=demo
#proxy.password=demo
#http 连接超时时间
#connection.timeout=2000
#http 连接读取时间
#read.timeout=2000