Browse Source

手持表上报时自动注册

master
wangwei_123 5 days ago
parent
commit
a11ee1d0cb
  1. 73
      cc-admin-master/yudao-module-hand-mqtt/src/main/java/cn/iocoder/yudao/module/mqtt/processor/BatchDeviceMessageProcessor.java
  2. 2
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/HandDetectorService.java
  3. 3
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/impl/AlarmRuleServiceImpl.java
  4. 8
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/impl/HandDetectorServiceImpl.java
  5. 12
      cc-admin-master/yudao-server/src/main/resources/application-dev.yaml
  6. 2
      cc-admin-master/yudao-server/src/main/resources/application.yaml

73
cc-admin-master/yudao-module-hand-mqtt/src/main/java/cn/iocoder/yudao/module/mqtt/processor/BatchDeviceMessageProcessor.java

@ -54,6 +54,7 @@ public class BatchDeviceMessageProcessor {
private FenceAlarmService fenceAlarmService; private FenceAlarmService fenceAlarmService;
@Resource @Resource
private KafkaTemplate<String, String> kafkaTemplate; private KafkaTemplate<String, String> kafkaTemplate;
private List<ConsumerRecord<String, String>> records;
/** /**
@ -93,6 +94,7 @@ public class BatchDeviceMessageProcessor {
} }
private BatchContext prepareBatchContext(List<ConsumerRecord<String, String>> records) { private BatchContext prepareBatchContext(List<ConsumerRecord<String, String>> records) {
this.records = records;
BatchContext context = new BatchContext(); BatchContext context = new BatchContext();
// 1. 提取所有有效的 SNs // 1. 提取所有有效的 SNs
@ -109,6 +111,76 @@ public class BatchDeviceMessageProcessor {
// 2. 批量获取租户信息 // 2. 批量获取租户信息
context.snToTenantMap = getTenantIdsInBatch(sns); context.snToTenantMap = getTenantIdsInBatch(sns);
// ======================= 新增:处理缺失租户/未注册设备的 SN =======================
List<String> missingSns = sns.stream()
.filter(sn -> !context.snToTenantMap.containsKey(sn))
.toList();
if (CollectionUtils.isNotEmpty(missingSns)) {
// 2.1 查库判断设备是否真的不存在(可能只是 Redis 中丢失了映射)
QueryWrapper<HandDetectorDO> query = new QueryWrapper<>();
query.in("sn", missingSns);
List<HandDetectorDO> dbDetectors = handDetectorService.listAll(query);
Set<String> existingDbSns = new HashSet<>();
for (HandDetectorDO dbDetector : dbDetectors) {
existingDbSns.add(dbDetector.getSn());
if (dbDetector.getTenantId() != null) {
context.snToTenantMap.put(dbDetector.getSn(), Long.valueOf(dbDetector.getTenantId()));
// 顺便回填 Redis,防止下次继续穿透查库
try {
redisUtil.hset(RedisKeyUtil.getDeviceTenantMappingKey(), dbDetector.getSn(), dbDetector.getTenantId());
} catch (Exception e) {
log.warn("[准备数据] 回填 Redis 租户映射失败,SN: {}", dbDetector.getSn(), e);
}
}
}
// 2.2 数据库中确实没有的,直接自动注册,默认租户为 1
List<String> trulyNewSns = missingSns.stream()
.filter(sn -> !existingDbSns.contains(sn))
.toList();
if (CollectionUtils.isNotEmpty(trulyNewSns)) {
List<HandDetectorDO> newDetectors = new ArrayList<>();
LocalDateTime now = LocalDateTime.now();
for (String sn : trulyNewSns) {
HandDetectorDO newDetector = new HandDetectorDO();
newDetector.setSn(sn);
newDetector.setTenantId(1); // 默认租户ID设为 1
newDetector.setName(sn); // 默认使用 SN 作为名称
newDetector.setEnableStatus(EnableStatus.ENABLED.value()); // 默认启用
newDetector.setCreator("system");
newDetector.setCreateTime(now);
newDetector.setGasTypeId(1L);
newDetector.setGasChemical("CO");
newDetectors.add(newDetector);
}
try {
// 保存到数据库。注意: 这里使用 save 单条保存,如果项目中存在 saveBatch(newDetectors) 则推荐替换成批量保存以提升性能。
handDetectorService.saveList(newDetectors);
log.info("[自动注册] 自动保存未知设备 {} 个,默认租户ID为 1", newDetectors.size());
// 将新注册的设备信息回填进上下文并更新 Redis,这样后续步骤就能流畅处理了
for (HandDetectorDO nd : newDetectors) {
context.snToTenantMap.put(nd.getSn(), 1L);
try {
redisUtil.hset(RedisKeyUtil.getDeviceTenantMappingKey(), nd.getSn(), "1");
} catch (Exception e) {
log.warn("[自动注册] 回填 Redis 租户映射失败,SN: {}", nd.getSn(), e);
}
}
} catch (Exception e) {
log.error("[自动注册] 自动注册新设备流程发生异常", e);
}
}
}
// ======================= 新增逻辑结束 =======================
// 3. 按租户分组 SN // 3. 按租户分组 SN
Map<Long, List<String>> tenantToSnsMap = sns.stream() Map<Long, List<String>> tenantToSnsMap = sns.stream()
.filter(context.snToTenantMap::containsKey) .filter(context.snToTenantMap::containsKey)
@ -875,7 +947,6 @@ public class BatchDeviceMessageProcessor {
} }
/** /**
* 批量更新 Redis * 批量更新 Redis
*/ */

2
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/HandDetectorService.java

@ -79,4 +79,6 @@ public interface HandDetectorService {
void batchUpdateRedisData(Long tenantId, Map<String, HandDataVo> deviceMap); void batchUpdateRedisData(Long tenantId, Map<String, HandDataVo> deviceMap);
void saveList(List<HandDetectorDO> newDetectors);
} }

3
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/impl/AlarmRuleServiceImpl.java

@ -47,9 +47,6 @@ import static cn.iocoder.yudao.module.hand.enums.ErrorCodeConstants.ALARM_RULE_N
@Slf4j @Slf4j
public class AlarmRuleServiceImpl implements AlarmRuleService { public class AlarmRuleServiceImpl implements AlarmRuleService {
// 定义一个常量来表示缓存清除的 SpEL 表达式,避免重复和拼写错误
private static final String EVICT_CACHE_KEY_SPEL =
"'gas_rules_map:' + T(cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder).getTenantId()";
@Resource @Resource
private AlarmRuleMapper alarmRuleMapper; private AlarmRuleMapper alarmRuleMapper;
@Resource @Resource

8
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/impl/HandDetectorServiceImpl.java

@ -382,4 +382,12 @@ public class HandDetectorServiceImpl implements HandDetectorService {
} }
} }
@Override
@TenantIgnore
@Transactional(rollbackFor = Exception.class)
public void saveList(List<HandDetectorDO> newDetectors) {
handDetectorMapper.insertBatch(newDetectors);
}
} }

12
cc-admin-master/yudao-server/src/main/resources/application-dev.yaml

@ -114,12 +114,12 @@ spring:
password: rabbit # RabbitMQ 服务的密码 password: rabbit # RabbitMQ 服务的密码
# Kafka 配置项,对应 KafkaProperties 配置类 # Kafka 配置项,对应 KafkaProperties 配置类
kafka: kafka:
bootstrap-servers: 127.0.0.1:9092 # 或者内网地址 172.21.16.6:9091,或者测试地址video.zdhlcn.com:9092,zdmq.zdhlcn.com:9092
# properties:
# security.protocol: SASL_PLAINTEXT
# sasl.mechanism: SCRAM-SHA-512
# sasl.jaas.config: 'org.apache.kafka.common.security.scram.ScramLoginModule required username="zdkafka" password="Zdhl@2025";'
--- #################### 服务保障相关配置 ####################
bootstrap-servers: video.zdhlcn.com:9092 # 或者内网地址 172.21.16.6:9091,或者测试地址video.zdhlcn.com:9092,zdmq.zdhlcn.com:9092
properties:
security.protocol: SASL_PLAINTEXT
sasl.mechanism: SCRAM-SHA-512
sasl.jaas.config: 'org.apache.kafka.common.security.scram.ScramLoginModule required username="zdkafka" password="Zdhl@2025";'
##################### 服务保障相关配置 ####################
# Lock4j 配置项 # Lock4j 配置项
lock4j: lock4j:

2
cc-admin-master/yudao-server/src/main/resources/application.yaml

@ -2,7 +2,7 @@ spring:
application: application:
name: gas_mobile name: gas_mobile
profiles: profiles:
active: local
active: prod
main: main:
allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。 allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。

Loading…
Cancel
Save