“mitao”
2026-04-07 3ee4725e50f2494fc291ba841730942004e22956
Merge remote-tracking branch 'origin/master'
30个文件已添加
5个文件已修改
2122 ■■■■■ 已修改文件
pom.xml 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-map-boot/src/main/resources/bootstrap.yml 148 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpWhitelistController.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/utils/TaskOrderUtil.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/resources/bootstrap.yml 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/Dockerfile 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/pom.xml 214 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/DecodingException.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/TrafficControlApplication.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/config/DataUpdateHandlerConfig.java 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/config/MessageLocalConfig.java 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/config/MultipartFilterConfig.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/config/MyLocaleResolver.java 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/config/MybatisPlusConfig.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/config/TransactionConfiguration.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/config/log/FeignLoggingAspect.java 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/config/log/RequestResponseLoggingFilter.java 139 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/constant/I18nKeyConstant.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/enums/SignatureType.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/util/HMACSHA1.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/util/HexUtil.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/util/ResourceUtil.java 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/util/SHA1Util.java 118 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/util/SignatureUtils.java 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/util/ThreadLocalSHA1.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/resources/application-local.properties 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/resources/i18n/messages.properties 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/resources/i18n/messages_en_US.properties 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/resources/i18n/messages_zh_CN.properties 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/resources/logback.xml 222 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/resources/logback.xml.bak 222 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/resources/mybatis-config.xml 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/main/resources/seata.conf 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/src/test/java/com/ruoyi/account/RuoYiAccountApplicationTests.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-traffic-control-boot/xp-robotaxi-vehicle-convoy-boot.iml 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml
@@ -267,6 +267,7 @@
        <module>xp-robotaxi-vehicle-convoy-boot</module>
        <module>xp-robotaxi-job-boot</module>
        <module>xp-robotaxi-file-boot</module>
        <module>xp-robotaxi-traffic-control-boot</module>
    </modules>
    <packaging>pom</packaging>
xp-robotaxi-map-boot/src/main/resources/bootstrap.yml
@@ -12,4 +12,150 @@
    allow-circular-references: true
  profiles:
    # 环境配置
    active: local
    active: dev
  #    active: prod
---
spring:
  config:
    activate:
      on-profile: dev
  cloud:
    nacos:
      discovery:
        # 服务注册地址
        server-addr: 192.168.110.80:8848
        service: ${spring.application.name}
        group: DEFAULT_GROUP
        namespace: 5185ac4b-6369-48eb-a21b-a7cbc441c5f1
        username: nacos
        password: nacos
        ip: 192.168.110.85
      config:
        # 配置中心地址
        server-addr: 192.168.110.80:8848
        namespace: 5185ac4b-6369-48eb-a21b-a7cbc441c5f1
        group: DEFAULT_GROUP
        name: ${spring.application.name}
        username: nacos
        password: nacos
        # 配置文件格式
        file-extension: yml
        # 共享配置
        shared-configs:
          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
---
seata:
  enabled: true
  application-id: ${spring.application.name}
  tx-service-group: seata_tx_group    #此处配置自定义的seata事务分组名称
  enable-auto-data-source-proxy: false    #关闭数据库代理
  service:
    vgroup-mapping:
      seata_tx_group: default
  data-source-proxy-mode: AT
  config:
    type: nacos
    nacos:
      # 开发环境
      server-addr: 192.168.110.80:8848
      namespace: 5185ac4b-6369-48eb-a21b-a7cbc441c5f1
      group: DEFAULT_GROUP
      data-id: seata-server.properties
      username: nacos
      password: nacos
      # 生产环境
  #      server-addr: 192.168.0.137:8848,192.168.0.123:8848
  #      namespace: c6cf40b5-44e8-43f9-be61-8d10fa830e2a
  #      group: DEFAULT_GROUP
  #      data-id: seata-server.properties
  #      username: nacos
  #      password: nacos
  registry:
    type: nacos
    nacos:
      application: seata-server
      # 开发环境
      server-addr: 192.168.110.80:8848
      namespace: 5185ac4b-6369-48eb-a21b-a7cbc441c5f1
      group: DEFAULT_GROUP
      username: nacos
      password: nacos
      # 生产环境
  #      server-addr: 192.168.0.137:8848,192.168.0.123:8848
  #      namespace: c6cf40b5-44e8-43f9-be61-8d10fa830e2a
  #      group: DEFAULT_GROUP
  #      username: nacos
  #      password: nacos
  cloud:
    nacos:
      discovery:
        # 开发环境
        server-addr: 192.168.110.80:8848
        namespace: 5185ac4b-6369-48eb-a21b-a7cbc441c5f1
        group: DEFAULT_GROUP
        application: seata-server #Nacos 中 Seata 名称
        username: nacos
        password: nacos
        # 生产环境
    #        server-addr: 192.168.0.137:8848,192.168.0.123:8848
    #        namespace: c6cf40b5-44e8-43f9-be61-8d10fa830e2a
    #        group: DEFAULT_GROUP
    #        application: seata-server #Nacos 中 Seata 名称
    #        username: nacos
    #        password: nacos
    sentinel:
      transport:
        dashboard: 192.168.0.137:8080  #  Sentinel控制台地址
      eager: true
---
spring:
  config:
    activate:
      on-profile: prod
  cloud:
    nacos:
      discovery:
        # 服务注册地址
        server-addr: 192.168.0.137:8848,192.168.0.123:8848
        service: ${spring.application.name}
        group: DEFAULT_GROUP
        namespace: c6cf40b5-44e8-43f9-be61-8d10fa830e2a
        username: nacos
        password: nacos
      config:
        # 配置中心地址
        server-addr: 192.168.0.137:8848,192.168.0.123:8848
        namespace: c6cf40b5-44e8-43f9-be61-8d10fa830e2a
        username: nacos
        password: nacos
        group: DEFAULT_GROUP
        name: ${spring.application.name}
        # 配置文件格式
        file-extension: yml
        # 共享配置
        shared-configs:
          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
---
spring:
  config:
    activate:
      on-profile: test
  cloud:
    nacos:
      discovery:
        # 服务注册地址
        server-addr: 127.0.0.1:8848
        service: ${spring.application.name}
        group: DEFAULT_GROUP
        namespace: 96712c7a-480b-4f40-b783-39f00f3b33ce
      config:
        # 配置中心地址
        server-addr: 127.0.0.1:8848
        namespace: 96712c7a-480b-4f40-b783-39f00f3b33ce
        group: DEFAULT_GROUP
        name: ${spring.application.name}
        # 配置文件格式
        file-extension: yml
        # 共享配置
        shared-configs:
          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpWhitelistController.java
@@ -457,4 +457,8 @@
    }
}
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/utils/TaskOrderUtil.java
@@ -137,7 +137,6 @@
     * @param firstElement 队列第一个元素
     */
    private void orderProcess(String quoteName, String firstElement) {
        System.out.println("进入处理环节");
        XpTradingStrategy xpTradingStrategy = xpTradingStrategyService.getOne(null);
        String orderId = firstElement.split("_")[0];
        String lonLat = firstElement.split("_")[1];
xp-robotaxi-order-boot/src/main/resources/bootstrap.yml
@@ -29,6 +29,7 @@
        namespace: 5185ac4b-6369-48eb-a21b-a7cbc441c5f1
        username: nacos
        password: nacos
        ip: 192.168.110.85
      config:
        # 配置中心地址
        server-addr: 192.168.110.80:8848
xp-robotaxi-traffic-control-boot/Dockerfile
New file
@@ -0,0 +1,16 @@
FROM registry.logan.xiaopeng.local/logancloud/logan-base:1.1.4-rc1-J1.8.0_372
LABEL maintainer="Linzhaoming <linzm2@xiaopeng.com>"
ENV JAVA_OPTS="-Xmx3072m -Xms1024m -XX:NewRatio=1 -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 \
-XX:+UseCMSInitiatingOccupancyOnly -XX:ReservedCodeCacheSize=128M -XX:ParallelGCThreads=2 \
-XX:+ExplicitGCInvokesConcurrent -Duser.timezone=Asia/Shanghai"
ENTRYPOINT [ "sh", "-c", "java $APP_OPTS $JMX_OPTS $JAVA_OPTS $GCLOG_OPTS -Djava.security.egd=file:/dev/./urandom -jar xp-robotaxi-vehicle-convoy-boot.jar" ]
WORKDIR /home/xpmotors/local
RUN mkdir -p /data/log/app/xp-robotaxi-vehicle-convoy-boot /data/tomcat && chown -R xpmotors:xpmotors /data/log/app/xp-robotaxi-vehicle-convoy-boot /data/tomcat
COPY target/xp-robotaxi-vehicle-convoy-boot-*-exec.jar /home/xpmotors/local/xp-robotaxi-vehicle-convoy-boot.jar
USER xpmotors
xp-robotaxi-traffic-control-boot/pom.xml
New file
@@ -0,0 +1,214 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>com.xiaopeng</groupId>
        <artifactId>robotaxi</artifactId>
        <version>0.1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>xp-robotaxi-traffic-control-boot</artifactId>
    <description>
        xp-modules-trafficControl交通监管模块
    </description>
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-loadbalancer</artifactId>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>${swagger.fox.version}</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.xiaopeng</groupId>
            <artifactId>xp-common-log</artifactId>
        </dependency>
        <dependency>
            <groupId>com.xiaopeng</groupId>
            <artifactId>xp-common-swagger</artifactId>
        </dependency>
        <dependency>
            <groupId>com.xiaopeng</groupId>
            <artifactId>xp-robotaxi-api</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>${druid.version}</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
        </dependency>
        <dependency>
            <groupId>com.xiaopeng</groupId>
            <artifactId>unified-verification</artifactId>
            <version>1.5.2-v2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
            <version>5.2.1</version>
            <exclusions>
                <exclusion>
                    <groupId>org.yaml</groupId>
                    <artifactId>snakeyaml</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>log4j</groupId>
                    <artifactId>log4j</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>shardingsphere-transaction-base-seata-at</artifactId>
            <version>5.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.yaml</groupId>
            <artifactId>snakeyaml</artifactId>
            <version>1.33</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.25.3</version>
        </dependency>
        <!-- easypoi -->
        <!-- Apache POI 核心依赖 -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>5.2.3</version>
        </dependency>
        <!-- Apache POI OOXML 支持(用于 .xlsx 文件) -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>5.2.3</version>
        </dependency>
        <!-- Apache POI XMLBeans(可选,用于复杂 XML 处理) -->
        <dependency>
            <groupId>org.apache.xmlbeans</groupId>
            <artifactId>xmlbeans</artifactId>
            <version>5.1.1</version>
        </dependency>
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-base</artifactId>
            <version>4.4.0</version>
            <exclusions>
                <exclusion>
                    <artifactId>guava</artifactId>
                    <groupId>com.google.guava</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-web</artifactId>
            <version>4.4.0</version>
        </dependency>
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-annotation</artifactId>
            <version>4.4.0</version>
        </dependency>
        <dependency>
            <groupId>com.xiaopeng.logan</groupId>
            <artifactId>xp-evi-oss-sdk</artifactId>
            <version>1.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies>
    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
            </resource>
            <resource>
                <directory>lib</directory>
                <targetPath>/BOOT-INF/lib/</targetPath>
                <includes>
                    <include>**/*.jar</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>
</project>
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/DecodingException.java
New file
@@ -0,0 +1,17 @@
package com.xiaopeng.trafficControl;
/**
 * 解码处理异常类</br>
 */
public class DecodingException extends RuntimeException {
    private static final long serialVersionUID = 1L;
    public DecodingException(String message) {
        super(message);
    }
    public DecodingException(Throwable cause) {
        super(cause);
    }
}
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/TrafficControlApplication.java
New file
@@ -0,0 +1,29 @@
package com.xiaopeng.trafficControl;
import com.xiaopeng.common.security.annotation.EnableCustomConfig;
import com.xiaopeng.common.security.annotation.EnableRyFeignClients;
import com.xiaopeng.common.swagger.annotation.EnableCustomSwagger2;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
 * 交通监管模块
 */
@EnableCustomConfig
@MapperScan({"com.xiaopeng.trafficControl.mapper"})
@EnableCustomSwagger2
@EnableRyFeignClients
@SpringBootApplication
@EnableScheduling//开启定时任务
@ServletComponentScan
@EnableTransactionManagement//开启事务
public class TrafficControlApplication {
    public static void main(String[] args) {
        SpringApplication.run(TrafficControlApplication.class, args);
        System.out.println("(♥◠‿◠)ノ゙  交通监管模块启动成功   ლ(´ڡ`ლ)゙  \n");
    }
}
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/config/DataUpdateHandlerConfig.java
New file
@@ -0,0 +1,71 @@
package com.xiaopeng.trafficControl.config;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.xiaopeng.common.core.utils.StringUtils;
import com.xiaopeng.common.security.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.context.annotation.Configuration;
import java.time.LocalDateTime;
/**
 * @author xiaochen
 * @ClassName DataUpdateInterceptor
 * @Description 数据更新操作处理
 * @date 2021-12-15
 * <p>
 * 注意,之前在此处注入了 JwtTokenUtils
 * <p>
 * 造成spring循环依赖,项目支棱不起来
 */
@Slf4j
@Configuration
public class DataUpdateHandlerConfig implements MetaObjectHandler {
    /**
     * 新增数据执行
     *
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        String userName = "";
        try{
            //  获取登录信息
            userName = SecurityUtils.getLoginUser().getSysUser().getNickName();
            log.info("DataUpdateInterceptor insertFill");
        } catch (Exception e) {
            log.error("DataUpdateInterceptor insertFill error:{}", e.getMessage());
        }
        if (StringUtils.isNotBlank(userName)) {
            this.setFieldValByName("createBy", userName, metaObject);
            this.setFieldValByName("updateBy", userName, metaObject);
        } else {
            this.setFieldValByName("createBy", userName, metaObject);
            this.setFieldValByName("updateBy", userName, metaObject);
        }
        this.setFieldValByName("createTime", LocalDateTime.now(), metaObject);
        this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
    }
    /**
     * 修改数据执行
     *
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        String userName = "";
        try{
            //  获取登录信息
            userName = SecurityUtils.getLoginUser().getSysUser().getNickName();
            log.info("DataUpdateInterceptor insertFill");
        } catch (Exception e) {
            log.error("DataUpdateInterceptor insertFill error:{}", e.getMessage());
        }
        this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
        this.setFieldValByName("updateBy", userName, metaObject);
    }
}
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/config/MessageLocalConfig.java
New file
@@ -0,0 +1,59 @@
package com.xiaopeng.trafficControl.config;
import org.springframework.boot.autoconfigure.context.MessageSourceProperties;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.LocaleResolver;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
/**
 * 国际化配置
 */
@Configuration
public class MessageLocalConfig {
    @Bean
    public MessageSourceProperties messageSourceProperties() {
        MessageSourceProperties properties = new MessageSourceProperties();
        properties.setBasename("i18n/messages");
        properties.setEncoding(StandardCharsets.UTF_8);
        properties.setFallbackToSystemLocale(false);
        properties.setCacheDuration(Duration.ofSeconds(-1));
        properties.setAlwaysUseMessageFormat(false);
        properties.setUseCodeAsDefaultMessage(true);
        return properties;
    }
    @Bean
    public MessageSource messageSource(MessageSourceProperties properties) {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        if (StringUtils.hasText(properties.getBasename())) {
            messageSource.setBasenames(StringUtils
                    .commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(properties.getBasename())));
        }
        if (properties.getEncoding() != null) {
            messageSource.setDefaultEncoding(properties.getEncoding().name());
        }
        messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale());
        Duration cacheDuration = properties.getCacheDuration();
        if (cacheDuration != null) {
            messageSource.setCacheMillis(cacheDuration.toMillis());
        }
        messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat());
        messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage());
        return messageSource;
    }
    @Bean//注册国际化组件
    public LocaleResolver localeResolver(){
        return new MyLocaleResolver();
    }
}
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/config/MultipartFilterConfig.java
New file
@@ -0,0 +1,64 @@
package com.xiaopeng.trafficControl.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
 * 修复 multipart 文件上传被 ReplaceRequestFilter 破坏的问题。
 * <p>
 * ReplaceRequestFilter(来自 request-wrapper jar,logan-starter-core 传递依赖)
 * 会读取 request 的 InputStream 来包装请求体,导致后续 Spring 解析 multipart 时
 * 抛出 "Stream closed" 异常。
 * <p>
 * 解决方案:注册一个高优先级 Filter,对 multipart 请求提前触发 Servlet 容器的
 * multipart 解析(通过调用 request.getParts()),使文件数据被缓存到临时文件中。
 * 这样即使后续 ReplaceRequestFilter 消费了 InputStream,multipart 数据仍然可用。
 */
@Slf4j
@Configuration
public class MultipartFilterConfig {
    private static final String MULTIPART = "multipart/";
    @Bean
    public FilterRegistrationBean<Filter> earlyMultipartParsingFilter() {
        FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new EarlyMultipartParsingFilter());
        registration.addUrlPatterns("/*");
        // 确保在 ReplaceRequestFilter 之前执行
        registration.setOrder(Integer.MIN_VALUE + 10);
        registration.setName("earlyMultipartParsingFilter");
        return registration;
    }
    /**
     * 在 filter 链最前面对 multipart 请求提前解析,
     * 让 Tomcat 将文件数据缓存到磁盘,避免后续 filter 消费 InputStream 导致 Stream closed。
     */
    static class EarlyMultipartParsingFilter implements Filter {
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            if (request instanceof HttpServletRequest) {
                HttpServletRequest httpRequest = (HttpServletRequest) request;
                String contentType = httpRequest.getContentType();
                if (contentType != null && contentType.toLowerCase().startsWith(MULTIPART)) {
                    // 提前触发 multipart 解析,Tomcat 会将 parts 缓存
                    try {
                        httpRequest.getParts();
                    } catch (Exception e) {
                        log.warn("Early multipart parsing failed, will retry later: {}", e.getMessage());
                    }
                }
            }
            chain.doFilter(request, response);
        }
    }
}
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/config/MyLocaleResolver.java
New file
@@ -0,0 +1,83 @@
package com.xiaopeng.trafficControl.config;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.LocaleResolver;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Locale;
public class MyLocaleResolver implements LocaleResolver {
    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        //1=中文,2=英文,3=印尼文
        //1=Chinese, 2=English, 3=Indonesian.
        String language = getQueryParams(request, "language");
        Locale locale = null;
        if (StringUtils.isEmpty(language)) {
            locale = Locale.getDefault();
            language = "1";
        }
        //如果请求不为空
        //If the request is not empty.
        if(!StringUtils.isEmpty(language)){
            if (language.equals("1")) {
                locale = new Locale("zh", "CN");
            } else if (language.equals("2")) {
                locale = new Locale("en", "US");
            }
        }
        return locale;
    }
    @Override
    public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
    }
    public String getQueryParams(HttpServletRequest request, String key) {
        try {
            String method = request.getMethod();
            if("POST".equals(method)){
                String parameter = request.getParameter(key);
                if(!StringUtils.isEmpty(parameter)){
                    return parameter;
                }
                Object attribute = request.getAttribute(key);
                if(null != attribute){
                    return attribute.toString();
                }
                StringBuffer sb = new StringBuffer();
                ServletInputStream inputStream = request.getInputStream();
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
                String s;
                while ((s = bufferedReader.readLine()) != null){
                    sb.append(s);
                }
                bufferedReader.close();
                inputStream.close();
                JSONObject jsonObject = JSON.parseObject(sb.toString());
                return jsonObject.getString(key);
            }else{
                String parameter = request.getParameter(key);
                if(!StringUtils.isEmpty(parameter)){
                    return parameter;
                }
                Object attribute = request.getAttribute(key);
                if(null != attribute){
                    return attribute.toString();
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/config/MybatisPlusConfig.java
New file
@@ -0,0 +1,51 @@
package com.xiaopeng.trafficControl.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * @author xiaochen
 * @ClassName MybatisPlusConfig
 * @Description MybatisPlus相关配置
 * @date 2020-09-22 11:22、
 * 直接以实现类作为bean的注入(有事务管理的类)
 * @EnableTransactionManagement(proxyTargetClass = true)
 */
@Configuration
public class MybatisPlusConfig {
    private final DataUpdateHandlerConfig dataUpdateHandler;
    @Autowired
    public MybatisPlusConfig(DataUpdateHandlerConfig dataUpdateHandler) {
        this.dataUpdateHandler = dataUpdateHandler;
    }
    /**
     * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
    /**
     * 自动填充功能
     *
     * @return
     */
    @Bean
    public GlobalConfig globalConfig() {
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setMetaObjectHandler(dataUpdateHandler);
        return globalConfig;
    }
}
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/config/TransactionConfiguration.java
New file
@@ -0,0 +1,27 @@
package com.xiaopeng.trafficControl.config;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
 * 分布式事务配置
 */
@Configuration
@EnableTransactionManagement
public class TransactionConfiguration {
    @Bean
    public PlatformTransactionManager txManager(final DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
    @Bean
    public JdbcTemplate jdbcTemplate(final DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/config/log/FeignLoggingAspect.java
New file
@@ -0,0 +1,83 @@
package com.xiaopeng.trafficControl.config.log;
import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
 * Feign 调用日志切面
 *
 * <p>拦截所有带 @FeignClient 注解的接口方法,记录:
 * <ul>
 *   <li>调用的接口类名 + 方法名</li>
 *   <li>入参(JSON 序列化)</li>
 *   <li>出参(JSON 序列化)</li>
 *   <li>耗时(ms)</li>
 *   <li>异常信息(含完整堆栈)</li>
 * </ul>
 */
@Slf4j
@Aspect
@Component
public class FeignLoggingAspect {
    /**
     * 拦截所有带 @FeignClient 注解的接口的所有方法
     */
    @Around("within(@org.springframework.cloud.openfeign.FeignClient *)")
    public Object logFeignCall(ProceedingJoinPoint pjp) throws Throwable {
        return doLog(pjp);
    }
    private Object doLog(ProceedingJoinPoint pjp) throws Throwable {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        // 使用接口声明类名,避免打印动态代理类名(如 $Proxy270)
        String className = signature.getDeclaringType().getSimpleName();
        String methodName = method.getName();
        String fullMethod = className + "#" + methodName;
        Object[] args = pjp.getArgs();
        String argsJson = safeToJson(args);
        log.info("[Feign] >>> 调用开始 | method={} | args={}", fullMethod, argsJson);
        long start = System.currentTimeMillis();
        try {
            Object result = pjp.proceed();
            long elapsed = System.currentTimeMillis() - start;
            String resultJson = safeToJson(result);
            log.info("[Feign] <<< 调用成功 | method={} | elapsed={}ms | result={}", fullMethod, elapsed, resultJson);
            return result;
        } catch (Throwable ex) {
            long elapsed = System.currentTimeMillis() - start;
            log.error("[Feign] <<< 调用异常 | method={} | elapsed={}ms | error={} | args={}",
                    fullMethod, elapsed, ex.getMessage(), argsJson, ex);
            throw ex;
        }
    }
    /**
     * 安全序列化为 JSON,避免序列化失败导致日志切面本身抛异常
     */
    private String safeToJson(Object obj) {
        if (obj == null) {
            return "null";
        }
        try {
            if (obj instanceof Object[]) {
                return JSON.toJSONString(Arrays.asList((Object[]) obj));
            }
            return JSON.toJSONString(obj);
        } catch (Exception e) {
            return "[序列化失败: " + obj.getClass().getSimpleName() + "]";
        }
    }
}
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/config/log/RequestResponseLoggingFilter.java
New file
@@ -0,0 +1,139 @@
package com.xiaopeng.trafficControl.config.log;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
 * 请求/响应日志过滤器
 * 打印:traceId、method、uri、queryString、请求体、响应状态、耗时、响应体
 */
@Slf4j
@Component
@Order(Ordered.HIGHEST_PRECEDENCE + 10)
public class RequestResponseLoggingFilter extends OncePerRequestFilter {
    /** 不打印 body 的路径前缀(健康检查、actuator 等) */
    private static final Set<String> EXCLUDE_PATHS = new HashSet<>(Arrays.asList(
            "/actuator", "/healthcheck", "/health", "/prometheus"
    ));
    /** 只对这些 Content-Type 打印 body(避免打印二进制流) */
    private static final Set<String> LOGGABLE_CONTENT_TYPES = new HashSet<>(Arrays.asList(
            MediaType.APPLICATION_JSON_VALUE,
            MediaType.APPLICATION_JSON_UTF8_VALUE,
            MediaType.TEXT_PLAIN_VALUE,
            MediaType.TEXT_XML_VALUE,
            MediaType.APPLICATION_XML_VALUE,
            "application/x-www-form-urlencoded"
    ));
    private static final int MAX_BODY_LENGTH = 2000;
    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) {
        String uri = request.getRequestURI();
        return EXCLUDE_PATHS.stream().anyMatch(uri::startsWith);
    }
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
                                    FilterChain chain) throws ServletException, IOException {
        // 初始化 MDC(Filter 先于 Interceptor 执行,在此统一设置)
        String traceId = request.getHeader("X-Trace-Id");
        if (traceId == null || traceId.isEmpty()) {
            traceId = java.util.UUID.randomUUID().toString().replace("-", "");
        }
        MDC.put("traceId",    traceId);
        MDC.put("clientIp",   getClientIp(request));
        MDC.put("requestUri", request.getRequestURI());
        response.setHeader("X-Trace-Id", traceId);
        ContentCachingRequestWrapper reqWrapper  = new ContentCachingRequestWrapper(request);
        ContentCachingResponseWrapper respWrapper = new ContentCachingResponseWrapper(response);
        long start = System.currentTimeMillis();
        try {
            chain.doFilter(reqWrapper, respWrapper);
        } finally {
            long cost = System.currentTimeMillis() - start;
            logRequest(reqWrapper);
            logResponse(respWrapper, cost);
            // 必须把响应体写回,否则客户端收不到数据
            respWrapper.copyBodyToResponse();
            MDC.clear();
        }
    }
    private String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip != null && !ip.isEmpty() && !"unknown".equalsIgnoreCase(ip)) {
            return ip.split(",")[0].trim();
        }
        ip = request.getHeader("X-Real-IP");
        if (ip != null && !ip.isEmpty() && !"unknown".equalsIgnoreCase(ip)) {
            return ip;
        }
        return request.getRemoteAddr();
    }
    private void logRequest(ContentCachingRequestWrapper request) {
        String traceId = MDC.get("traceId");
        String uri     = request.getRequestURI();
        String query   = request.getQueryString();
        String method  = request.getMethod();
        String body    = extractBody(request.getContentAsByteArray(), request.getContentType());
        log.info(">>> [{}] {} {}{} | body={}",
                traceId,
                method,
                uri,
                query != null ? "?" + query : "",
                body);
    }
    private void logResponse(ContentCachingResponseWrapper response, long cost) {
        String traceId = MDC.get("traceId");
        int    status  = response.getStatus();
        String body    = extractBody(response.getContentAsByteArray(), response.getContentType());
        log.info("<<< [{}] status={} cost={}ms | body={}",
                traceId, status, cost, body);
    }
    private String extractBody(byte[] bodyBytes, String contentType) {
        if (bodyBytes == null || bodyBytes.length == 0) {
            return "";
        }
        if (!isLoggableContentType(contentType)) {
            return "[binary, " + bodyBytes.length + " bytes]";
        }
        String body = new String(bodyBytes, StandardCharsets.UTF_8);
        if (body.length() > MAX_BODY_LENGTH) {
            body = body.substring(0, MAX_BODY_LENGTH) + "...(truncated)";
        }
        return body;
    }
    private boolean isLoggableContentType(String contentType) {
        if (contentType == null) return true;
        String ct = contentType.toLowerCase();
        return LOGGABLE_CONTENT_TYPES.stream().anyMatch(ct::contains);
    }
}
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/constant/I18nKeyConstant.java
New file
@@ -0,0 +1,69 @@
package com.xiaopeng.trafficControl.constant;
/**
 * @author MiTao
 * @date 2026-02-06 17:34
 * 国际化消息键常量
 *
 */
public interface I18nKeyConstant {
    //========== 小程序业务流程 ==========
    String ORDER_NOT_EXISTS = "order.not.exists";
    String VEHICLE_NOT_EXISTS = "vehicle.not.exists";
    // ========== 车辆导入相关 ==========
    String VEHICLE_IMPORT_FAILED = "vehicle.import.failed";
    String VEHICLE_IMPORT_DATA_EMPTY = "vehicle.import.data.empty";
    String VEHICLE_IMPORT_FIELDS_REQUIRED = "vehicle.import.fields.required";
    // ========== 车队删除相关 ==========
    String FLEET_DELETE_HAS_BOUND_VEHICLE_OR_USER = "fleet.delete.has.bound.vehicle.or.user";
    // ========== 车辆运营相关 ==========
    String VEHICLE_OPERATION_INFO_INCOMPLETE = "vehicle.operation.info.incomplete";
    String VEHICLE_BATCH_OPERATION_CONDITION_NOT_MET = "vehicle.batch.operation.condition.not.met";
    String VEHICLE_TIME_EXPIRED = "vehicle.time.expired";
    // ========== 车队相关 ==========
    String FLEET_OPERATION_USER_BOUND_V1 = "fleet.operation.user.bound.v1";
    String FLEET_OPERATION_USER_BOUND_2 = "fleet.operation.user.bound.v2";
    String FLEET_VEHICLE_BOUND_V1 = "fleet.vehicle.bound.v1";
    String FLEET_VEHICLE_BOUND_V2 = "fleet.vehicle.bound.v2";
    // ========== 车辆开关车门 ==========
    String VEHICLE_NOT_P_GEAR = "vehicle.not.p.gear";
    String VEHICLE_DISTANCE_TOO_LONG = "vehicle.distance.too.long";
    // ========== 车辆温度控制 ==========
    String VEHICLE_TEMPERATURE_UP = "vehicle.temperature.up";
    String VEHICLE_TEMPERATURE_DOWN = "vehicle.temperature.down";
    // ========== 车辆新增/编辑校验 ==========
    String VEHICLE_CODE_INVALID = "vehicle.code.invalid";
    String VEHICLE_CODE_EXISTS = "vehicle.code.exists";
    String VEHICLE_VIN_INVALID = "vehicle.vin.invalid";
    String VEHICLE_VIN_EXISTS = "vehicle.vin.exists";
    String VEHICLE_PLATE_INVALID = "vehicle.plate.invalid";
    String VEHICLE_PLATE_EXISTS = "vehicle.plate.exists";
    String VEHICLE_COLOR_INVALID = "vehicle.color.invalid";
    String VEHICLE_ELECTRONIC_NOT_EXISTS = "vehicle.electronic.not.exists";
    // ========== 车辆导入校验 ==========
    String VEHICLE_IMPORT_VALIDATE_FAIL = "vehicle.import.validate.fail";
    String VEHICLE_IMPORT_CODE_INVALID = "vehicle.import.code.invalid";
    String VEHICLE_IMPORT_VIN_INVALID = "vehicle.import.vin.invalid";
    String VEHICLE_IMPORT_PLATE_INVALID = "vehicle.import.plate.invalid";
    String VEHICLE_IMPORT_COLOR_INVALID = "vehicle.import.color.invalid";
    String VEHICLE_IMPORT_CODE_DUPLICATE = "vehicle.import.code.duplicate";
    String VEHICLE_IMPORT_VIN_DUPLICATE = "vehicle.import.vin.duplicate";
    String VEHICLE_IMPORT_PLATE_DUPLICATE = "vehicle.import.plate.duplicate";
    String VEHICLE_IMPORT_CODE_EXISTS = "vehicle.import.code.exists";
    String VEHICLE_IMPORT_VIN_EXISTS = "vehicle.import.vin.exists";
    String VEHICLE_IMPORT_PLATE_EXISTS = "vehicle.import.plate.exists";
    // ========== 车辆删除相关 ==========
    String VEHICLE_DELETE_HAS_BOUND_FLEET = "vehicle.delete.has.bound.fleet";
}
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/enums/SignatureType.java
New file
@@ -0,0 +1,15 @@
package com.xiaopeng.trafficControl.enums;
/** 签名类型枚举 */
public enum SignatureType {
    MD5("MD5"), SHA1("SHA1"), SHA256("SHA256");
    private String value;
    private SignatureType(String value) {
        this.value = value;
    }
    public String getValue() {
        return value;
    }
}
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/util/HMACSHA1.java
New file
@@ -0,0 +1,35 @@
package com.xiaopeng.trafficControl.util;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class HMACSHA1 {
    private static final String MAC_NAME = "HmacSHA1";
    private static final String ENCODING = "UTF-8";
    /**
     * 使用 HMAC-SHA1 签名方法对对encryptText进行签名
     *
     * @param encryptText 被签名的字符串
     * @param encryptKey  密钥
     * @return
     * @throws Exception
     */
    public static byte[] HmacSHA1Encrypt(String encryptText, String encryptKey) throws Exception {
        byte[] data = encryptKey.getBytes(ENCODING);
        // 根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称
        Mac mac = Mac.getInstance(MAC_NAME);
        SecretKey secretKey = new SecretKeySpec(data, MAC_NAME);
        // 生成一个指定 Mac 算法 的 Mac 对象
        // 用给定密钥初始化 Mac 对象
        mac.init(secretKey);
        byte[] text = encryptText.getBytes(ENCODING);
        // 完成 Mac 操作
        return mac.doFinal(text);
    }
}
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/util/HexUtil.java
New file
@@ -0,0 +1,36 @@
package com.xiaopeng.trafficControl.util;
import com.xiaopeng.trafficControl.DecodingException;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
/**
 * 与字节16进制相关的工具类<br/>
 */
public class HexUtil {
    /** 将十六进制字符串转成字节数组 */
    public static byte[] toHexBytes(String hexText) {
        try {
            return Hex.decodeHex(hexText.toCharArray());
        } catch (DecoderException e) {
            throw new DecodingException(e);
        }
    }
    /** 将字节数组转成十六进制字符串(字母小写) */
    public static String toLowerCase(byte[] hex) {
        return new String(Hex.encodeHex(hex, true));
    }
    /** 将字节数组转成十六进制字符串(字母大写) */
    public static String toUpperCase(byte[] hex) {
        return new String(Hex.encodeHex(hex, false));
    }
    /** 将字节数组转成整数 */
    public static int hashToInt(byte[] hash) {
        return (int) (hash[3] << 24 | hash[2] << 16 | hash[1] << 8 | hash[0]);
    }
}
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/util/ResourceUtil.java
New file
@@ -0,0 +1,82 @@
package com.xiaopeng.trafficControl.util;
import java.io.*;
import java.lang.reflect.Method;
import java.net.URL;
/**
 * 资源工具类
 * @author binghuoliu
 *
 */
public class ResourceUtil {
    /**
     * 读取classpath下的文件<br>
     * 读取classpath下的文件 一般用于读取classpath下的配置文件,注意读取的配置文件路径是相对传入参数clazz的load入路径. 例:<br>
     * ClassTest c1;//假设c1是从/usr/local/classpath/ 载入<br>
     * ClassTest c2;//假设c2是从/home/classpath/ 载入<br>
     * ............<br>
     * loadConfigFile("a.xml",c1.class);//从/usr/local/classpath1/下寻找a.xml<br>
     * loadConfigFile("a.xml",c2.class);//从/home/classpath/下寻找a.xml<br>
     * @param resource 资源路径
     * @param clazz
     * @return InputStream 文件的inputstram,如果找不到则返回null
     */
    @SuppressWarnings("unchecked")
    public static InputStream loadConfigFile(String resource, Class clazz) {
        ClassLoader classLoader = null;
        try {
            Method method = Thread.class.getMethod("getContextClassLoader");
            classLoader = (ClassLoader) method.invoke(Thread.currentThread());
        } catch (Exception e) {
            throw new RuntimeException("loadConfigFile error: ", e);
        }
        if (classLoader == null) {
            classLoader = clazz.getClassLoader();
        }
        try {
            if (classLoader != null) {
                URL url = classLoader.getResource(resource);
                if (url == null) {
                    System.out.println("Can not find resource:" + resource);
                    return null;
                }
                if (url.toString().startsWith("jar:file:")) {
                    System.out.println("Get resource \"" + resource + "\" from jar:\t" + url.toString());
                    return clazz.getResourceAsStream(resource.startsWith("/") ? resource : "/" + resource);
                } else {
                    System.out.println("Get resource \"" + resource + "\" from:\t" + url.toString());
                    return new FileInputStream(new File(url.toURI()));
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("loadConfigFile error: ", e);
        }
        return null;
    }
    /**
     * 释放资源(有异常抛出)
     * @param closeable
     * @throws IOException
     */
    public static void close(Closeable closeable) throws IOException {
        if (closeable != null) {
            closeable.close();
        }
    }
    /**
     * 以优雅的形式释放资源(内部吃掉了异常)
     * @param closeable
     */
    public static void closeGracefully(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (IOException e) {
            }
        }
    }
}
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/util/SHA1Util.java
New file
@@ -0,0 +1,118 @@
package com.xiaopeng.trafficControl.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
/**
 * 该API支持线程安全<br/>
 */
public class SHA1Util {
    // --------------------------计算SHA1大写字符串----------------------------------------------
    /**
     * 计算出文件的SHA1大写字符串
     *
     * @param file
     * @return
     * @throws IOException
     */
    public static String getSHA1UpperString(File file) throws IOException {
        return HexUtil.toUpperCase(getSHA1Bytes(file));
    }
    /**
     * 计算出SHA1后十六进制结果(大写)
     *
     * @param s
     * @return
     */
    public static String getSHA1UpperString(String s) {
        try {
            return getSHA1UpperString(s.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 计算出SHA1后十六进制结果(大写)
     *
     * @param bytes
     * @return
     */
    public static String getSHA1UpperString(byte[] bytes) {
        return HexUtil.toUpperCase(getSHA1Bytes(bytes));
    }
    // --------------------------计算SHA1小写字符串----------------------------------------------
    /**
     * 计算出文件的SHA1小写字符串
     *
     * @param file
     * @return
     * @throws IOException
     */
    public static String getSHA1LowerString(File file) throws IOException {
        return HexUtil.toLowerCase(getSHA1Bytes(file));
    }
    /**
     * 计算出SHA1后十六进制结果(小写)
     *
     * @param s
     * @return
     */
    public static String getSHA1LowerString(String s) {
        try {
            return getSHA1LowerString(s.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 计算出SHA1后十六进制结果(小写)
     *
     * @param bytes
     * @return
     */
    public static String getSHA1LowerString(byte[] bytes) {
        return HexUtil.toLowerCase(getSHA1Bytes(bytes));
    }
    // ------------------------计算出SHA1的byte[]------------------------------------------------
    public static byte[] getSHA1Bytes(byte[] bytes) {
        ThreadLocalSHA1.current().update(bytes);
        return ThreadLocalSHA1.current().digest();
    }
    public static byte[] getSHA1Bytes(File file) throws IOException {
        FileInputStream in = null;
        FileChannel ch = null;
        try {
            in = new FileInputStream(file);
            ch = in.getChannel();
            MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY, 0, file.length());
            ThreadLocalSHA1.current().update(byteBuffer);
            return ThreadLocalSHA1.current().digest();
        } finally {
            ResourceUtil.closeGracefully(ch);
            ResourceUtil.closeGracefully(in);
        }
    }
    // ------------------------------------------------------------------------
    public static boolean checkPassword(String originContent, String sha1Content) {
        String s = getSHA1LowerString(originContent);
        return s.equals(sha1Content);
    }
    // ------------------------------------------------------------------------
}
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/util/SignatureUtils.java
New file
@@ -0,0 +1,114 @@
package com.xiaopeng.trafficControl.util;
import com.xiaopeng.unifiedverification.util.md5.MD5Util;
import com.xiaopeng.unifiedverification.util.sha256.SHA256Util;
import com.xiaopeng.trafficControl.enums.SignatureType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
public class SignatureUtils {
    private static final Logger LOGGER = LoggerFactory.getLogger(SignatureUtils.class);
    /**
     * 通用签名方法,签名算法为SHA1<br/>
     * 签名原文拼装规则:<br/>
     * ①paraMap按key的自然排序,并按key1+value1+key2+value2的规则拼接,中间无分隔符<br/>
     * ②在第①步骤组装的String前面追加appid的值<br/>
     * ③在第①步骤组装的String后面追加appSecret的值<br/>
     *
     * @param appId     业务系统唯一标识
     * @param paraMap   所需要传递的参数map
     * @param appSecret 分配给业务系统的秘钥
     * @return
     */
    public static String getSignatureSHA1(String appId, Map<String, String> paraMap, String appSecret) {
        return getSignature(appId, paraMap, appSecret, SignatureType.SHA1);
    }
    /**
     * 通用签名方法<br/>
     * 签名原文拼装规则:<br/>
     * ①paraMap按key的自然排序,并按key1+value1+key2+value2的规则拼接,中间无分隔符<br/>
     * ②在第①步骤组装的String前面追加appid的值<br/>
     * ③在第①步骤组装的String后面追加appSecret的值<br/>
     *
     * @param appId         业务系统唯一标识
     * @param paraMap       所需要传递的参数map
     * @param appSecret     分配给业务系统的秘钥
     * @param signatureType 签名算法类型(参考SignatureType)
     * @return
     */
    public static String getSignature(String appId, Map<String, String> paraMap, String appSecret,
                                      SignatureType signatureType) {
        String originStr = buildAllSignatureOriginStr(appId, paraMap, appSecret);
        LOGGER.info("originStr: {}", originStr);
        return getSignature(originStr, signatureType);
    }
    // ------------------------------------------------------------------------------------------
    /**
     * 构造计算签名的完整消息内容<br/>
     */
    public static String buildAllSignatureOriginStr(String appId, Map<String, String> paraMap, String appSecret) {
        StringBuilder sb = new StringBuilder(128);
        String result = sb.append(appId).append(buildMiddleSignatureOriginStr(paraMap)).append(appSecret).toString(); // 用于签名的原文
        return result;
    }
    /**
     * 构造计算签名的中间消息内容<br/>
     */
    public static String buildMiddleSignatureOriginStr(Map<String, String> map) {
        if (map.isEmpty()) {
            return "";
        }
        Map<String, String> treeMap = new TreeMap<String, String>(new Comparator<String>() {
            public int compare(String obj1, String obj2) {
                // 升序排序
                return obj1.compareTo(obj2);
            }
        });
        treeMap.putAll(map);
        Iterator<Map.Entry<String, String>> iter = treeMap.entrySet().iterator();
        StringBuilder stringBuilder = new StringBuilder(128);
        while (iter.hasNext()) {
            Map.Entry<String, String> entry = iter.next();
            stringBuilder.append(entry.getKey()).append(entry.getValue());
        }
        return stringBuilder.toString();
    }
    /**
     * 计算签名
     *
     * @param originStr
     *            用于签名的原始内容
     * @param signatureType
     *            签名算法类型(参考SignatureType)
     * @return 签名值
     */
    public static String getSignature(String originStr, SignatureType signatureType) {
        if (SignatureType.MD5 == signatureType) {
            return MD5Util.getMD5LowerString(originStr);
        } else if (SignatureType.SHA1 == signatureType) {
            return SHA1Util.getSHA1LowerString(originStr);
        } else if (SignatureType.SHA256 == signatureType) {
            return SHA256Util.getSHA256LowerString(originStr);
        } else { // 默认用SHA1
            return SHA1Util.getSHA1LowerString(originStr);
        }
    }
}
xp-robotaxi-traffic-control-boot/src/main/java/com/xiaopeng/trafficControl/util/ThreadLocalSHA1.java
New file
@@ -0,0 +1,26 @@
package com.xiaopeng.trafficControl.util;
import java.security.MessageDigest;
/**
 * SHA1算法计算散列值的ThreadLocal,避免多线程场景下的线程安全问题<br/>
 */
public class ThreadLocalSHA1 {
    private static final ThreadLocal<MessageDigest> localFormat = new ThreadLocal<MessageDigest>() {
        protected MessageDigest initialValue() {
            try {
                return MessageDigest.getInstance("SHA1");
            } catch (Exception e) {
                System.err.println(SHA1Util.class.getName() + "初始化失败,MessageDigest不支持SHA1Util。");
                e.printStackTrace();
                return null;
            }
        };
    };
    /** 获取当前线程对应的实例 */
    public static MessageDigest current() {
        return localFormat.get();
    }
}
xp-robotaxi-traffic-control-boot/src/main/resources/application-local.properties
New file
@@ -0,0 +1,104 @@
spring.autoconfigure.exclude=com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
spring.shardingsphere.props.sql.show=true
spring.shardingsphere.props.show-sql=true
spring.shardingsphere.datasource.names=xp0
spring.shardingsphere.datasource.xp0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.xp0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.xp0.url=jdbc:mysql://pc-bp1o444934f546768po.rwlb.rds.aliyuncs.com:3306/xp_rt_maintenance?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
spring.shardingsphere.datasource.xp0.username=xp_rt_maintenance
spring.shardingsphere.datasource.xp0.password=gWgoAv_bi02um8sN
spring.shardingsphere.datasource.xp0.druid.initial-size=10
spring.shardingsphere.datasource.xp0.druid.min-idle=10
spring.shardingsphere.datasource.xp0.druid.max-active=100
spring.shardingsphere.datasource.xp0.druid.max-wait=60000
spring.shardingsphere.datasource.xp0.druid.time-between-eviction-runs-millis=60000
spring.shardingsphere.datasource.xp0.druid.min-evictable-idle-time-millis=300000
spring.shardingsphere.datasource.xp0.druid.validation-query=SELECT 1
spring.shardingsphere.datasource.xp0.druid.test-while-idle=true
spring.shardingsphere.datasource.xp0.druid.test-on-borrow=false
spring.shardingsphere.datasource.xp0.druid.test-on-return=false
spring.shardingsphere.datasource.xp0.druid.pool-prepared-statements=true
spring.shardingsphere.datasource.xp0.druid.max-pool-prepared-statement-per-connection-size=20
spring.shardingsphere.datasource.xp0.druid.filters=stat,wall,log4j
spring.shardingsphere.datasource.xp0.druid.connection-properties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
spring.shardingsphere.datasource.xp0.druid.remove-abandoned=true
spring.shardingsphere.datasource.xp0.druid.remove-abandoned-timeout=1800
spring.shardingsphere.datasource.xp0.druid.log-abandoned=true
spring.shardingsphere.datasource.xp0.druid.stat-view-servlet.enabled=true
spring.shardingsphere.datasource.xp0.druid.stat-view-servlet.url-pattern=/druid/*
spring.shardingsphere.datasource.xp0.druid.stat-view-servlet.login-username=admin
spring.shardingsphere.datasource.xp0.druid.stat-view-servlet.login-password=admin
spring.shardingsphere.datasource.xp0.druid.stat-view-servlet.reset-enable=false
spring.shardingsphere.datasource.xp0.druid.wall.config.multi-statement-allow=false
spring.shardingsphere.rules.sharding.tables.xp_charging_record.actual-data-nodes=xp0.xp_charging_record_$->{0..9}
spring.shardingsphere.rules.sharding.tables.xp_charging_record.table-strategy.standard.sharding-column=vehicle_id
spring.shardingsphere.rules.sharding.tables.xp_charging_record.table-strategy.standard.sharding-algorithm-name=xp-charging-record-inline
spring.shardingsphere.rules.sharding.tables.xp_charging_record.key-generate-strategy.column=id
spring.shardingsphere.rules.sharding.tables.xp_charging_record.key-generate-strategy.key-generator-name=snowflake
spring.shardingsphere.rules.sharding.tables.xp_clock_in.actual-data-nodes=xp0.xp_clock_in_$->{0..9}
spring.shardingsphere.rules.sharding.tables.xp_clock_in.table-strategy.standard.sharding-column=app_user_id
spring.shardingsphere.rules.sharding.tables.xp_clock_in.table-strategy.standard.sharding-algorithm-name=xp-clock-in-inline
spring.shardingsphere.rules.sharding.tables.xp_clock_in.key-generate-strategy.column=id
spring.shardingsphere.rules.sharding.tables.xp_clock_in.key-generate-strategy.key-generator-name=snowflake
spring.shardingsphere.rules.sharding.tables.xp_task.actual-data-nodes=xp0.xp_task_$->{0..19}
spring.shardingsphere.rules.sharding.tables.xp_task.table-strategy.standard.sharding-column=vehicle_id
spring.shardingsphere.rules.sharding.tables.xp_task.table-strategy.standard.sharding-algorithm-name=xp-task-inline
spring.shardingsphere.rules.sharding.tables.xp_task.key-generate-strategy.column=id
spring.shardingsphere.rules.sharding.tables.xp_task.key-generate-strategy.key-generator-name=snowflake
spring.shardingsphere.rules.sharding.tables.xp_task_handle_detail.actual-data-nodes=xp0.xp_task_handle_detail_$->{0..19}
spring.shardingsphere.rules.sharding.tables.xp_task_handle_detail.table-strategy.standard.sharding-column=task_id
spring.shardingsphere.rules.sharding.tables.xp_task_handle_detail.table-strategy.standard.sharding-algorithm-name=xp-task-handle-detail-inline
spring.shardingsphere.rules.sharding.tables.xp_task_handle_detail.key-generate-strategy.column=id
spring.shardingsphere.rules.sharding.tables.xp_task_handle_detail.key-generate-strategy.key-generator-name=snowflake
spring.shardingsphere.rules.sharding.tables.xp_task_handle_detail_routine.actual-data-nodes=xp0.xp_task_handle_detail_routine_$->{0..19}
spring.shardingsphere.rules.sharding.tables.xp_task_handle_detail_routine.table-strategy.standard.sharding-column=task_id
spring.shardingsphere.rules.sharding.tables.xp_task_handle_detail_routine.table-strategy.standard.sharding-algorithm-name=xp-task-handle-detail-routine-inline
spring.shardingsphere.rules.sharding.tables.xp_task_handle_detail_routine.key-generate-strategy.column=id
spring.shardingsphere.rules.sharding.tables.xp_task_handle_detail_routine.key-generate-strategy.key-generator-name=snowflake
spring.shardingsphere.rules.sharding.tables.xp_vehicle_detection.actual-data-nodes=xp0.xp_vehicle_detection_$->{0..9}
spring.shardingsphere.rules.sharding.tables.xp_vehicle_detection.table-strategy.standard.sharding-column=task_id
spring.shardingsphere.rules.sharding.tables.xp_vehicle_detection.table-strategy.standard.sharding-algorithm-name=xp-vehicle-detection-inline
spring.shardingsphere.rules.sharding.tables.xp_vehicle_detection.key-generate-strategy.column=id
spring.shardingsphere.rules.sharding.tables.xp_vehicle_detection.key-generate-strategy.key-generator-name=snowflake
spring.shardingsphere.rules.sharding.tables.xp_vehicle_preparation.actual-data-nodes=xp0.xp_vehicle_preparation_$->{0..9}
spring.shardingsphere.rules.sharding.tables.xp_vehicle_preparation.table-strategy.standard.sharding-column=task_id
spring.shardingsphere.rules.sharding.tables.xp_vehicle_preparation.table-strategy.standard.sharding-algorithm-name=xp-vehicle-preparation-inline
spring.shardingsphere.rules.sharding.tables.xp_vehicle_preparation.key-generate-strategy.column=id
spring.shardingsphere.rules.sharding.tables.xp_vehicle_preparation.key-generate-strategy.key-generator-name=snowflake
spring.shardingsphere.rules.sharding.tables.xp_vehicle_repair.actual-data-nodes=xp0.xp_vehicle_repair_$->{0..9}
spring.shardingsphere.rules.sharding.tables.xp_vehicle_repair.table-strategy.standard.sharding-column=task_id
spring.shardingsphere.rules.sharding.tables.xp_vehicle_repair.table-strategy.standard.sharding-algorithm-name=xp-vehicle-repair-inline
spring.shardingsphere.rules.sharding.tables.xp_vehicle_repair.key-generate-strategy.column=id
spring.shardingsphere.rules.sharding.tables.xp_vehicle_repair.key-generate-strategy.key-generator-name=snowflake
spring.shardingsphere.rules.sharding.tables.xp_work_order.actual-data-nodes=xp0.xp_work_order_$->{0..9}
spring.shardingsphere.rules.sharding.tables.xp_work_order.table-strategy.standard.sharding-column=feedback_user_phone
spring.shardingsphere.rules.sharding.tables.xp_work_order.table-strategy.standard.sharding-algorithm-name=xp-work-order-inline
spring.shardingsphere.rules.sharding.tables.xp_work_order.key-generate-strategy.column=id
spring.shardingsphere.rules.sharding.tables.xp_work_order.key-generate-strategy.key-generator-name=snowflake
spring.shardingsphere.rules.sharding.tables.xp_work_order_log.actual-data-nodes=xp0.xp_work_order_log_$->{0..19}
spring.shardingsphere.rules.sharding.tables.xp_work_order_log.table-strategy.standard.sharding-column=work_order_id
spring.shardingsphere.rules.sharding.tables.xp_work_order_log.table-strategy.standard.sharding-algorithm-name=xp-work-order-log-inline
spring.shardingsphere.rules.sharding.tables.xp_work_order_log.key-generate-strategy.column=id
spring.shardingsphere.rules.sharding.tables.xp_work_order_log.key-generate-strategy.key-generator-name=snowflake
spring.shardingsphere.rules.sharding.sharding-algorithms.xp-charging-record-inline.type=INLINE
spring.shardingsphere.rules.sharding.sharding-algorithms.xp-charging-record-inline.props.algorithm-expression=xp_charging_record_${vehicle_id % 20}
spring.shardingsphere.rules.sharding.sharding-algorithms.xp-clock-in-inline.type=INLINE
spring.shardingsphere.rules.sharding.sharding-algorithms.xp-clock-in-inline.props.algorithm-expression=xp_clock_in_${app_user_id % 10}
spring.shardingsphere.rules.sharding.sharding-algorithms.xp-task-inline.type=INLINE
spring.shardingsphere.rules.sharding.sharding-algorithms.xp-task-inline.props.algorithm-expression=xp_task_${vehicle_id % 20}
spring.shardingsphere.rules.sharding.sharding-algorithms.xp-task-handle-detail-inline.type=INLINE
spring.shardingsphere.rules.sharding.sharding-algorithms.xp-task-handle-detail-inline.props.algorithm-expression=xp_task_handle_detail_${task_id % 20}
spring.shardingsphere.rules.sharding.sharding-algorithms.xp-task-handle-detail-routine-inline.type=INLINE
spring.shardingsphere.rules.sharding.sharding-algorithms.xp-task-handle-detail-routine-inline.props.algorithm-expression=xp_task_handle_detail_routine_${task_id % 20}
spring.shardingsphere.rules.sharding.sharding-algorithms.xp-vehicle-detection-inline.type=INLINE
spring.shardingsphere.rules.sharding.sharding-algorithms.xp-vehicle-detection-inline.props.algorithm-expression=xp_vehicle_detection_${task_id % 10}
spring.shardingsphere.rules.sharding.sharding-algorithms.xp-vehicle-preparation-inline.type=INLINE
spring.shardingsphere.rules.sharding.sharding-algorithms.xp-vehicle-preparation-inline.props.algorithm-expression=xp_vehicle_preparation_${task_id % 10}
spring.shardingsphere.rules.sharding.sharding-algorithms.xp-vehicle-repair-inline.type=INLINE
spring.shardingsphere.rules.sharding.sharding-algorithms.xp-vehicle-repair-inline.props.algorithm-expression=xp_vehicle_repair_${task_id % 10}
spring.shardingsphere.rules.sharding.sharding-algorithms.xp-work-order-inline.type=INLINE
spring.shardingsphere.rules.sharding.sharding-algorithms.xp-work-order-inline.props.algorithm-expression=xp_work_order_${feedback_user_phone % 10}
spring.shardingsphere.rules.sharding.sharding-algorithms.xp-work-order-log-inline.type=INLINE
spring.shardingsphere.rules.sharding.sharding-algorithms.xp-work-order-log-inline.props.algorithm-expression=xp_work_order_log_${work_order_id % 20}
spring.shardingsphere.rules.sharding.key-generators.snowflake.type=SNOWFLAKE
seata.enabled=false
xp-robotaxi-traffic-control-boot/src/main/resources/i18n/messages.properties
xp-robotaxi-traffic-control-boot/src/main/resources/i18n/messages_en_US.properties
xp-robotaxi-traffic-control-boot/src/main/resources/i18n/messages_zh_CN.properties
xp-robotaxi-traffic-control-boot/src/main/resources/logback.xml
New file
@@ -0,0 +1,222 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,比如: 如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文档如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文档是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration  scan="true" scanPeriod="10 seconds">
    <contextName>logback</contextName>
    <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义后,可以使“${}”来使用变量。 -->
    <property name="log.path" value="/data/log/app/xp-robotaxi-traffic-control-boot"/>
    <!--0. 日志格式和颜色渲染 -->
    <!-- 彩色日志依赖的渲染类 -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
    <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
    <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
    <!-- 彩色日志格式 -->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
    <!--1. 输出到控制台-->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>debug</level>
        </filter>
        <encoder>
            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            <!-- 设置字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <!--2. 输出到文档-->
    <!-- 2.1 level为 DEBUG 日志,时间滚动输出  -->
    <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${log.path}/debug.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 日志归档 -->
            <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档只记录debug级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>debug</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!-- 2.2 level为 INFO 日志,时间滚动输出  -->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${log.path}/info.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天日志归档路径以及格式 -->
            <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档只记录info级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!-- 2.3 level为 WARN 日志,时间滚动输出  -->
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${log.path}/warn.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档只记录warn级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>warn</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!-- 2.4 level为 ERROR 日志,时间滚动输出  -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${log.path}/error.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档只记录ERROR级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!-- 2.5 所有 除了DEBUG级别的其它高于DEBUG的 日志,记录到一个文件  -->
    <appender name="ALL_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${log.path}/all.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/all-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档记录除了DEBUG级别的其它高于DEBUG的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUG</level>
            <onMatch>DENY</onMatch>
            <onMismatch>ACCEPT</onMismatch>
        </filter>
    </appender>
    <!--
        <logger>用来设置某一个包或者具体的某一个类的日志打印级别、
        以及指定<appender>。<logger>仅有一个name属性,
        一个可选的level和一个可选的addtivity属性。
        name:用来指定受此logger约束的某一个包或者具体的某一个类。
        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
              还有一个特殊值INHERITED或者同义词NULL,代表强制执行上级的级别。
              如果未设置此属性,那么当前logger将会继承上级的级别。
        addtivity:是否向上级logger传递打印信息。默认是true。
        <logger name="org.springframework.web" level="info"/>
        <logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>
    -->
    <!--
        root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
        不能设置为INHERITED或者同义词NULL。默认是DEBUG
        可以包含零个或多个元素,标识这个appender将会添加到这个logger。
    -->
    <!-- 4  最终的策略:
                 基本策略(root级) + 根据profile在启动时, logger标签中定制化package日志级别(优先级高于上面的root级)-->
    <springProfile name="dev">
        <root level="info">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="DEBUG_FILE" />
            <appender-ref ref="INFO_FILE" />
            <appender-ref ref="WARN_FILE" />
            <appender-ref ref="ERROR_FILE" />
            <appender-ref ref="ALL_FILE" />
        </root>
        <logger name="com.stylefeng.guns.modular.system.dao" level="debug"/>
    </springProfile>
    <springProfile name="test">
        <root level="info">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="DEBUG_FILE" />
            <appender-ref ref="INFO_FILE" />
            <appender-ref ref="WARN_FILE" />
            <appender-ref ref="ERROR_FILE" />
            <appender-ref ref="ALL_FILE" />
        </root>
    </springProfile>
    <springProfile name="prod">
        <root level="info">
            <!-- 生产环境最好不配置console写文件 -->
            <appender-ref ref="DEBUG_FILE" />
            <appender-ref ref="INFO_FILE" />
            <appender-ref ref="WARN_FILE" />
            <appender-ref ref="ERROR_FILE" />
            <appender-ref ref="ALL_FILE" />
        </root>
    </springProfile>
</configuration>
xp-robotaxi-traffic-control-boot/src/main/resources/logback.xml.bak
New file
@@ -0,0 +1,222 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,比如: 如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文档如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文档是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration  scan="true" scanPeriod="10 seconds">
    <contextName>logback</contextName>
    <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义后,可以使"${}"来使用变量。 -->
    <property name="log.path" value="/data/log/app/ruoyi-account"/>
    <!--0. 日志格式和颜色渲染 -->
    <!-- 彩色日志依赖的渲染类 -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
    <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
    <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
    <!-- 彩色日志格式 -->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
    <!--1. 输出到控制台-->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>debug</level>
        </filter>
        <encoder>
            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            <!-- 设置字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <!--2. 输出到文档-->
    <!-- 2.1 level为 DEBUG 日志,时间滚动输出  -->
    <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${log.path}/debug.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 日志归档 -->
            <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档只记录debug级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>debug</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!-- 2.2 level为 INFO 日志,时间滚动输出  -->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${log.path}/info.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天日志归档路径以及格式 -->
            <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档只记录info级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!-- 2.3 level为 WARN 日志,时间滚动输出  -->
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${log.path}/warn.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档只记录warn级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>warn</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!-- 2.4 level为 ERROR 日志,时间滚动输出  -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${log.path}/error.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档只记录ERROR级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!-- 2.5 所有 除了DEBUG级别的其它高于DEBUG的 日志,记录到一个文件  -->
    <appender name="ALL_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${log.path}/all.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/all-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档记录除了DEBUG级别的其它高于DEBUG的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUG</level>
            <onMatch>DENY</onMatch>
            <onMismatch>ACCEPT</onMismatch>
        </filter>
    </appender>
    <!--
        <logger>用来设置某一个包或者具体的某一个类的日志打印级别、
        以及指定<appender>。<logger>仅有一个name属性,
        一个可选的level和一个可选的addtivity属性。
        name:用来指定受此logger约束的某一个包或者具体的某一个类。
        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
              还有一个特殊值INHERITED或者同义词NULL,代表强制执行上级的级别。
              如果未设置此属性,那么当前logger将会继承上级的级别。
        addtivity:是否向上级logger传递打印信息。默认是true。
        <logger name="org.springframework.web" level="info"/>
        <logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>
    -->
    <!--
        root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
        不能设置为INHERITED或者同义词NULL。默认是DEBUG
        可以包含零个或多个元素,标识这个appender将会添加到这个logger。
    -->
    <!-- 4  最终的策略:
                 基本策略(root级) + 根据profile在启动时, logger标签中定制化package日志级别(优先级高于上面的root级)-->
    <springProfile name="dev">
        <root level="info">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="DEBUG_FILE" />
            <appender-ref ref="INFO_FILE" />
            <appender-ref ref="WARN_FILE" />
            <appender-ref ref="ERROR_FILE" />
            <appender-ref ref="ALL_FILE" />
        </root>
        <logger name="com.stylefeng.guns.modular.system.dao" level="debug"/>
    </springProfile>
    <springProfile name="test">
        <root level="info">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="DEBUG_FILE" />
            <appender-ref ref="INFO_FILE" />
            <appender-ref ref="WARN_FILE" />
            <appender-ref ref="ERROR_FILE" />
            <appender-ref ref="ALL_FILE" />
        </root>
    </springProfile>
    <springProfile name="prod">
        <root level="info">
            <!-- 生产环境最好不配置console写文件 -->
            <appender-ref ref="DEBUG_FILE" />
            <appender-ref ref="INFO_FILE" />
            <appender-ref ref="WARN_FILE" />
            <appender-ref ref="ERROR_FILE" />
            <appender-ref ref="ALL_FILE" />
        </root>
    </springProfile>
</configuration>
xp-robotaxi-traffic-control-boot/src/main/resources/mybatis-config.xml
New file
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration  PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <!-- 打印查询语句 不会写入到日志文件中-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <!--<setting name="logImpl" value="LOG4J" />-->
        <!-- 控制全局缓存(二级缓存),按美团技术团队的说法,尽量别用缓存机制 emmmm.... -->
        <setting name="cacheEnabled" value="true"/>
        <!-- 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。默认 false  -->
        <!-- <setting name="lazyLoadingEnabled" value="true"/> -->
        <setting name="mapUnderscoreToCamelCase" value="true"/><!--是否将map下划线方式转为驼峰式命名-->
        <!-- 当开启时,任何方法的调用都会加载该对象的所有属性。默认 false,可通过select标签的 fetchType来覆盖-->
        <!-- <setting name="aggressiveLazyLoading" value="false"/>-->
        <!--  Mybatis 创建具有延迟加载能力的对象所用到的代理工具,默认JAVASSIST -->
        <!--<setting name="proxyFactory" value="CGLIB" />-->
        <!-- 关于mybatis的一二级缓存 请参照:https://tech.meituan.com/2018/01/19/mybatis-cache.html -->
        <!-- 一级缓存范围默认:SESSION ,此范围在复杂应用场景中可能会出现脏读数据-->
        <!-- STATEMENT级别的缓存,使一级缓存,只针对当前执行的这一statement有效 -->
        <!--<setting name="localCacheScope" value="STATEMENT"/>-->
        <setting name="localCacheScope" value="STATEMENT"/>
    </settings>
</configuration>
xp-robotaxi-traffic-control-boot/src/main/resources/seata.conf
New file
@@ -0,0 +1,7 @@
# seata.conf
shardingsphere.transaction.seata.at.enable = true
shardingsphere.transaction.seata.tx.timeout = 60
client {
    application.id = "xp-robotaxi-traffic-control-boot"  # 与spring.application.name一致
    transaction.service.group = "seata_tx_group"
}
xp-robotaxi-traffic-control-boot/src/test/java/com/ruoyi/account/RuoYiAccountApplicationTests.java
New file
@@ -0,0 +1,30 @@
//package com.ruoyi.account;
//
//import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
//import com.ruoyi.common.security.service.TokenService;
//import com.ruoyi.system.api.model.LoginUserApplet;
//import org.junit.jupiter.api.Test;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.boot.test.context.SpringBootTest;
//
//import java.util.HashMap;
//import java.util.Map;
//
//@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = RuoYiAccountApplication.class)
//public class RuoYiAccountApplicationTests {
//    @Autowired
//    private TokenService tokenService;
//
//    @Test
//    public void test(){
//        LoginUserApplet loginUserApplet = new LoginUserApplet();
//        loginUserApplet.setUserId(1839480334642704385L);
//        loginUserApplet.setUserIdStr("1839480334642704385");
//        loginUserApplet.setName("158****3127");
//        loginUserApplet.setPhone("15828353127");
//        loginUserApplet.setAvatar("");
//        loginUserApplet.setAddress("");
//        Map<String, Object> tokenInfos = new HashMap<>();
//        System.err.println(tokenService.createTokenApplet(loginUserApplet));
//    }
//}
xp-robotaxi-traffic-control-boot/xp-robotaxi-vehicle-convoy-boot.iml
New file
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
  <component name="AdditionalModuleElements">
    <content url="file://$MODULE_DIR$" dumb="true">
      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
      <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
    </content>
  </component>
</module>