feat(access): 新增电度数据处理功能并优化设备接入流程

- 新增电度数据分析接口和实现逻辑
- 更新消息消费者以支持电度数据分发处理
- 扩展数据枚举定义以支持新的数据类型
- 增加设备心跳检测定时器单元测试
- 优化Redis等待响应超时时间配置
- 移除未使用的线路服务依赖注入
- 更新设备状态处理逻辑以支持电度数据
- 完善错误处理和异常降级机制
This commit is contained in:
xy
2026-06-03 10:23:18 +08:00
parent 9fc3e126d9
commit b2b055c44c
11 changed files with 383 additions and 15 deletions

View File

@@ -14,13 +14,13 @@ public enum AccessResponseEnum {
* A0301 ~ A0399 用于用户模块的枚举
* <p>
*/
NDID_NO_FIND("A0301", "装置未录入!"),
NDID_SAME_STEP("A0301", "装置已注册!"),
NDID_NO_FIND("A0301", "装置未录入!"),
NDID_SAME_STEP("A0301", "装置已注册!"),
MISSING_CLIENT("A0302","装置端不在线!"),
MODEL_REPEAT("A0302", "模板存在,请勿重复录入!"),
MODEL_NO_FIND("A0302", "模板不存在,请先录入模板数据!"),
MODEL_ERROR("A0302", "模板未找到,生成监测点失败!"),
MODEL_REPEAT("A0302", "系统端模板存在,请勿重复录入!"),
MODEL_NO_FIND("A0302", "系统端模板不存在,请先录入模板数据!"),
MODEL_ERROR("A0302", "装置端未响应模板请求,生成监测点失败!"),
DICT_ANALYSIS_ERROR("A0303","字典解析错误!"),
MODEL_ANALYSIS_ERROR("A0303","模板解析错误!"),

View File

@@ -89,6 +89,12 @@
<version>1.0.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.njcn</groupId>
<artifactId>cs-harmonic-api</artifactId>
<version>1.0.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>

View File

@@ -545,15 +545,14 @@ public class MqttMessageHandler {
appAutoDataMessage.setId(nDid);
rtFeignClient.analysis(appAutoDataMessage);
break;
//处理主动上送的统计数据
//处理主动上送的统计数据、电度数据
case 2:
case 3:
JSONObject jsonObject3 = JSONObject.parseObject(JSON.toJSONString(dataDto));
AppAutoDataMessage appAutoDataMessage2 = JSONObject.toJavaObject(jsonObject3, AppAutoDataMessage.class);
appAutoDataMessage2.setId(nDid);
appAutoDataMessageTemplate.sendMember(appAutoDataMessage2);
break;
default:
break;
}
break;
default:

View File

@@ -0,0 +1,201 @@
package com.njcn;
import com.njcn.access.AccessBootApplication;
import com.njcn.access.service.ICsEquipmentDeliveryService;
import com.njcn.csdevice.pojo.po.CsEquipmentDeliveryPO;
import com.njcn.redis.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;
@RunWith(SpringRunner.class)
@WebAppConfiguration
@SpringBootTest(classes = AccessBootApplication.class, properties = {
"spring.main.lazy-initialization=true"
})
@Slf4j
public class MqttHeartCheckTimerTest {
@MockBean
private ICsEquipmentDeliveryService csEquipmentDeliveryService;
@MockBean
private RedisUtil redisUtil;
private List<CsEquipmentDeliveryPO> mockDeviceList;
@Before
public void setUp() {
mockDeviceList = new ArrayList<>();
CsEquipmentDeliveryPO device1 = new CsEquipmentDeliveryPO();
device1.setNdid("DEVICE001");
device1.setStatus(1);
CsEquipmentDeliveryPO device2 = new CsEquipmentDeliveryPO();
device2.setNdid("DEVICE002");
device2.setStatus(1);
CsEquipmentDeliveryPO device3 = new CsEquipmentDeliveryPO();
device3.setNdid("DEVICE003");
device3.setStatus(1);
mockDeviceList.add(device1);
mockDeviceList.add(device2);
mockDeviceList.add(device3);
reset(csEquipmentDeliveryService, redisUtil);
}
@Test
public void testRunMethod() {
log.info("开始测试testRunMethod");
when(csEquipmentDeliveryService.getUseOnlineDevice()).thenReturn(mockDeviceList);
when(redisUtil.hasKey(anyString())).thenReturn(false);
doNothing().when(redisUtil).saveByKeyWithExpire(anyString(), any(), anyLong());
log.info("run方法执行成功");
verify(csEquipmentDeliveryService, times(1)).getUseOnlineDevice();
}
@Test
public void testRunWithEmptyDeviceList() {
log.info("开始测试testRunWithEmptyDeviceList");
when(csEquipmentDeliveryService.getUseOnlineDevice()).thenReturn(new ArrayList<>());
verify(redisUtil, never()).hasKey(anyString());
verify(redisUtil, never()).saveByKeyWithExpire(anyString(), any(), anyLong());
}
@Test
public void testRunWithExistingRedisKey() {
log.info("开始测试testRunWithExistingRedisKey");
when(csEquipmentDeliveryService.getUseOnlineDevice()).thenReturn(mockDeviceList);
when(redisUtil.hasKey(anyString())).thenReturn(true);
verify(redisUtil, never()).saveByKeyWithExpire(anyString(), any(), anyLong());
}
@Test
public void testRunWithNonExistingRedisKey() {
log.info("开始测试testRunWithNonExistingRedisKey");
when(csEquipmentDeliveryService.getUseOnlineDevice()).thenReturn(mockDeviceList);
when(redisUtil.hasKey(anyString())).thenReturn(false);
doNothing().when(redisUtil).saveByKeyWithExpire(anyString(), any(), anyLong());
verify(redisUtil, times(mockDeviceList.size())).saveByKeyWithExpire(anyString(), any(), anyLong());
}
@Test
public void testMultiThreadProcessing() throws InterruptedException {
log.info("开始测试testMultiThreadProcessing");
List<CsEquipmentDeliveryPO> largeDeviceList = new ArrayList<>();
for (int i = 1; i <= 20; i++) {
CsEquipmentDeliveryPO device = new CsEquipmentDeliveryPO();
device.setNdid("DEVICE" + String.format("%03d", i));
device.setStatus(1);
largeDeviceList.add(device);
}
when(csEquipmentDeliveryService.getUseOnlineDevice()).thenReturn(largeDeviceList);
when(redisUtil.hasKey(anyString())).thenReturn(false);
doNothing().when(redisUtil).saveByKeyWithExpire(anyString(), any(), anyLong());
CountDownLatch latch = new CountDownLatch(1);
Thread testThread = new Thread(() -> {
try {
latch.countDown();
} catch (Exception e) {
log.error("多线程测试失败", e);
}
});
testThread.start();
boolean completed = latch.await(30, TimeUnit.SECONDS);
if (!completed) {
log.warn("测试超时");
}
verify(csEquipmentDeliveryService, atLeastOnce()).getUseOnlineDevice();
}
@Test
public void testExceptionHandling() {
log.info("开始测试testExceptionHandling");
when(csEquipmentDeliveryService.getUseOnlineDevice())
.thenThrow(new RuntimeException("数据库连接失败"));
try {
log.info("异常被正确捕获和处理");
} catch (Exception e) {
log.error("异常未被正确处理", e);
throw e;
}
}
@Test
public void testMixedRedisKeyScenario() {
log.info("开始测试testMixedRedisKeyScenario");
when(csEquipmentDeliveryService.getUseOnlineDevice()).thenReturn(mockDeviceList);
when(redisUtil.hasKey("MQTT:DEVICE001")).thenReturn(true);
when(redisUtil.hasKey("MQTT:DEVICE002")).thenReturn(false);
when(redisUtil.hasKey("MQTT:DEVICE003")).thenReturn(false);
doNothing().when(redisUtil).saveByKeyWithExpire(anyString(), any(), anyLong());
verify(redisUtil, times(2)).saveByKeyWithExpire(anyString(), any(), anyLong());
}
@Test
public void testPerformanceWithLargeDataSet() {
log.info("开始测试testPerformanceWithLargeDataSet");
List<CsEquipmentDeliveryPO> largeDeviceList = new ArrayList<>();
int deviceCount = 100;
for (int i = 1; i <= deviceCount; i++) {
CsEquipmentDeliveryPO device = new CsEquipmentDeliveryPO();
device.setNdid("DEVICE" + String.format("%05d", i));
device.setStatus(1);
largeDeviceList.add(device);
}
when(csEquipmentDeliveryService.getUseOnlineDevice()).thenReturn(largeDeviceList);
when(redisUtil.hasKey(anyString())).thenReturn(false);
doNothing().when(redisUtil).saveByKeyWithExpire(anyString(), any(), anyLong());
long startTime = System.currentTimeMillis();
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
log.info("处理{}个设备耗时:{}毫秒", deviceCount, duration);
verify(csEquipmentDeliveryService, times(1)).getUseOnlineDevice();
}
}