bugfix ebike auto register fallback

This commit is contained in:
Guoqs
2026-06-13 10:36:46 +08:00
parent d569f70315
commit d7e8562f42
6 changed files with 564 additions and 46 deletions

View File

@@ -248,7 +248,15 @@ public interface PileBasicInfoService {
* 注册电单车桩
* @param message
*/
void registrationEBikePile(EBikeMessageCmd20 message);
void registrationEBikePile(EBikeMessageCmd20 message);
/**
* 确保电单车桩基础数据已注册
* @param pileSn 桩号
* @param portNumber 端口数量
* @param source 触发来源
*/
void ensureEBikePileRegistered(String pileSn, int portNumber, String source);
List<PileDetailInfoVO> getPileDetailInfoList(String stationId);

View File

@@ -64,6 +64,16 @@ import java.util.stream.Collectors;
@Slf4j
@Service
public class PileBasicInfoServiceImpl implements PileBasicInfoService {
private static final String EBIKE_AUTO_REGISTER_LOCK_KEY = "ebike:auto_register:pile:";
private static final String EBIKE_AUTO_REGISTER_CHECKED_KEY = "ebike:auto_register:checked:";
private static final int EBIKE_AUTO_REGISTER_LOCK_EXPIRE_SECONDS = 30;
private static final int EBIKE_AUTO_REGISTER_CHECKED_EXPIRE_SECONDS = 300;
private static final int EBIKE_AUTO_REGISTER_MAX_PORT_NUMBER = 64;
@Autowired
private PileBasicInfoMapper pileBasicInfoMapper;
@@ -94,6 +104,18 @@ public class PileBasicInfoServiceImpl implements PileBasicInfoService {
@Value("${baseurl.prefix}")
private String BASE_URL_PREFIX;
@Value("${ebike.auto-register.enabled:true}")
private Boolean ebikeAutoRegisterEnabled;
@Value("${ebike.auto-register.merchant-id:1}")
private Long ebikeAutoRegisterMerchantId;
@Value("${ebike.auto-register.station-id:2}")
private Long ebikeAutoRegisterStationId;
@Value("${ebike.auto-register.model-id:0}")
private Long ebikeAutoRegisterModelId;
@Autowired
private PileReservationInfoService pileReservationInfoService;
@@ -1587,53 +1609,144 @@ public class PileBasicInfoServiceImpl implements PileBasicInfoService {
*/
@Override
public void registrationEBikePile(EBikeMessageCmd20 message) {
// 根据物理id(桩编号)查询桩信息
PileBasicInfo pileBasicInfo = this.selectPileBasicInfoBySN(message.getPhysicalId() + "");
if (pileBasicInfo != null) {
ensureEBikePileRegistered(message.getPhysicalId() + "", message.getPortNumber(), "registration_0x20");
}
/**
* 确保电单车桩基础数据已注册。用于注册包和心跳包兜底建档。
*/
@Override
public void ensureEBikePileRegistered(String pileSn, int portNumber, String source) {
if (!Boolean.TRUE.equals(ebikeAutoRegisterEnabled)) {
return;
}
List<PileBasicInfo> basicInfoList = Lists.newArrayList();
List<PileConnectorInfo> connectorInfoList = Lists.newArrayList();
// 组装pile_basic_info表数据
PileBasicInfo basicInfo = new PileBasicInfo();
// 桩编号
String sn = message.getPhysicalId() + "";
basicInfo.setSn(sn);
basicInfo.setBusinessType(Constants.ONE); // 经营类型 1-运营桩2-个人桩
basicInfo.setSoftwareProtocol(Constants.THREE); // 软件协议
basicInfo.setMerchantId(Long.valueOf("1")); // 运营商id 默认1
basicInfo.setStationId(Long.valueOf("2")); // 站点id
basicInfo.setModelId(null); // 型号id
basicInfo.setProductionDate(new Date()); // 生产日期
basicInfo.setLicenceId(null); // TODO 证书编号
basicInfo.setSimId(null); // TODO sim卡
basicInfo.setRemark(null); // 备注
basicInfo.setCreateBy(Constants.SYSTEM); // 创建人
basicInfo.setDelFlag(DelFlagEnum.NORMAL.getValue()); // 删除标识
basicInfoList.add(basicInfo);
int portNumber = message.getPortNumber();
PileConnectorInfo connectorInfo;
for (int i = 1; i < portNumber + 1; i++) {
// 组装pile_connector_info表数据
connectorInfo = new PileConnectorInfo();
connectorInfo.setPileSn(sn); // sn号
String connectorCode = String.format("%1$02d", i);
connectorInfo.setPileConnectorCode(sn + connectorCode); // 枪口号
connectorInfo.setStatus(Constants.ZERO); //状态,默认 0-离网
connectorInfo.setCreateBy(Constants.SYSTEM); // 创建人
connectorInfo.setDelFlag(DelFlagEnum.NORMAL.getValue()); // 删除标识
connectorInfoList.add(connectorInfo);
if (StringUtils.isBlank(pileSn)) {
log.warn("电单车自动建档-跳过, pileSn:{}, reason:桩号为空, source:{}", pileSn, source);
return;
}
if (portNumber <= 0 || portNumber > EBIKE_AUTO_REGISTER_MAX_PORT_NUMBER) {
log.warn("电单车自动建档-跳过, pileSn:{}, portNumber:{}, reason:端口数量异常, source:{}",
pileSn, portNumber, source);
return;
}
// 批量入库
PileTransactionDTO transactionDTO = PileTransactionDTO.builder()
.pileBasicInfoList(basicInfoList)
.pileConnectorInfoList(connectorInfoList)
.build();
pileTransactionService.doCreatePileTransaction(transactionDTO);
}
String checkedKey = EBIKE_AUTO_REGISTER_CHECKED_KEY + pileSn;
String checked = redisCache.getCacheObject(checkedKey);
if (StringUtils.equals(Constants.ONE, checked)) {
return;
}
String lockKey = EBIKE_AUTO_REGISTER_LOCK_KEY + pileSn;
Boolean locked = redisCache.setnx(lockKey, source, EBIKE_AUTO_REGISTER_LOCK_EXPIRE_SECONDS);
if (!Boolean.TRUE.equals(locked)) {
log.debug("电单车自动建档-跳过, pileSn:{}, reason:未获取到锁, source:{}", pileSn, source);
return;
}
try {
checked = redisCache.getCacheObject(checkedKey);
if (StringUtils.equals(Constants.ONE, checked)) {
return;
}
log.info("电单车自动建档-开始, pileSn:{}, portNumber:{}, source:{}", pileSn, portNumber, source);
PileBasicInfo pileBasicInfo = this.selectPileBasicInfoBySN(pileSn);
List<PileConnectorInfo> connectorInfoList = pileConnectorInfoService.selectPileConnectorInfoList(pileSn);
List<PileConnectorInfo> missingConnectorInfoList = buildMissingEBikeConnectorInfoList(pileSn, portNumber, connectorInfoList);
if (pileBasicInfo == null) {
PileBasicInfo basicInfo = buildAutoRegisterEBikeBasicInfo(pileSn, portNumber, source);
PileTransactionDTO transactionDTO = PileTransactionDTO.builder()
.pileBasicInfoList(Lists.newArrayList(basicInfo))
.pileConnectorInfoList(missingConnectorInfoList)
.build();
pileTransactionService.doCreatePileTransaction(transactionDTO);
cleanEBikeAutoRegisterCache(pileSn, basicInfo.getStationId());
log.info("电单车自动建档-创建成功, pileSn:{}, connectorCount:{}, source:{}",
pileSn, missingConnectorInfoList.size(), source);
} else {
if (CollectionUtils.isNotEmpty(missingConnectorInfoList)) {
pileConnectorInfoService.batchInsertConnectorInfo(missingConnectorInfoList);
cleanEBikeAutoRegisterCache(pileSn, pileBasicInfo.getStationId());
log.info("电单车自动建档-补齐端口, pileSn:{}, missingConnectors:{}, source:{}",
pileSn, missingConnectorInfoList.stream().map(PileConnectorInfo::getPileConnectorCode).collect(Collectors.toList()), source);
} else {
log.info("电单车自动建档-已存在, pileSn:{}, portNumber:{}, source:{}", pileSn, portNumber, source);
}
if (CollectionUtils.isNotEmpty(connectorInfoList) && connectorInfoList.size() > portNumber) {
log.warn("电单车自动建档-端口数量变小, pileSn:{}, dbConnectorCount:{}, reportedPortNumber:{}, source:{}",
pileSn, connectorInfoList.size(), portNumber, source);
}
}
redisCache.setCacheObject(checkedKey, Constants.ONE, EBIKE_AUTO_REGISTER_CHECKED_EXPIRE_SECONDS);
} catch (Exception e) {
log.error("电单车自动建档-失败, pileSn:{}, portNumber:{}, source:{}", pileSn, portNumber, source, e);
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
}
throw new RuntimeException(e);
} finally {
redisCache.deleteObject(lockKey);
}
}
private PileBasicInfo buildAutoRegisterEBikeBasicInfo(String pileSn, int portNumber, String source) {
PileBasicInfo basicInfo = new PileBasicInfo();
basicInfo.setSn(pileSn);
basicInfo.setBusinessType(Constants.ONE);
basicInfo.setSoftwareProtocol(Constants.THREE);
basicInfo.setMerchantId(ebikeAutoRegisterMerchantId);
basicInfo.setStationId(ebikeAutoRegisterStationId);
if (ebikeAutoRegisterModelId != null && ebikeAutoRegisterModelId > 0) {
basicInfo.setModelId(ebikeAutoRegisterModelId);
} else {
log.warn("电单车自动建档-modelId未配置或无效, pileSn:{}, configuredModelId:{}, source:{}",
pileSn, ebikeAutoRegisterModelId, source);
}
basicInfo.setProductionDate(new Date());
basicInfo.setCreateBy(Constants.SYSTEM);
basicInfo.setDelFlag(DelFlagEnum.NORMAL.getValue());
basicInfo.setRemark("自动建档:" + source + "; portNumber=" + portNumber);
return basicInfo;
}
private List<PileConnectorInfo> buildMissingEBikeConnectorInfoList(String pileSn, int portNumber, List<PileConnectorInfo> existingConnectorInfoList) {
Set<String> existingConnectorCodeSet = CollectionUtils.isEmpty(existingConnectorInfoList)
? Collections.emptySet()
: existingConnectorInfoList.stream()
.map(PileConnectorInfo::getPileConnectorCode)
.filter(StringUtils::isNotBlank)
.collect(Collectors.toSet());
List<PileConnectorInfo> connectorInfoList = Lists.newArrayList();
for (int i = 1; i < portNumber + 1; i++) {
String connectorCode = String.format("%1$02d", i);
String pileConnectorCode = pileSn + connectorCode;
if (existingConnectorCodeSet.contains(pileConnectorCode)) {
continue;
}
PileConnectorInfo connectorInfo = new PileConnectorInfo();
connectorInfo.setPileSn(pileSn);
connectorInfo.setPileConnectorCode(pileConnectorCode);
connectorInfo.setStatus(Constants.ZERO);
connectorInfo.setCreateBy(Constants.SYSTEM);
connectorInfo.setDelFlag(DelFlagEnum.NORMAL.getValue());
connectorInfoList.add(connectorInfo);
}
return connectorInfoList;
}
private void cleanEBikeAutoRegisterCache(String pileSn, Long stationId) {
List<String> keys = Lists.newArrayList();
keys.add(CacheConstants.SELECT_PILE_BASIC_INFO_BY_SN + pileSn);
keys.add(CacheConstants.SELECT_PILE_CONNECTOR_INFO_LIST + pileSn);
keys.add(CacheConstants.PILE_DETAIL_KEY + pileSn);
if (stationId != null) {
keys.add(CacheConstants.GET_PILE_LIST_BY_STATION_ID + stationId);
}
redisCache.deleteObject(keys);
}
@Override
public java.math.BigDecimal getMonthlyAvgElectricity(String monthStartDate, String monthEndDate) {

View File

@@ -777,6 +777,10 @@ public class PileConnectorInfoServiceImpl implements PileConnectorInfoService {
String pileSn = pileConnectorCode.substring(0, pileConnectorCode.length() - 2);
// 只修改一个枪口的状态
num = pileConnectorInfoMapper.updateConnectorStatus(pileConnectorCode, status);
if (num <= 0) {
log.warn("更新枪口状态-更新结果为0, pileConnectorCode:{}, status:{}, 状态描述:{}",
pileConnectorCode, status, PileConnectorDataBaseStatusEnum.getStatusDescription(status));
}
deleteRedisByPileSnOrPileConnectorCode(pileSn, pileConnectorCode);
redisCache.setCacheObject(redisKey, status, CacheConstants.cache_expire_time_6m);