xp-robotaxi-api/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -25,4 +25,5 @@ com.xiaopeng.api.factory.vehicleConvoy.VehicleControlClientFallbackFactory com.xiaopeng.api.factory.automaticPilot.XPUClientFallbackFactory com.xiaopeng.api.factory.automaticPilot.XpuVimClientFallbackFactory com.xiaopeng.api.factory.maintenance.XpCheckLocationClientFallbackFactory com.xiaopeng.api.factory.maintenance.XpCheckLocationClientFallbackFactory com.xiaopeng.api.factory.automaticPilot.OrderMissionClientFallbackFactory xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/constant/CacheConstants.java
@@ -84,6 +84,11 @@ */ public static final String XP_REGION_CITY = "XP_REGION_CITY"; /** * 省市区级联树 */ public static final String XP_REGION_CASCADER = "XP_REGION_CASCADER"; /** * 节假日 xp-robotaxi-map-boot/src/main/resources/bootstrap.yml
@@ -159,137 +159,3 @@ shared-configs: - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} --- spring: shardingsphere: mode: type: Standalone repository: type: File overwrite: true datasource: names: xp0 xp0: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://192.168.110.34:3306/xprt_operation?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 username: root password: 123456 druid: # 连接池初始化时创建的连接数。 # 应根据实际应用场景设置,确保应用程序启动时即可获取数据库连接。 initial-size: 10 # 连接池中最小的空闲连接数,保证即使在低负载时也有足够的连接可用。 min-idle: 10 # 连接池中最大活动连接数,限制并发请求时的数据库连接数,避免过多的连接消耗系统资源。 max-active: 100 # 获取连接时的最大等待时间,超过该时间则抛出异常。单位通常为毫秒。 max-wait: 60000 # 两个连接检查之间的时间间隔,用于检测和清理空闲过久的连接。单位为毫秒。 time-between-eviction-runs-millis: 60000 # 连接在被清理前的最小空闲时间。单位为毫秒。 min-evictable-idle-time-millis: 300000 # 用于验证连接有效性的 SQL 查询语句。 validation-query: SELECT 1 # 如果为真,则连接空闲时会被定期测试有效性。 test-while-idle: true # 如果为真,在获取连接前进行有效性测试。 test-on-borrow: false # 如果为真,在归还连接时进行有效性测试。 test-on-return: false # 是否开启 PreparedStatement 缓存。 pool-prepared-statements: true # 单个连接上缓存的 PreparedStatement 最大数量。 max-pool-prepared-statement-per-connection-size: 20 # 指定要启用的过滤器,如 stat, log4j, wall 等,用于监控和日志记录。 filters: stat,wall,log4j # 连接属性,例如配置日志级别或慢 SQL 阈值。 connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 # 是否自动回收超时连接 remove-abandoned: true # 超时时间,单位秒 remove-abandoned-timeout: 1800 # 是否记录被遗弃的连接 log-abandoned: true # StatViewServlet配置,访问监控页面 stat-view-servlet: enabled: true url-pattern: /druid/* login-username: admin login-password: admin reset-enable: false # 防火墙配置 wall: config: multi-statement-allow: false rules: sharding: tables: sys_oper_log: standard: sharding-column: userId sharding-algorithm-name: sys_oper_log_inline key-generate-strategy: column: oper_id key-generator-name: snowflake xp_agreement_app_user: standard: sharding-column: app_user_id sharding-algorithm-name: xp_agreement_app_user_inline key-generate-strategy: column: id key-generator-name: snowflake xp_point: standard: sharding-column: id sharding-algorithm-name: xp_point_inline key-generate-strategy: column: id key-generator-name: snowflake sharding-algorithms: sys_oper_log_inline: type: INLINE props: algorithm-expression: xp0.sys_oper_log_${userId % 10} xp_agreement_app_user_inline: type: INLINE props: algorithm-expression: xp0.xp_agreement_app_user_${app_user_id % 10} xp_point_inline: type: INLINE props: algorithm-expression: xp0.xp_point_${id % 10} single-table: tables: - xp0.sys_config - xp0.sys_dict_data - xp0.sys_dict_type - xp0.sys_logininfor - xp0.sys_menu - xp0.xp_acticity - xp0.xp_acticity_coupon - xp0.xp_agreement - xp0.xp_banner - xp0.xp_coupon - xp0.xp_electronic_fence - xp0.xp_electronic_fence_area - xp0.xp_feedback_type - xp0.xp_frequently_asked_questions - xp0.xp_invitation_code - xp0.xp_notification - xp0.xp_open_city - xp0.xp_pricing - xp0.xp_pricing_item - xp0.xp_region - xp0.xp_ride_guide - xp0.xp_route_plan - xp0.xp_system_setting - xp0.xp_trading_strategy - xp0.xp_trading_strategy_city - xp0.xp_user_feedback - xp0.xp_whitelist - xp0.xp_whitelist_operlog props: sql-show: true sql-simple: true xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpRegionController.java
@@ -11,6 +11,7 @@ import com.xiaopeng.operation.query.getProvinceQuery; import com.xiaopeng.operation.service.XpOpenCityService; import com.xiaopeng.operation.service.XpRegionService; import com.xiaopeng.operation.vo.RegionCascaderVO; import com.xiaopeng.operation.vo.RegionDistrictSyncResultVO; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -100,6 +101,15 @@ } /** * 管理后台-省市区三级级联查询 */ @ApiOperation(value = "管理后台-省市区三级级联查询", tags = {"管理后台-省市区管理"}) @GetMapping("/api/v1/region/cascader") public R<List<RegionCascaderVO>> getRegionCascader() { return R.ok(regionService.getRegionCascader()); } /** * 管理后台-同步区级数据 */ @ApiOperation(value = "管理后台-同步区级数据", tags = {"管理后台-省市区管理"}) xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/XpRegionService.java
@@ -3,6 +3,7 @@ import com.baomidou.mybatisplus.extension.service.IService; import com.xiaopeng.api.model.operation.XpRegion; import com.xiaopeng.operation.vo.RegionCascaderVO; import com.xiaopeng.operation.vo.RegionDistrictSyncResultVO; import java.util.List; @@ -24,6 +25,12 @@ List<List<XpRegion>> getXpRegion(); /** * 管理后台-省市区三级级联查询 * @return 级联树 */ List<RegionCascaderVO> getRegionCascader(); /** * 从xp_region_all同步区级数据到xp_region * @return 同步结果 */ xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpRegionServiceImpl.java
@@ -3,19 +3,27 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.xiaopeng.api.model.operation.XpOpenCity; import com.xiaopeng.api.model.operation.XpRegion; import com.xiaopeng.common.core.constant.CacheConstants; import com.xiaopeng.common.redis.service.RedisService; import com.xiaopeng.operation.mapper.XpRegionMapper; import com.xiaopeng.api.model.operation.XpRegion; import com.xiaopeng.operation.service.XpOpenCityService; import com.xiaopeng.operation.service.XpRegionService; import com.xiaopeng.operation.vo.RegionCascaderVO; import com.xiaopeng.operation.vo.RegionDistrictSyncResultVO; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; /** @@ -31,6 +39,8 @@ @Resource private RedisService redisService; @Resource private XpOpenCityService openCityService; @Override public List<List<XpRegion>> getXpRegion() { @@ -69,10 +79,116 @@ } @Override public List<RegionCascaderVO> getRegionCascader() { List<Object> cacheList = redisService.getCacheList(CacheConstants.XP_REGION_CASCADER); if (cacheList != null && !cacheList.isEmpty()) { try { return cacheList.stream() .filter(item -> item instanceof RegionCascaderVO) .map(item -> (RegionCascaderVO) item) .collect(Collectors.toList()); } catch (ClassCastException e) { redisService.deleteObject(CacheConstants.XP_REGION_CASCADER); } } List<XpRegion> regionList = this.baseMapper.selectList(Wrappers.lambdaQuery(XpRegion.class)); if (regionList == null || regionList.isEmpty()) { return Collections.emptyList(); } List<XpOpenCity> openCityList = openCityService.list(Wrappers.lambdaQuery(XpOpenCity.class) .eq(XpOpenCity::getStatus, 1)); Set<String> openCityCodeSet = openCityList.stream() .map(XpOpenCity::getCityCode) .filter(StringUtils::isNotBlank) .collect(Collectors.toCollection(HashSet::new)); Set<String> openDistrictCodeSet = openCityList.stream() .map(XpOpenCity::getDistrictCode) .filter(StringUtils::isNotBlank) .collect(Collectors.toCollection(HashSet::new)); Map<Long, List<XpRegion>> childrenMap = regionList.stream() .collect(Collectors.groupingBy(region -> region.getParentId() == null ? 0L : region.getParentId())); List<XpRegion> provinceList = childrenMap.getOrDefault(0L, Collections.emptyList()).stream() .sorted(REGION_COMPARATOR) .collect(Collectors.toList()); List<RegionCascaderVO> result = provinceList.stream() .map(region -> buildRegionNode(region, childrenMap, openCityCodeSet, openDistrictCodeSet)) .collect(Collectors.toList()); redisService.setCacheList(CacheConstants.XP_REGION_CASCADER, result); return result; } private RegionCascaderVO buildRegionNode(XpRegion current, Map<Long, List<XpRegion>> childrenMap, Set<String> openCityCodeSet, Set<String> openDistrictCodeSet) { List<XpRegion> children = childrenMap.getOrDefault(current.getId(), Collections.emptyList()).stream() .sorted(REGION_COMPARATOR) .collect(Collectors.toList()); List<RegionCascaderVO> childNodes = children.stream() .map(child -> buildRegionNode(child, childrenMap, openCityCodeSet, openDistrictCodeSet)) .collect(Collectors.toList()); Integer level = resolveRegionLevel(current.getCode()); Integer selfOpen = resolveSelfOpen(level, current.getCode(), openCityCodeSet, openDistrictCodeSet); boolean hasOpenChild = childNodes.stream().anyMatch(node -> Integer.valueOf(1).equals(node.getIsOpen())); RegionCascaderVO node = new RegionCascaderVO(); node.setCode(current.getCode()); node.setName(current.getName()); node.setLeaf(Integer.valueOf(3).equals(level)); node.setChildren(childNodes); node.setIsOpen(selfOpen == 1 || hasOpenChild ? 1 : 0); return node; } private Integer resolveRegionLevel(String code) { if (StringUtils.isBlank(code) || code.length() < 4) { return 3; } if (code.endsWith("0000")) { return 1; } if (code.endsWith("00")) { return 2; } return 3; } private Integer resolveSelfOpen(Integer level, String code, Set<String> openCityCodeSet, Set<String> openDistrictCodeSet) { if (StringUtils.isBlank(code)) { return 0; } if (Integer.valueOf(2).equals(level)) { return openCityCodeSet.contains(code) ? 1 : 0; } if (Integer.valueOf(3).equals(level)) { return openDistrictCodeSet.contains(code) ? 1 : 0; } return 0; } private static final Comparator<XpRegion> REGION_COMPARATOR = Comparator .comparing((XpRegion region) -> StringUtils.defaultString(region.getInitial())) .thenComparing((XpRegion region) -> StringUtils.defaultString(region.getCode())); @Override @Transactional(rollbackFor = Exception.class) public RegionDistrictSyncResultVO syncDistrictFromRegionAll() { Long cityCount = Objects.requireNonNullElse(this.baseMapper.countCityForDistrictSync(), 0L); Long candidateDistrictCount = Objects.requireNonNullElse(this.baseMapper.countCandidateDistrictForSync(), 0L); Long cityCount = this.baseMapper.countCityForDistrictSync(); if (cityCount == null) { cityCount = 0L; } Long candidateDistrictCount = this.baseMapper.countCandidateDistrictForSync(); if (candidateDistrictCount == null) { candidateDistrictCount = 0L; } List<XpRegion> missingDistrictList = this.baseMapper.selectMissingDistrictFromRegionAll(); long insertedCount = 0L; @@ -83,6 +199,7 @@ redisService.deleteObject(CacheConstants.XP_REGION); redisService.deleteObject(CacheConstants.XP_REGION_CITY); redisService.deleteObject(CacheConstants.XP_REGION_CASCADER); RegionDistrictSyncResultVO result = new RegionDistrictSyncResultVO(); result.setCityCount(cityCount); xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/vo/RegionCascaderVO.java
New file @@ -0,0 +1,33 @@ package com.xiaopeng.operation.vo; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.io.Serializable; import java.util.List; /** * 省市区级联节点 */ @Data @ApiModel(value = "省市区级联节点") public class RegionCascaderVO implements Serializable { private static final long serialVersionUID = 1L; @ApiModelProperty(value = "行政区编码") private String code; @ApiModelProperty(value = "行政区名称") private String name; @ApiModelProperty(value = "是否开通 0否1是") private Integer isOpen; @ApiModelProperty(value = "是否叶子节点") private Boolean leaf; @ApiModelProperty(value = "子节点") private List<RegionCascaderVO> children; } xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/vo/RegionDistrictSyncResultVO.java
New file @@ -0,0 +1,25 @@ package com.xiaopeng.operation.vo; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @Data @ApiModel(value = "区级数据同步结果") public class RegionDistrictSyncResultVO { @ApiModelProperty(value = "参与同步的市级总数") private Long cityCount; @ApiModelProperty(value = "候选区级总数") private Long candidateDistrictCount; @ApiModelProperty(value = "实际新增数量") private Long insertedCount; @ApiModelProperty(value = "跳过数量") private Long skippedCount; @ApiModelProperty(value = "结果信息") private String message; } xp-robotaxi-operation-boot/src/main/resources/mapper/operation/XpRegionMapper.xml
@@ -2,6 +2,42 @@ <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.xiaopeng.operation.mapper.XpRegionMapper"> <select id="selectMissingDistrictFromRegionAll" resultType="com.xiaopeng.api.model.operation.XpRegion"> select district.name as name, district.code as code, district.citycode as cityCode, city.id as parentId, district.english as english, city.initial as initial from xp_region city join xp_region_all all_city on all_city.code = city.code join xp_region_all district on district.parent_id = all_city.id left join xp_region existing on existing.code = district.code where city.parentId != 0 and city.code like '%00' and city.code not like '%0000' and existing.id is null order by city.code, district.code </select> <select id="countCityForDistrictSync" resultType="java.lang.Long"> select count(1) from xp_region city join xp_region_all all_city on all_city.code = city.code where city.parentId != 0 and city.code like '%00' and city.code not like '%0000' </select> <select id="countCandidateDistrictForSync" resultType="java.lang.Long"> select count(1) from xp_region city join xp_region_all all_city on all_city.code = city.code join xp_region_all district on district.parent_id = all_city.id where city.parentId != 0 and city.code like '%00' and city.code not like '%0000' </select> </mapper> xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java
@@ -131,7 +131,6 @@ private final XpPushMessageClient xpPushMessageClient; private final OrderMissionClient orderMissionClient; private final XpOrderDetailMapper xpOrderDetailMapper; private final OrderMissionClient orderMissionClient; @Autowired private MongoTemplate mongoTemplate;