17 Commits

Author SHA1 Message Date
xy
b32219c1c1 refactor(access): 重构设备接入任务和优化线程管理
- 移除废弃的日志消息相关依赖和代码
- 优化 AccessApplicationRunner 和 AutoAccessTimer 的线程池使用
- 采用共享线程池和信号量控制并发访问设备
- 批量处理设备接入任务并添加批次间隔控制
- 重构 autoAccess2 方法移除事务注解并改用异步处理
- 修复更新线路ID时参数传递错误的问题
- 统一错误处理和异常捕获机制
- 添加更详细的日志记录和错误追踪功能
2026-07-02 19:07:36 +08:00
xy
f1ea5f4b44 fix(realtime): 修复实时数据处理中的Redis缓存和设备注册逻辑
- 移除MqttMessageHandler中重复的Redis缓存保存操作
- 移除RealDataConsumer中冗余的Redis缓存保存逻辑
- 在RtServiceImpl中添加必要的Redis缓存保存以确保设备响应状态同步
- 集成设备注册表查询以正确获取线路ID
- 修复APF实时数据分析中的模块工作状态键名错误
2026-06-29 20:20:34 +08:00
xy
47d58e589b feat(wave): 更新波形分析服务以支持新的线路ID获取逻辑
- 添加 CsDeviceRegistryFeignClient 和 CsLineFeignClient 依赖注入
- 实现通过 nDid 和 clDid 查询设备注册信息的逻辑
- 添加当设备注册信息为空时通过线路查询的备选方案
- 移除旧的线路ID拼接方式并替换为从设备注册表或线路表获取
- 在统计服务中更新云前置设备线路ID获取方式为从Redis缓存获取
2026-06-26 19:11:02 +08:00
xy
f439a4f2c8 fix(device): 修复设备服务中的循环次数和排序设置问题
- 将等待设备上线的循环次数从3次增加到10次
- 为负载侧和电源侧拓扑图参数添加正确的排序值设置
- 移除重复的排序设置逻辑,避免数据冲突
- 确保设备数据集按正确顺序进行初始化配置
2026-06-26 15:22:20 +08:00
xy
14a8a4344a feat(config): 为Nacos配置中心添加认证支持
- 在discovery配置中增加username和password字段
- 在config配置中增加username和password字段
- 更新日志配置URL以包含认证参数
- 注释掉原始无认证的日志配置URL
- 在事件服务中修改幅度值设置逻辑,同时支持VVADEPTH和RMS参数
2026-06-25 15:54:52 +08:00
xy
cf6e07eec1 fix(device): 修复设备注册和容量记录功能
- 修复ledger树排序字段设置,使用正确的设备ID而非固定值0
- 添加设备注册查询逻辑,支持通过NDID和CLDID获取注册信息
- 实现线路ID动态获取机制,避免硬编码导致的数据错误
- 添加空值检查和异常处理,提升系统稳定性
- 优化MQTT消息处理中的设备容量记录流程
2026-06-24 20:34:52 +08:00
xy
723fe45286 fix(mqtt): 修复MQTT消息处理中的设备注册查询逻辑
- 添加了通过逻辑子设备ID获取监测点信息的查询逻辑
- 实现了当设备注册信息为空时的备用查询方案
- 增加了对装置NDID和逻辑子设备ID的校验验证
- 统一了Redis缓存键值的生成方式为使用监测点ID
- 添加了相关业务异常处理以提高系统稳定性
2026-06-24 16:32:07 +08:00
xy
ad1e051a94 feat(access): 优化设备接入流程并增加监测点管理功能
- 新增DEV_DATA_ERROR响应枚举处理装置端监测点信息获取失败情况
- 集成CsLineFeignClient服务实现线路信息精确获取,替代原有字符解析方式
- 删除无用的LogMessageTemplate依赖和objectToMap工具方法
- 添加CsDeviceRegistryFeignClient支持设备注册表管理
- 重构CsDeviceServiceImpl中的设备接入逻辑,优化监测点ID分配机制
- 新增accessByUpdateMac接口支持设备MAC地址变更后的重新接入
- 完善设备监测点信息获取流程,增加数据去重和异常处理机制
- 添加稳态事件指标配置功能,集成谐波方案管理
- 优化MQTT消息处理器中的设备信息更新逻辑
- 增强设备软件信息解析的日期格式兼容性
- 优化设备容量和台账信息更新的数据持久化流程
2026-06-22 13:49:11 +08:00
xy
7ad8f5f80c 微调 2026-06-16 16:20:32 +08:00
xy
17e23fcb78 调整模板存储方式 2026-06-16 16:20:08 +08:00
xy
acec35f6b0 微调 2026-06-15 10:18:51 +08:00
xy
8b95b1902c feat(cache): 优化设备模板缓存策略并添加分布式缓存清理功能
- 引入Caffeine本地缓存替代Redis缓存提高性能
- 添加Redis Pub/Sub机制实现多节点缓存同步清理
- 在CsDeviceServiceImpl中注释掉原有的Redis缓存清理逻辑
- 在CsDevModelServiceImpl中添加缓存清理消息发送功能
- 新增ModelCacheClearListener监听器处理缓存清理通知
- 实现IStatService接口的clearModelCache方法
- 添加getModelData方法实现本地缓存优先的数据获取策略
- 配置最大50000条缓存数据,60分钟过期时间
2026-06-15 10:09:29 +08:00
xy
e4f42ba047 fix(device): 解决装置在线注册时项目验证缺失问题
- 添加了项目存在性检查逻辑
- 当未找到装置绑定的项目时抛出业务异常
- 提供了重新绑定的错误提示信息
2026-06-13 11:34:30 +08:00
xy
9e9fbb360b refactor(access): 优化设备接入流程和日志记录
- 移除不必要的日志模板依赖和相关变量
- 简化设备接入方法中的成功失败ID收集逻辑
- 优化模板信息获取的等待机制,替换固定延时为条件循环
- 更新设备状态查询条件,排除未注册状态的设备
- 重构消息处理器中的日志记录方式,统一操作描述格式
- 修复事务注解在特定方法上的配置问题
- 调整设备接入流程步骤顺序,优化异常处理机制
- 更新MQTT消息处理中的操作日志描述,增加系统端标识
- 优化设备数据询问功能的日志记录完整性
2026-06-12 14:43:39 +08:00
xy
cfd22f3ea8 refactor(access): 优化设备接入服务的日志记录和性能
- 移除旧的字典树Feign客户端依赖,改为从Redis获取字典数据
- 添加ChannelObjectUtil和LogMessageTemplate用于数据转换和日志发送
- 在设备接入过程中增加成功和失败设备ID的统计功能
- 实现批量获取主题版本信息以提高性能
- 重构日志记录方式,统一使用LogMessageTemplate发送日志
- 优化设备注册和接入流程中的日志记录和错误处理
- 移除旧的CsLogsFeignClient相关代码并更新日志DTO结构
2026-06-11 19:54:41 +08:00
xy
1eb2db4f40 refactor(access): 优化设备访问逻辑并移除调试输出
- 移除 AccessApplicationRunner 中的调试打印语句
- 移除 AutoAccessTimer 中的调试打印语句
- 为 CsDevModelServiceImpl 添加非空检查避免空列表操作
- 更新 IDeviceDeliveryService 接口注释说明获取条件为启用且未删除的装置
2026-06-11 15:17:08 +08:00
xy
73fc8805d8 feat(event): 添加事件参数处理和严重度计算功能
- 移除未使用的通知服务依赖注入
- 添加DecimalFormat用于数值格式化
- 新增相别、暂降源、瞬态有效值和电压变化常量定义
- 实现暂降事件严重度计算方法getYzd
- 添加暂降源转换方法getSagSource
- 在事件处理中新增SagSource和Rms字段解析
- 完善暂降事件严重度计算逻辑并修复空指针风险
2026-06-10 10:53:10 +08:00
42 changed files with 2039 additions and 846 deletions

View File

@@ -57,7 +57,7 @@ public enum AccessResponseEnum {
WAVE_INFO_MISSING("A0307","波形参数缺失!"), WAVE_INFO_MISSING("A0307","波形参数缺失!"),
MODEL_MISS("A0308","询问模板信息超时,设备未响应!"), MODEL_MISS("A0308","询问模板信息超时,设备未响应!"),
MODEL_VERSION_ERROR("A0308","询问装置模板信息错误"), MODEL_VERSION_ERROR("A0308","装置模板DevModInfo数据为空"),
UPLOAD_ERROR("A0308","平台上送文件异常"), UPLOAD_ERROR("A0308","平台上送文件异常"),
RELOAD_UPLOAD_ERROR("A0308","平台重新上送文件异常"), RELOAD_UPLOAD_ERROR("A0308","平台重新上送文件异常"),
@@ -75,6 +75,7 @@ public enum AccessResponseEnum {
FILE_CHECK_ERROR("A0312","文件校验码不一致!"), FILE_CHECK_ERROR("A0312","文件校验码不一致!"),
CLD_MODEL_EXIST("A0313","云前置模板已存在,请先删除再录入!"), CLD_MODEL_EXIST("A0313","云前置模板已存在,请先删除再录入!"),
DEV_DATA_ERROR("A0313","系统端询问装置端监测点信息失败,无法生成监测点!"),
/** /**
* A3001 ~ A3099 用于zlevent模块的枚举 * A3001 ~ A3099 用于zlevent模块的枚举

View File

@@ -5,7 +5,8 @@ import com.njcn.redis.utils.RedisUtil;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.*; import java.util.ArrayList;
import java.util.List;
/** /**
* @author xy * @author xy
@@ -51,22 +52,4 @@ public class ChannelObjectUtil {
public Object getDeviceMid(String nDid) { public Object getDeviceMid(String nDid) {
return redisUtil.getObjectByKey(AppRedisKey.DEVICE_MID + nDid); return redisUtil.getObjectByKey(AppRedisKey.DEVICE_MID + nDid);
} }
public Map<String, List<String>> objectToMap(Object obj) {
// 创建并填充 Map
Map<String, List<String>> resultMap = new HashMap<>();
String json = obj.toString();
// 移除首尾的 {}
json = json.substring(1, json.length() - 1);
// 找到键和值的分隔符位置
int keyEndIndex = json.indexOf("=[");
String key = json.substring(0, keyEndIndex);
String valuesStr = json.substring(keyEndIndex + 2, json.length() - 1);
// 将值字符串分割成列表
String[] valuesArray = valuesStr.split(", ");
List<String> valuesList = Arrays.asList(valuesArray);
resultMap.put(key, valuesList);
return resultMap;
}
} }

View File

@@ -0,0 +1,52 @@
package com.njcn.access.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.*;
/**
* MQTT接入任务共享资源池配置
*/
@Configuration
@Slf4j
public class MqttAccessSchedulerConfig {
/**
* 全局MQTT发送并发上限
* 建议设为 MqttConnectOptions.maxInflight 的 50%-70%
*/
@Value("${mqtt.access.concurrency-limit:200}")
private int concurrencyLimit;
@Value("${mqtt.access.worker-threads:5}")
private int workerThreads;
@Bean(destroyMethod = "shutdownNow")
public ScheduledExecutorService sharedScheduler() {
return Executors.newSingleThreadScheduledExecutor(r -> {
Thread t = new Thread(r, "mqtt-access-scheduler");
t.setDaemon(true);
return t;
});
}
@Bean(destroyMethod = "shutdownNow")
public ExecutorService sharedWorkerPool() {
return new ThreadPoolExecutor(
workerThreads, workerThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(200),
r -> new Thread(r, "mqtt-access-worker"),
new ThreadPoolExecutor.CallerRunsPolicy() // 队列满时调用者线程执行,天然背压
);
}
@Bean
public Semaphore mqttSemaphore() {
log.info("初始化MQTT接入信号量, 并发上限={}", concurrencyLimit);
return new Semaphore(concurrencyLimit);
}
}

View File

@@ -159,5 +159,15 @@ public class CsDeviceController extends BaseController {
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe); return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
} }
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
@PostMapping("/accessByUpdateMac")
@ApiOperation("修改mac后手动接入")
@ApiImplicitParam(name = "nDid", value = "设备识别码", required = true)
public HttpResult<String> accessByUpdateMac(@RequestParam("nDid") String nDid){
String methodDescribe = getMethodDescribe("accessByUpdateMac");
String result = csDeviceService.accessByUpdateMac(nDid);
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
}
} }

View File

@@ -17,7 +17,8 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;
import java.util.List;
/** /**
* 类的介绍: * 类的介绍:
@@ -31,7 +32,6 @@ import springfox.documentation.annotations.ApiIgnore;
@RequestMapping("/heartbeat") @RequestMapping("/heartbeat")
@Api(tags = "心跳") @Api(tags = "心跳")
@AllArgsConstructor @AllArgsConstructor
@ApiIgnore
public class CsHeartController extends BaseController { public class CsHeartController extends BaseController {
private final ICsHeartService csHeartService; private final ICsHeartService csHeartService;
@@ -45,4 +45,22 @@ public class CsHeartController extends BaseController {
csHeartService.handleHeartbeat(message); csHeartService.handleHeartbeat(message);
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, null, methodDescribe); return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, null, methodDescribe);
} }
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
@PostMapping("/getMissHeartbeat")
@ApiOperation("获取物联心跳丢失状态在线的设备")
public HttpResult<List<String>> getMissHeartbeat(){
String methodDescribe = getMethodDescribe("getMissHeartbeat");
List<String> result = csHeartService.getMissHeartbeat();
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
}
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
@PostMapping("/updateDevStatus")
@ApiOperation("手动调整状态")
public HttpResult<String> updateDevStatus(){
String methodDescribe = getMethodDescribe("updateDevStatus");
csHeartService.updateDevStatus();
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, null, methodDescribe);
}
} }

View File

@@ -22,9 +22,11 @@ import com.njcn.access.pojo.dto.file.FileRedisDto;
import com.njcn.access.pojo.param.ReqAndResParam; import com.njcn.access.pojo.param.ReqAndResParam;
import com.njcn.access.pojo.po.CsLineModel; import com.njcn.access.pojo.po.CsLineModel;
import com.njcn.access.pojo.po.CsTopic; import com.njcn.access.pojo.po.CsTopic;
import com.njcn.access.service.*; import com.njcn.access.service.ICsEquipmentDeliveryService;
import com.njcn.access.service.ICsLineModelService;
import com.njcn.access.service.ICsTopicService;
import com.njcn.access.service.IHeartbeatService;
import com.njcn.access.utils.ChannelObjectUtil; import com.njcn.access.utils.ChannelObjectUtil;
import com.njcn.common.pojo.dto.DeviceLogDTO;
import com.njcn.common.pojo.exception.BusinessException; import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.csdevice.api.*; import com.njcn.csdevice.api.*;
import com.njcn.csdevice.pojo.dto.PqsCommunicateDto; import com.njcn.csdevice.pojo.dto.PqsCommunicateDto;
@@ -36,10 +38,8 @@ import com.njcn.device.biz.utils.COverlimitUtil;
import com.njcn.mq.message.AppAutoDataMessage; import com.njcn.mq.message.AppAutoDataMessage;
import com.njcn.mq.message.AppEventMessage; import com.njcn.mq.message.AppEventMessage;
import com.njcn.mq.message.AppFileMessage; import com.njcn.mq.message.AppFileMessage;
import com.njcn.mq.template.AppAutoDataMessageTemplate; import com.njcn.mq.message.LogMessage;
import com.njcn.mq.template.AppEventMessageTemplate; import com.njcn.mq.template.*;
import com.njcn.mq.template.AppFileMessageTemplate;
import com.njcn.mq.template.AppFileStreamMessageTemplate;
import com.njcn.redis.pojo.enums.AppRedisKey; import com.njcn.redis.pojo.enums.AppRedisKey;
import com.njcn.redis.utils.RedisUtil; import com.njcn.redis.utils.RedisUtil;
import com.njcn.rt.api.RtFeignClient; import com.njcn.rt.api.RtFeignClient;
@@ -86,10 +86,8 @@ public class MqttMessageHandler {
private final DataSetFeignClient dataSetFeignClient; private final DataSetFeignClient dataSetFeignClient;
private final AppAutoDataMessageTemplate appAutoDataMessageTemplate; private final AppAutoDataMessageTemplate appAutoDataMessageTemplate;
private final AppEventMessageTemplate appEventMessageTemplate; private final AppEventMessageTemplate appEventMessageTemplate;
private final CsLogsFeignClient csLogsFeignClient;
private final AppFileMessageTemplate appFileMessageTemplate; private final AppFileMessageTemplate appFileMessageTemplate;
private final AppFileStreamMessageTemplate appFileStreamMessageTemplate; private final AppFileStreamMessageTemplate appFileStreamMessageTemplate;
private final ICsDeviceOnlineLogsService onlineLogsService;
private final CsSoftInfoFeignClient csSoftInfoFeignClient; private final CsSoftInfoFeignClient csSoftInfoFeignClient;
private final CsLineFeignClient csLineFeignClient; private final CsLineFeignClient csLineFeignClient;
private final DevCapacityFeignClient devCapacityFeignClient; private final DevCapacityFeignClient devCapacityFeignClient;
@@ -100,31 +98,29 @@ public class MqttMessageHandler {
private final RtFeignClient rtFeignClient; private final RtFeignClient rtFeignClient;
private final CsCommunicateFeignClient csCommunicateFeignClient; private final CsCommunicateFeignClient csCommunicateFeignClient;
private final IHeartbeatService heartbeatService; private final IHeartbeatService heartbeatService;
private final LogMessageTemplate logMessageTemplate;
private final CsDeviceRegistryFeignClient csDeviceRegistryFeignClient;
@Autowired @Autowired
Validator validator; Validator validator;
@MqttSubscribe(value = "/Dev/DevTopic/{edgeId}",qos = 1) @MqttSubscribe(value = "/Dev/DevTopic/{edgeId}",qos = 1)
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void devTopic(String topic, MqttMessage message, @NamedValue("edgeId") String nDid, @Payload String payload){ public void devTopic(String topic, MqttMessage message, @NamedValue("edgeId") String nDid, @Payload String payload){
//日志记录
DeviceLogDTO logDto = new DeviceLogDTO();
try{
logDto.setUserName("运维管理员");
logDto.setLoginName("njcnyw");
} catch (Exception e) {
logDto.setUserName("运维管理员");
logDto.setLoginName("njcnyw");
}
logDto.setOperate(nDid + "设备主题录入");
logDto.setResult(1);
//业务流程开始 //业务流程开始
Gson gson = new Gson(); Gson gson = new Gson();
ReqAndResParam.Res res = gson.fromJson(new String(message.getPayload(), StandardCharsets.UTF_8), ReqAndResParam.Res.class); ReqAndResParam.Res res = gson.fromJson(new String(message.getPayload(), StandardCharsets.UTF_8), ReqAndResParam.Res.class);
//日志记录
LogMessage logDto = new LogMessage();
logDto.setUserIndex("系统");
logDto.setLoginName("系统");
logDto.setOperate("系统端收到装置端"+nDid+"发送的主题信息code = " + res.getCode());
logDto.setResult(1);
logMessageTemplate.sendMember(logDto);
//检验传递的参数是否准确 //检验传递的参数是否准确
Set<ConstraintViolation<ReqAndResParam.Res>> validate = validator.validate(res); Set<ConstraintViolation<ReqAndResParam.Res>> validate = validator.validate(res);
validate.forEach(constraintViolation -> { // validate.forEach(constraintViolation -> {
System.out.println(constraintViolation.getMessage()); // System.out.println(constraintViolation.getMessage());
}); // });
if (Objects.equals(res.getCode(),AccessEnum.SUCCESS.getCode())){ if (Objects.equals(res.getCode(),AccessEnum.SUCCESS.getCode())){
if (Objects.equals(res.getType(), Integer.parseInt(TypeEnum.TYPE_16.getCode()))){ if (Objects.equals(res.getType(), Integer.parseInt(TypeEnum.TYPE_16.getCode()))){
List<CsTopic> list = new ArrayList<>(); List<CsTopic> list = new ArrayList<>();
@@ -141,18 +137,20 @@ public class MqttMessageHandler {
list.add(csTopic); list.add(csTopic);
}); });
csTopicService.addTopic(nDid,list); csTopicService.addTopic(nDid,list);
csLogsFeignClient.addUserLog(logDto); String version = list.stream().map(CsTopic::getVersion).filter(Objects::nonNull).findFirst().orElse("V1");
redisUtil.saveByKeyWithExpire(nDid +":version",version,30L);
logMessageTemplate.sendMember(logDto);
} else { } else {
logDto.setResult(0); logDto.setResult(0);
logDto.setFailReason(AccessResponseEnum.MESSAGE_TYPE_ERROR.getMessage()); logDto.setFailReason(AccessResponseEnum.MESSAGE_TYPE_ERROR.getMessage());
csLogsFeignClient.addUserLog(logDto); logMessageTemplate.sendMember(logDto);
log.info(AccessResponseEnum.MESSAGE_TYPE_ERROR.getMessage()); //log.info(AccessResponseEnum.MESSAGE_TYPE_ERROR.getMessage());
} }
} else { } else {
logDto.setResult(0); logDto.setResult(0);
logDto.setFailReason(AccessResponseEnum.RESPONSE_ERROR.getMessage()); logDto.setFailReason(AccessResponseEnum.RESPONSE_ERROR.getMessage());
csLogsFeignClient.addUserLog(logDto); logMessageTemplate.sendMember(logDto);
log.info(AccessResponseEnum.RESPONSE_ERROR.getMessage()); //log.info(AccessResponseEnum.RESPONSE_ERROR.getMessage());
} }
} }
@@ -168,20 +166,16 @@ public class MqttMessageHandler {
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void devOperation(String topic, MqttMessage message, @NamedValue("edgeId") String nDid, @Payload String payload){ public void devOperation(String topic, MqttMessage message, @NamedValue("edgeId") String nDid, @Payload String payload){
log.info("收到注册应答响应--->{}", nDid); log.info("收到注册应答响应--->{}", nDid);
//日志记录
DeviceLogDTO logDto = new DeviceLogDTO();
try{
logDto.setUserName("运维管理员");
logDto.setLoginName("njcnyw");
} catch (Exception e) {
logDto.setUserName("运维管理员");
logDto.setLoginName("njcnyw");
}
logDto.setOperate("收到设备"+nDid+"注册应答响应");
logDto.setResult(1);
//业务处理 //业务处理
Gson gson = new Gson(); Gson gson = new Gson();
ReqAndResDto.Res res = gson.fromJson(new String(message.getPayload(), StandardCharsets.UTF_8), ReqAndResDto.Res.class); ReqAndResDto.Res res = gson.fromJson(new String(message.getPayload(), StandardCharsets.UTF_8), ReqAndResDto.Res.class);
//日志记录
LogMessage logDto = new LogMessage();
logDto.setUserIndex("系统");
logDto.setLoginName("系统");
logDto.setOperate("系统端收到装置端"+nDid+"注册应答响应code = " + res.getCode());
logDto.setResult(1);
logMessageTemplate.sendMember(logDto);
if (Objects.equals(res.getCode(),AccessEnum.SUCCESS.getCode())){ if (Objects.equals(res.getCode(),AccessEnum.SUCCESS.getCode())){
if (Objects.equals(res.getType(),Integer.parseInt(TypeEnum.TYPE_17.getCode()))){ if (Objects.equals(res.getType(),Integer.parseInt(TypeEnum.TYPE_17.getCode()))){
//询问模板数据 //询问模板数据
@@ -193,18 +187,23 @@ public class MqttMessageHandler {
reqAndResParam.setExpire(-1); reqAndResParam.setExpire(-1);
String version = csTopicService.getVersion(nDid); String version = csTopicService.getVersion(nDid);
publisher.send("/Pfm/DevCmd/"+version+"/"+nDid,new Gson().toJson(reqAndResParam),1,false); publisher.send("/Pfm/DevCmd/"+version+"/"+nDid,new Gson().toJson(reqAndResParam),1,false);
csLogsFeignClient.addUserLog(logDto); //记录日志
logDto.setUserIndex("系统");
logDto.setLoginName("系统");
logDto.setOperate("注册阶段:系统端向装置端"+nDid+"发送询问模板请求");
logDto.setResult(1);
logMessageTemplate.sendMember(logDto);
} else { } else {
logDto.setResult(0); logDto.setResult(0);
logDto.setFailReason(AccessResponseEnum.MESSAGE_TYPE_ERROR.getMessage()); logDto.setFailReason(AccessResponseEnum.MESSAGE_TYPE_ERROR.getMessage());
csLogsFeignClient.addUserLog(logDto); logMessageTemplate.sendMember(logDto);
log.info(AccessResponseEnum.MESSAGE_TYPE_ERROR.getMessage()); //log.info(AccessResponseEnum.MESSAGE_TYPE_ERROR.getMessage());
} }
} else { } else {
logDto.setResult(0); logDto.setResult(0);
logDto.setFailReason(AccessResponseEnum.REGISTER_RESPONSE_ERROR.getMessage()); logDto.setFailReason(AccessResponseEnum.REGISTER_RESPONSE_ERROR.getMessage());
csLogsFeignClient.addUserLog(logDto); logMessageTemplate.sendMember(logDto);
log.info(AccessResponseEnum.REGISTER_RESPONSE_ERROR.getMessage()); //log.info(AccessResponseEnum.REGISTER_RESPONSE_ERROR.getMessage());
} }
} }
@@ -218,22 +217,17 @@ public class MqttMessageHandler {
*/ */
@MqttSubscribe(value = "/Pfm/DevRsp/{version}/{edgeId}",qos = 1) @MqttSubscribe(value = "/Pfm/DevRsp/{version}/{edgeId}",qos = 1)
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void devAccessOperation(String topic, MqttMessage message, @NamedValue("version") String version, @NamedValue("edgeId") String nDid, @Payload String payload){ public void devAccessOperation(String topic, MqttMessage message, @NamedValue("version") String version, @NamedValue("edgeId") String nDid, @Payload String payload) throws InterruptedException {
//日志实体 //日志实体
DeviceLogDTO logDto = new DeviceLogDTO(); LogMessage logDto = new LogMessage();
try{ logDto.setUserIndex("系统");
logDto.setUserName("运维管理员"); logDto.setLoginName("系统");
logDto.setLoginName("njcnyw");
} catch (Exception e) {
logDto.setUserName("运维管理员");
logDto.setLoginName("njcnyw");
}
logDto.setResult(1); logDto.setResult(1);
//业务处理 //业务处理
Gson gson = new Gson(); Gson gson = new Gson();
ReqAndResDto.Res res = gson.fromJson(new String(message.getPayload(), StandardCharsets.UTF_8), ReqAndResDto.Res.class); ReqAndResDto.Res res = gson.fromJson(new String(message.getPayload(), StandardCharsets.UTF_8), ReqAndResDto.Res.class);
redisUtil.saveByKeyWithExpire("devResponse",res.getCode(),5L); //redisUtil.saveByKeyWithExpire("devResponse",res.getCode(),5L);
if (Objects.equals(res.getCode(),AccessEnum.SUCCESS.getCode())){ if (Objects.equals(res.getCode(),AccessEnum.SUCCESS.getCode())) {
switch (res.getType()){ switch (res.getType()){
/** /**
* 装置类型模板应答 * 装置类型模板应答
@@ -242,17 +236,21 @@ public class MqttMessageHandler {
* 3.平台端需读取装置的DevMod来判断网关支持的设备模板包含设备型号和模板版本根据app提交的接入子设备DID匹配数据模板型号及版本生成DevCfg下发给网关网关根据下发信息生成就地设备点表。 * 3.平台端需读取装置的DevMod来判断网关支持的设备模板包含设备型号和模板版本根据app提交的接入子设备DID匹配数据模板型号及版本生成DevCfg下发给网关网关根据下发信息生成就地设备点表。
*/ */
case 4611: case 4611:
log.info("{},装置模板应答,应答code {}",nDid,res.getCode()); logDto.setOperate("系统端收到装置端"+nDid+"模板应答code = " + res.getCode());
logMessageTemplate.sendMember(logDto);
//log.info("{},装置模板应答,应答code {}",nDid,res.getCode());
ModelDto modelDto = gson.fromJson(new String(message.getPayload(), StandardCharsets.UTF_8), ModelDto.class); ModelDto modelDto = gson.fromJson(new String(message.getPayload(), StandardCharsets.UTF_8), ModelDto.class);
List<DevModInfoDto> list = modelDto.getMsg().getDevMod(); List<DevModInfoDto> list = modelDto.getMsg().getDevMod();
List<DevCfgDto> list2 = modelDto.getMsg().getDevCfg(); List<DevCfgDto> list2 = modelDto.getMsg().getDevCfg();
if (CollectionUtils.isEmpty(list)){ if (CollectionUtils.isEmpty(list)) {
log.error(AccessResponseEnum.MODEL_VERSION_ERROR.getMessage()); //log.error(AccessResponseEnum.MODEL_VERSION_ERROR.getMessage());
logDto.setOperate("查看装置端模板报文数据");
logDto.setResult(0); logDto.setResult(0);
logDto.setFailReason(AccessResponseEnum.MODEL_VERSION_ERROR.getMessage()); logDto.setFailReason(AccessResponseEnum.MODEL_VERSION_ERROR.getMessage());
csLogsFeignClient.addUserLog(logDto); logMessageTemplate.sendMember(logDto);
//有异常删除缓存的模板信息 //有异常删除缓存的模板信息
redisUtil.delete(AppRedisKey.MODEL + nDid); redisUtil.delete(AppRedisKey.MODEL + nDid);
log.error("{}{}", nDid, AccessResponseEnum.MODEL_VERSION_ERROR.getMessage());
throw new BusinessException(AccessResponseEnum.MODEL_VERSION_ERROR); throw new BusinessException(AccessResponseEnum.MODEL_VERSION_ERROR);
} }
//校验前置传递的装置模板库中是否存在 //校验前置传递的装置模板库中是否存在
@@ -267,11 +265,11 @@ public class MqttMessageHandler {
CsModelDto csModelDto = new CsModelDto(); CsModelDto csModelDto = new CsModelDto();
CsDevModelPO po = devModelFeignClient.findModel(item.getDevType(),item.getVersionNo(),item.getVersionDate()).getData(); CsDevModelPO po = devModelFeignClient.findModel(item.getDevType(),item.getVersionNo(),item.getVersionDate()).getData();
if (Objects.isNull(po)){ if (Objects.isNull(po)){
log.error(AccessResponseEnum.MODEL_NO_FIND.getMessage()); //log.error(AccessResponseEnum.MODEL_NO_FIND.getMessage());
logDto.setOperate(nDid + "模板缺失"); logDto.setOperate(nDid + "查询系统中是否存在模板");
logDto.setResult(0); logDto.setResult(0);
logDto.setFailReason(AccessResponseEnum.MODEL_NO_FIND.getMessage()); logDto.setFailReason(AccessResponseEnum.MODEL_NO_FIND.getMessage());
csLogsFeignClient.addUserLog(logDto); logMessageTemplate.sendMember(logDto);
//有异常删除缓存的模板信息 //有异常删除缓存的模板信息
redisUtil.delete(AppRedisKey.MODEL + nDid); redisUtil.delete(AppRedisKey.MODEL + nDid);
throw new BusinessException(AccessResponseEnum.MODEL_NO_FIND); throw new BusinessException(AccessResponseEnum.MODEL_NO_FIND);
@@ -279,9 +277,10 @@ public class MqttMessageHandler {
if (Objects.equals(po.getType(),0)){ if (Objects.equals(po.getType(),0)){
List<CsDataSet> dataSetList = dataSetFeignClient.getModuleDataSet(po.getId()).getData(); List<CsDataSet> dataSetList = dataSetFeignClient.getModuleDataSet(po.getId()).getData();
if (CollectionUtils.isEmpty(dataSetList)){ if (CollectionUtils.isEmpty(dataSetList)){
logDto.setOperate("查看APF模块个数");
logDto.setResult(0); logDto.setResult(0);
logDto.setFailReason(AccessResponseEnum.MODULE_NUMBER_IS_NULL.getMessage()); logDto.setFailReason(AccessResponseEnum.MODULE_NUMBER_IS_NULL.getMessage());
csLogsFeignClient.addUserLog(logDto); logMessageTemplate.sendMember(logDto);
//有异常删除缓存的模板信息 //有异常删除缓存的模板信息
redisUtil.delete(AppRedisKey.MODEL + nDid); redisUtil.delete(AppRedisKey.MODEL + nDid);
throw new BusinessException(AccessResponseEnum.MODULE_NUMBER_IS_NULL); throw new BusinessException(AccessResponseEnum.MODULE_NUMBER_IS_NULL);
@@ -296,16 +295,19 @@ public class MqttMessageHandler {
}); });
//存储模板id //存储模板id
String key2 = AppRedisKey.MODEL + nDid; String key2 = AppRedisKey.MODEL + nDid;
redisUtil.saveByKeyWithExpire(key2,modelList,600L); redisUtil.saveByKey(key2,modelList);
//存储监测点模板信息,用于界面回显 //存储监测点模板信息,用于界面回显
List<String> modelId = modelList.stream().map(CsModelDto::getModelId).collect(Collectors.toList()); List<String> modelId = modelList.stream().map(CsModelDto::getModelId).collect(Collectors.toList());
List<CsLineModel> lineList = csLineModelService.getMonitorNumByModelId(modelId); List<CsLineModel> lineList = csLineModelService.getMonitorNumByModelId(modelId);
String key = AppRedisKey.LINE + nDid; String key = AppRedisKey.LINE + nDid;
redisUtil.saveByKeyWithExpire(key,lineList,600L); redisUtil.saveByKeyWithExpire(key,lineList,600L);
logMessageTemplate.sendMember(logDto);
break; break;
case 4613: case 4613:
logDto.setOperate(nDid + "设备接入"); logDto.setOperate("系统端收到装置端"+nDid+"接入应答code = " + res.getCode());
log.info("{},收到接入应答响应,应答code {}",nDid,res.getCode()); logDto.setResult(1);
logMessageTemplate.sendMember(logDto);
//log.info("{},收到接入应答响应,应答code {}",nDid,res.getCode());
if (Objects.equals(res.getCode(),AccessEnum.SUCCESS.getCode())){ if (Objects.equals(res.getCode(),AccessEnum.SUCCESS.getCode())){
int mid = 1; int mid = 1;
//修改装置状态 //修改装置状态
@@ -333,20 +335,21 @@ public class MqttMessageHandler {
//录波任务倒计时 //录波任务倒计时
redisUtil.saveByKeyWithExpire("startFile:" + nDid,null,60L); redisUtil.saveByKeyWithExpire("startFile:" + nDid,null,60L);
} else { } else {
log.info(AccessResponseEnum.ACCESS_RESPONSE_ERROR.getMessage()); //log.info(AccessResponseEnum.ACCESS_RESPONSE_ERROR.getMessage());
logDto.setResult(0); logDto.setResult(0);
logDto.setFailReason(AccessResponseEnum.ACCESS_RESPONSE_ERROR.getMessage()); logDto.setFailReason(AccessResponseEnum.ACCESS_RESPONSE_ERROR.getMessage());
csLogsFeignClient.addUserLog(logDto); logMessageTemplate.sendMember(logDto);
throw new BusinessException(AccessResponseEnum.ACCESS_RESPONSE_ERROR); throw new BusinessException(AccessResponseEnum.ACCESS_RESPONSE_ERROR);
} }
csLogsFeignClient.addUserLog(logDto); logMessageTemplate.sendMember(logDto);
break; break;
case 4614: case 4614:
RspDataDto rspDataDto = JSON.parseObject(JSON.toJSONString(res.getMsg()), RspDataDto.class); RspDataDto rspDataDto = JSON.parseObject(JSON.toJSONString(res.getMsg()), RspDataDto.class);
if (!Objects.isNull(rspDataDto.getDataType())) { if (!Objects.isNull(rspDataDto.getDataType())) {
switch (rspDataDto.getDataType()){ switch (rspDataDto.getDataType()){
case 1: case 1:
logDto.setOperate(nDid + "更新设备软件信息"); logDto.setOperate("系统端收到装置端"+nDid+"更新设备软件信息报文code = " + res.getCode());
logDto.setResult(1);
RspDataDto.SoftInfo softInfo = JSON.parseObject(JSON.toJSONString(rspDataDto.getDataArray()), RspDataDto.SoftInfo.class); RspDataDto.SoftInfo softInfo = JSON.parseObject(JSON.toJSONString(rspDataDto.getDataArray()), RspDataDto.SoftInfo.class);
//记录设备软件信息 //记录设备软件信息
CsSoftInfoPO csSoftInfoPo = new CsSoftInfoPO(); CsSoftInfoPO csSoftInfoPo = new CsSoftInfoPO();
@@ -354,11 +357,14 @@ public class MqttMessageHandler {
String id = IdUtil.fastSimpleUUID(); String id = IdUtil.fastSimpleUUID();
csSoftInfoPo.setId(id); csSoftInfoPo.setId(id);
DateTimeFormatter formatter = new DateTimeFormatterBuilder() DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd[[HH][:mm][:ss]]") // 优先尝试紧凑格式
.optionalStart().appendPattern("yyyyMMdd").optionalEnd()
// 再尝试带横线格式
.optionalStart().appendPattern("yyyy-MM-dd").optionalEnd()
// 默认时间部分
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0) .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0) .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0) .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
.parseDefaulting(ChronoField.MILLI_OF_SECOND, 0)
.toFormatter(); .toFormatter();
LocalDateTime localDateTime = LocalDateTime.parse(softInfo.getAppDate(), formatter); LocalDateTime localDateTime = LocalDateTime.parse(softInfo.getAppDate(), formatter);
assertThat(localDateTime).isNotNull(); assertThat(localDateTime).isNotNull();
@@ -371,22 +377,41 @@ public class MqttMessageHandler {
csSoftInfoFeignClient.removeSoftInfo(soft); csSoftInfoFeignClient.removeSoftInfo(soft);
} }
equipmentFeignClient.updateSoftInfo(nDid,csSoftInfoPo.getId()); equipmentFeignClient.updateSoftInfo(nDid,csSoftInfoPo.getId());
logMessageTemplate.sendMember(logDto);
break; break;
case 2: case 2:
List<RspDataDto.LdevInfo> devInfo = JSON.parseArray(JSON.toJSONString(rspDataDto.getDataArray()), RspDataDto.LdevInfo.class); List<RspDataDto.LdevInfo> devInfo = JSON.parseArray(JSON.toJSONString(rspDataDto.getDataArray()), RspDataDto.LdevInfo.class);
if (CollectionUtil.isNotEmpty(devInfo)){ if (CollectionUtil.isNotEmpty(devInfo)){
if (Objects.equals(res.getDid(),1)){ if (Objects.equals(res.getDid(),1)){
redisUtil.saveByKeyWithExpire("lineInfo:"+nDid,devInfo,30L);
List<CsDevCapacityPO> list3 = new ArrayList<>(); List<CsDevCapacityPO> list3 = new ArrayList<>();
boolean hasZeroClDid = devInfo.stream().anyMatch(item -> item.getClDid() == 0); boolean hasZeroClDid = devInfo.stream().anyMatch(item -> item.getClDid() == 0);
//治理设备 //治理设备
if (hasZeroClDid) { if (hasZeroClDid) {
logDto.setOperate("系统端收到装置端"+nDid+"更新APF容量报文code = " + res.getCode());
logDto.setResult(1);
devInfo.forEach(item->{ devInfo.forEach(item->{
if (Objects.equals(item.getClDid(),0)){ if (Objects.equals(item.getClDid(),0)){
updateLineInfo(nDid,item); updateLineInfo(nDid,item);
} }
//2.录入各个模块设备容量 //2.录入各个模块设备容量
CsDeviceRegistry csDeviceRegistry = csDeviceRegistryFeignClient.queryByCurrentNdidAndClDid(nDid, 0).getData();
String lineId;
if (Objects.isNull(csDeviceRegistry)) {
List<CsLinePO> lines = csLineFeignClient.findByNdid(nDid).getData();
if (CollectionUtil.isEmpty(lines)) {
throw new BusinessException("通过装置NDID获取监测点信息失败");
}
CsLinePO line = lines.stream().filter(item2->Objects.equals(item2.getClDid(),0)).findFirst().orElse(null);
if (Objects.isNull(line)) {
throw new BusinessException("通过逻辑子设备ID获取监测点信息失败");
}
lineId = line.getLineId();
} else {
lineId = csDeviceRegistry.getId();
}
CsDevCapacityPO csDevCapacity = new CsDevCapacityPO(); CsDevCapacityPO csDevCapacity = new CsDevCapacityPO();
csDevCapacity.setLineId(nDid.concat("0")); csDevCapacity.setLineId(lineId);
csDevCapacity.setCldid(item.getClDid()); csDevCapacity.setCldid(item.getClDid());
csDevCapacity.setCapacity(Objects.isNull(item.getCapacityA())?0.0:item.getCapacityA()); csDevCapacity.setCapacity(Objects.isNull(item.getCapacityA())?0.0:item.getCapacityA());
list3.add(csDevCapacity); list3.add(csDevCapacity);
@@ -394,6 +419,8 @@ public class MqttMessageHandler {
} }
//其余设备 //其余设备
else { else {
logDto.setOperate("系统端收到装置端"+nDid+"更新监测点台账报文code = " + res.getCode());
logDto.setResult(1);
devInfo.forEach(item->{ devInfo.forEach(item->{
updateLineInfo(nDid,item); updateLineInfo(nDid,item);
}); });
@@ -404,26 +431,47 @@ public class MqttMessageHandler {
equipmentFeignClient.updateModuleNumber(nDid,(devInfo.size()-1)); equipmentFeignClient.updateModuleNumber(nDid,(devInfo.size()-1));
} }
} else if (Objects.equals(res.getDid(),2)) { } else if (Objects.equals(res.getDid(),2)) {
logDto.setOperate(nDid + "更新电网侧、负载侧监测点信息"); logDto.setOperate("系统端收到装置端"+nDid+"更新电网侧、负载侧监测点信息报文code = " + res.getCode());
logDto.setResult(1);
//1.更新电网侧、负载侧监测点相关信息 //1.更新电网侧、负载侧监测点相关信息
devInfo.forEach(item->{ devInfo.forEach(item->{
updateLineInfo(nDid,item); updateLineInfo(nDid,item);
}); });
} }
} }
logMessageTemplate.sendMember(logDto);
break; break;
case 15: case 15:
logDto.setOperate("系统端收到装置端"+nDid+"更新设备软件信息报文code = " + res.getCode());
logDto.setResult(1);
JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(res)); JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(res));
AppAutoDataMessage appAutoDataMessage = JSONObject.toJavaObject(jsonObject, AppAutoDataMessage.class); AppAutoDataMessage appAutoDataMessage = JSONObject.toJavaObject(jsonObject, AppAutoDataMessage.class);
appAutoDataMessage.setId(nDid); appAutoDataMessage.setId(nDid);
rtFeignClient.apfRtAnalysis(appAutoDataMessage); rtFeignClient.apfRtAnalysis(appAutoDataMessage);
logMessageTemplate.sendMember(logDto);
break; break;
case 48: case 48:
logDto.setUserName("运维管理员"); logDto.setOperate("系统端收到装置端"+nDid+"询问项目列表报文code = " + res.getCode());
logDto.setOperate("监测点:" + (nDid + rspDataDto.getClDid()) + "询问项目列表"); logDto.setResult(1);
List<RspDataDto.ProjectInfo> projectInfoList = JSON.parseArray(JSON.toJSONString(rspDataDto.getDataArray()), RspDataDto.ProjectInfo.class); List<RspDataDto.ProjectInfo> projectInfoList = JSON.parseArray(JSON.toJSONString(rspDataDto.getDataArray()), RspDataDto.ProjectInfo.class);
String key3 = AppRedisKey.PROJECT_INFO + nDid + rspDataDto.getClDid(); CsDeviceRegistry csDeviceRegistry = csDeviceRegistryFeignClient.queryByCurrentNdidAndClDid(nDid, rspDataDto.getClDid()).getData();
String lineId;
if (Objects.isNull(csDeviceRegistry)) {
List<CsLinePO> lines = csLineFeignClient.findByNdid(nDid).getData();
if (CollectionUtil.isEmpty(lines)) {
throw new BusinessException("通过装置NDID获取监测点信息失败");
}
CsLinePO line = lines.stream().filter(item->Objects.equals(item.getClDid(),rspDataDto.getClDid())).findFirst().orElse(null);
if (Objects.isNull(line)) {
throw new BusinessException("通过逻辑子设备ID获取监测点信息失败");
}
lineId = line.getLineId();
} else {
lineId = csDeviceRegistry.getId();
}
String key3 = AppRedisKey.PROJECT_INFO + lineId;
redisUtil.saveByKeyWithExpire(key3,projectInfoList,60L); redisUtil.saveByKeyWithExpire(key3,projectInfoList,60L);
logMessageTemplate.sendMember(logDto);
break; break;
default: default:
break; break;
@@ -439,19 +487,40 @@ public class MqttMessageHandler {
default: default:
break; break;
} }
} else if (Objects.equals(res.getCode(),AccessEnum.START_CHANNEL.getCode())) {
logDto.setOperate(AccessEnum.START_CHANNEL.getMessage() + "系统等待5s");
logDto.setResult(1);
logMessageTemplate.sendMember(logDto);
Thread.sleep(5000);
} else { } else {
String result = getEnum(res.getCode()); String result = getEnum(res.getCode());
log.info(result); //log.info(result);
logDto.setOperate("装置响应");
logDto.setResult(0); logDto.setResult(0);
logDto.setFailReason(result); logDto.setFailReason(result);
csLogsFeignClient.addUserLog(logDto); logMessageTemplate.sendMember(logDto);
throw new BusinessException(result); throw new BusinessException(result);
} }
} }
public void updateLineInfo(String nDid,RspDataDto.LdevInfo item) { public void updateLineInfo(String nDid,RspDataDto.LdevInfo item) {
CsDeviceRegistry csDeviceRegistry = csDeviceRegistryFeignClient.queryByCurrentNdidAndClDid(nDid, item.getClDid()).getData();
String lineId;
if (Objects.isNull(csDeviceRegistry)) {
List<CsLinePO> lines = csLineFeignClient.findByNdid(nDid).getData();
if (CollectionUtil.isEmpty(lines)) {
throw new BusinessException("通过装置NDID获取监测点信息失败");
}
CsLinePO line = lines.stream().filter(item2->Objects.equals(item2.getClDid(),item.getClDid())).findFirst().orElse(null);
if (Objects.isNull(line)) {
throw new BusinessException("通过逻辑子设备ID获取监测点信息失败");
}
lineId = line.getLineId();
} else {
lineId = csDeviceRegistry.getId();
}
CsLineParam csLineParam = new CsLineParam(); CsLineParam csLineParam = new CsLineParam();
csLineParam.setLineId(nDid.concat(item.getClDid().toString())); csLineParam.setLineId(lineId);
csLineParam.setVolGrade(item.getVolGrade()); csLineParam.setVolGrade(item.getVolGrade());
csLineParam.setPtRatio(item.getPtRatio()); csLineParam.setPtRatio(item.getPtRatio());
csLineParam.setCtRatio(item.getCtRatio()); csLineParam.setCtRatio(item.getCtRatio());
@@ -460,8 +529,8 @@ public class MqttMessageHandler {
csLineFeignClient.updateLine(csLineParam); csLineFeignClient.updateLine(csLineParam);
//生成监测点限值 //生成监测点限值
Overlimit overlimit = COverlimitUtil.globalAssemble(item.getVolGrade().floatValue(),10f,10f,10f,0,0); Overlimit overlimit = COverlimitUtil.globalAssemble(item.getVolGrade().floatValue(),10f,10f,10f,0,0);
overlimit.setId(nDid.concat(item.getClDid().toString())); overlimit.setId(lineId);
overLimitWlMapper.deleteById(nDid.concat(item.getClDid().toString())); overLimitWlMapper.deleteById(lineId);
overLimitWlMapper.insert(overlimit); overLimitWlMapper.insert(overlimit);
} }
@@ -694,44 +763,57 @@ public class MqttMessageHandler {
* 2模块信息 * 2模块信息
* 3监测点pt/ct信息 * 3监测点pt/ct信息
*/ */
public void askDevData(String nDid,String version,Integer type,Integer mid){ public void askDevData(String nDid,String version,Integer type,Integer mid) {
ReqAndResDto.Req reqAndResParam = new ReqAndResDto.Req(); //获取文件模板信息
reqAndResParam.setMid(mid); List<CsModelDto> modelList = channelObjectUtil.objectToList(redisUtil.getObjectByKey(AppRedisKey.MODEL + nDid),CsModelDto.class);
reqAndResParam.setPri(AccessEnum.FIRST_CHANNEL.getCode()); for (CsModelDto model : modelList) {
reqAndResParam.setType(Integer.parseInt(TypeEnum.TYPE_6.getCode())); LogMessage logDto = new LogMessage();
reqAndResParam.setExpire(-1); logDto.setUserIndex("系统");
AskDataDto askDataDto = new AskDataDto(); logDto.setLoginName("系统");
askDataDto.setDataAttr(0); logDto.setResult(1);
askDataDto.setOperate(1); ReqAndResDto.Req reqAndResParam = new ReqAndResDto.Req();
askDataDto.setStartTime(-1); reqAndResParam.setMid(mid);
askDataDto.setEndTime(-1); reqAndResParam.setPri(AccessEnum.FIRST_CHANNEL.getCode());
switch (type) { reqAndResParam.setType(Integer.parseInt(TypeEnum.TYPE_6.getCode()));
case 1: reqAndResParam.setExpire(-1);
reqAndResParam.setDid(0); AskDataDto askDataDto = new AskDataDto();
askDataDto.setCldid(0); askDataDto.setDataAttr(0);
askDataDto.setDataType(1); askDataDto.setOperate(1);
break; askDataDto.setStartTime(-1);
case 2: askDataDto.setEndTime(-1);
reqAndResParam.setDid(1); switch (type) {
askDataDto.setCldid(-1); case 1:
askDataDto.setDataType(2); reqAndResParam.setDid(model.getDid());
break; askDataDto.setCldid(0);
case 3: askDataDto.setDataType(1);
reqAndResParam.setDid(2); logDto.setOperate("系统端向装置端"+nDid+"询问软件信息");
askDataDto.setCldid(-1); break;
askDataDto.setDataType(2); case 2:
break; reqAndResParam.setDid(model.getDid());
//询问工程信息 askDataDto.setCldid(-1);
case 48: askDataDto.setDataType(2);
reqAndResParam.setDid(1); logDto.setOperate("系统端向装置端"+nDid+"询问逻辑设备1信息");
askDataDto.setCldid(1); break;
askDataDto.setDataType(48); case 3:
break; reqAndResParam.setDid(model.getDid());
default: askDataDto.setCldid(-1);
break; askDataDto.setDataType(2);
logDto.setOperate("系统端向装置端"+nDid+"询问逻辑设备2信息");
break;
//询问工程信息
case 48:
reqAndResParam.setDid(model.getDid());
askDataDto.setCldid(1);
askDataDto.setDataType(48);
logDto.setOperate("系统端向装置端"+nDid+"询问工程信息");
break;
default:
break;
}
reqAndResParam.setMsg(askDataDto);
publisher.send("/Pfm/DevCmd/"+version+"/"+nDid, new Gson().toJson(reqAndResParam),1,false);
logMessageTemplate.sendMember(logDto);
} }
reqAndResParam.setMsg(askDataDto);
publisher.send("/Pfm/DevCmd/"+version+"/"+nDid, new Gson().toJson(reqAndResParam),1,false);
} }
public String getEnum(Integer code) { public String getEnum(Integer code) {

View File

@@ -3,10 +3,7 @@ package com.njcn.access.listener;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.alibaba.nacos.shaded.com.google.gson.Gson; import com.alibaba.nacos.shaded.com.google.gson.Gson;
import com.github.tocrhz.mqtt.publisher.MqttPublisher; import com.github.tocrhz.mqtt.publisher.MqttPublisher;
import com.njcn.access.service.ICsEquipmentDeliveryService;
import com.njcn.access.utils.RedisSetUtil; import com.njcn.access.utils.RedisSetUtil;
import com.njcn.access.utils.SendMessageUtil;
import com.njcn.csdevice.api.*;
import com.njcn.redis.utils.RedisUtil; import com.njcn.redis.utils.RedisUtil;
import com.njcn.rt.pojo.dto.BaseRealDataSet; import com.njcn.rt.pojo.dto.BaseRealDataSet;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -27,27 +24,12 @@ import java.util.Set;
@Slf4j @Slf4j
@Component @Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener { public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
@Resource
private ICsEquipmentDeliveryService csEquipmentDeliveryService;
@Resource
private CsLogsFeignClient csLogsFeignClient;
@Resource
private CsLedgerFeignClient csLedgerFeignclient;
@Resource
private EquipmentFeignClient equipmentFeignClient;
@Resource @Resource
private RedisUtil redisUtil; private RedisUtil redisUtil;
@Resource @Resource
private SendMessageUtil sendMessageUtil;
@Resource
private CsCommunicateFeignClient csCommunicateFeignClient;
@Resource
private MqttPublisher publisher; private MqttPublisher publisher;
@Resource @Resource
private RedisSetUtil redisSetUtil; private RedisSetUtil redisSetUtil;
@Resource
private DeviceMessageFeignClient deviceMessageFeignClient;
public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) { public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer); super(listenerContainer);

View File

@@ -4,111 +4,253 @@ import cn.hutool.core.collection.CollUtil;
import com.njcn.access.service.ICsEquipmentDeliveryService; import com.njcn.access.service.ICsEquipmentDeliveryService;
import com.njcn.access.service.ICsTopicService; import com.njcn.access.service.ICsTopicService;
import com.njcn.access.service.impl.CsDeviceServiceImpl; import com.njcn.access.service.impl.CsDeviceServiceImpl;
import com.njcn.access.utils.ChannelObjectUtil;
import com.njcn.csdevice.pojo.po.CsEquipmentDeliveryPO; import com.njcn.csdevice.pojo.po.CsEquipmentDeliveryPO;
import com.njcn.redis.pojo.enums.AppRedisKey; import com.njcn.redis.pojo.enums.AppRedisKey;
import com.njcn.redis.utils.RedisUtil; import com.njcn.redis.utils.RedisUtil;
import com.njcn.system.api.DictTreeFeignClient;
import com.njcn.system.enums.DicDataEnum; import com.njcn.system.enums.DicDataEnum;
import com.njcn.system.pojo.po.SysDicTreePO;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner; import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.*; import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* 类的介绍:用来重新发起设备的接入,存在程序意外停止了,缓存失效导致无法更新装置的状态,所以需要在程序启动时发起设备的接入
*
* @author xuyang
* @version 1.0.0
* @createTime 2023/8/28 13:57
*/
@Component @Component
@Slf4j @Slf4j
@RequiredArgsConstructor @RequiredArgsConstructor
public class AccessApplicationRunner implements ApplicationRunner { public class AccessApplicationRunner implements ApplicationRunner {
private static final long STARTUP_DELAY = 60L;
private static final int BATCH_SIZE = 20;
private static final long BATCH_INTERVAL_MS = 500L;
private final RedisUtil redisUtil; private final RedisUtil redisUtil;
private final ICsEquipmentDeliveryService csEquipmentDeliveryService; private final ICsEquipmentDeliveryService csEquipmentDeliveryService;
private final ICsTopicService csTopicService; private final ICsTopicService csTopicService;
private final CsDeviceServiceImpl csDeviceService; private final CsDeviceServiceImpl csDeviceService;
private final DictTreeFeignClient dictTreeFeignClient; private final ChannelObjectUtil channelObjectUtil;
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); // ✅ 注入公共资源
private static final long ACCESS_TIME = 60L; private final ScheduledExecutorService sharedScheduler;
private final ExecutorService sharedWorkerPool;
private final Semaphore mqttSemaphore;
@Override @Override
public void run(ApplicationArguments args) { public void run(ApplicationArguments args) {
//项目启动60s后发起自动接入 sharedScheduler.schedule(() -> {
Runnable task = () -> { try {
log.info("系统重启,所有符合条件的装置发起接入!"); executeStartupRecovery();
List<CsEquipmentDeliveryPO> list = csEquipmentDeliveryService.getOnlineDev(); } catch (Throwable t) {
if (CollUtil.isNotEmpty(list)) { log.error("启动恢复任务异常", t);
ExecutorService executor = Executors.newFixedThreadPool(10);
// 将任务平均分配给10个子列表
List<List<CsEquipmentDeliveryPO>> subLists = new ArrayList<>();
int partitionSize = list.size() / 10;
for (int i = 0; i < 10; i++) {
int start = i * partitionSize;
int end = (i == 9) ? list.size() : start + partitionSize;
subLists.add(list.subList(start, end));
}
// 创建一个ExecutorService来处理这些任务
List<Future<Void>> futures = new ArrayList<>();
// 提交任务给线程池执行
for (int i = 0; i < 10; i++) {
int index = i;
futures.add(executor.submit(new Callable<Void>() {
@Override
public Void call() {
accessDev(subLists.get(index));
return null;
}
}));
}
// 等待所有任务完成
for (Future<Void> future : futures) {
try {
future.get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
// 关闭ExecutorService
executor.shutdown();
} }
}; }, STARTUP_DELAY, TimeUnit.SECONDS);
scheduler.schedule(task,ACCESS_TIME,TimeUnit.SECONDS);
scheduler.shutdown(); log.info("启动恢复任务已调度, 延迟={}s", STARTUP_DELAY);
} }
public void accessDev(List<CsEquipmentDeliveryPO> list) { private void executeStartupRecovery() {
if (CollUtil.isNotEmpty(list)) { List<CsEquipmentDeliveryPO> list = csEquipmentDeliveryService.getOnlineDev();
try { if (CollUtil.isEmpty(list)) {
list.forEach(item->{ log.info("启动恢复: 无需恢复的设备");
System.out.println(Thread.currentThread().getName() + ": reboot : nDid : " + item.getNdid()); return;
//判断设备类型 便携式设备需要特殊处理 未注册的要先注册、再接入;已注册的直接重新接入 }
String code = dictTreeFeignClient.queryById(item.getDevType()).getData().getCode(); log.info("启动恢复: 待恢复设备数={}", list.size());
if (Objects.equals(code, DicDataEnum.PORTABLE.getCode()) && Objects.equals(item.getStatus(),1)) {
//csDeviceService.wlDevRegister(item.getNdid()); List<SysDicTreePO> dictTreeKey = channelObjectUtil.objectToList(
log.info("请先手动注册、接入"); redisUtil.getObjectByKey(AppRedisKey.DICT_TREE), SysDicTreePO.class);
} else { Map<String, SysDicTreePO> dictTreeMap = dictTreeKey.stream()
String version = csTopicService.getVersion(item.getNdid()); .collect(Collectors.toMap(SysDicTreePO::getId, item -> item, (a, b) -> a));
if (Objects.isNull(version)) {
version = "V1"; List<String> ndidIds = list.stream().map(CsEquipmentDeliveryPO::getNdid).collect(Collectors.toList());
} Map<String, String> topicVersions = csTopicService.getVersion(ndidIds);
csDeviceService.autoAccess(item.getNdid(),version,1);
} List<List<CsEquipmentDeliveryPO>> batches = CollUtil.split(list, BATCH_SIZE);
redisUtil.saveByKey(AppRedisKey.DEVICE_MID + item.getNdid(),1);
}); int batchCount = 0;
} catch (Exception e) { for (List<CsEquipmentDeliveryPO> batch : batches) {
log.error(e.getMessage()); sharedWorkerPool.submit(() -> accessDevSafely(batch, dictTreeMap, topicVersions));
// 非最后一批时等待
if (++batchCount < batches.size()) {
try {
Thread.sleep(BATCH_INTERVAL_MS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.warn("批次间隔被中断,停止后续调度");
return;
}
} }
} }
} }
private void accessDevSafely(List<CsEquipmentDeliveryPO> list,
Map<String, SysDicTreePO> dictTreeMap,
Map<String, String> topicVersions) {
for (CsEquipmentDeliveryPO item : list) {
try {
SysDicTreePO dicItem = dictTreeMap.get(item.getDevType());
if (dicItem != null
&& Objects.equals(dicItem.getCode(), DicDataEnum.PORTABLE.getCode())
&& Objects.equals(item.getStatus(), 1)) {
log.debug("设备 {} 需手动注册接入,跳过", item.getNdid());
continue;
}
String version = topicVersions.getOrDefault(item.getNdid(), "V1");
mqttSemaphore.acquire();
try {
boolean result = csDeviceService.autoAccess(item.getNdid(), version, 1);
if (result) {
redisUtil.saveByKey(AppRedisKey.DEVICE_MID + item.getNdid(), 1);
}
} finally {
mqttSemaphore.release();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.warn("启动恢复: 设备 {} 处理被中断", item.getNdid());
return;
} catch (Exception e) {
log.error("启动恢复: 设备 {} 接入异常: {}", item.getNdid(), e.getMessage());
}
}
}
} }
//package com.njcn.access.runner;
//
//import cn.hutool.core.collection.CollUtil;
//import com.njcn.access.service.ICsEquipmentDeliveryService;
//import com.njcn.access.service.ICsTopicService;
//import com.njcn.access.service.impl.CsDeviceServiceImpl;
//import com.njcn.access.utils.ChannelObjectUtil;
//import com.njcn.csdevice.pojo.po.CsEquipmentDeliveryPO;
//import com.njcn.mq.message.LogMessage;
//import com.njcn.mq.template.LogMessageTemplate;
//import com.njcn.redis.pojo.enums.AppRedisKey;
//import com.njcn.redis.utils.RedisUtil;
//import com.njcn.system.enums.DicDataEnum;
//import com.njcn.system.pojo.po.SysDicTreePO;
//import lombok.RequiredArgsConstructor;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.boot.ApplicationArguments;
//import org.springframework.boot.ApplicationRunner;
//import org.springframework.stereotype.Component;
//
//import java.util.ArrayList;
//import java.util.List;
//import java.util.Map;
//import java.util.Objects;
//import java.util.concurrent.*;
//import java.util.stream.Collectors;
//
///**
// * 类的介绍:用来重新发起设备的接入,存在程序意外停止了,缓存失效导致无法更新装置的状态,所以需要在程序启动时发起设备的接入
// *
// * @author xuyang
// * @version 1.0.0
// * @createTime 2023/8/28 13:57
// */
//@Component
//@Slf4j
//@RequiredArgsConstructor
//public class AccessApplicationRunner implements ApplicationRunner {
//
// private final RedisUtil redisUtil;
// private final ICsEquipmentDeliveryService csEquipmentDeliveryService;
// private final ICsTopicService csTopicService;
// private final CsDeviceServiceImpl csDeviceService;
// private final ChannelObjectUtil channelObjectUtil;
//
// ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
// private static final long ACCESS_TIME = 60L;
//
// @Override
// public void run(ApplicationArguments args) {
// //项目启动60s后发起自动接入
// Runnable task = () -> {
// log.info("系统重启,所有符合条件的装置发起接入!");
// List<CsEquipmentDeliveryPO> list = csEquipmentDeliveryService.getOnlineDev();
// if (CollUtil.isNotEmpty(list)) {
// //获取字典数据
// List<SysDicTreePO> dictTreeKey = channelObjectUtil.objectToList(redisUtil.getObjectByKey(AppRedisKey.DICT_TREE), SysDicTreePO.class);
// Map<String, SysDicTreePO> dictTreeMap = dictTreeKey.stream().collect(Collectors.toMap(SysDicTreePO::getId, item -> item));
// //获取主题版本信息
// List<String> nDidIds = list.stream().map(CsEquipmentDeliveryPO::getNdid).collect(Collectors.toList());
// Map<String,String> topicVersions = csTopicService.getVersion(nDidIds);
//
// ExecutorService executor = Executors.newFixedThreadPool(10);
// // 将任务平均分配给10个子列表
// List<List<CsEquipmentDeliveryPO>> subLists = new ArrayList<>();
// int partitionSize = list.size() / 10;
// for (int i = 0; i < 10; i++) {
// int start = i * partitionSize;
// int end = (i == 9) ? list.size() : start + partitionSize;
// subLists.add(list.subList(start, end));
// }
// // 创建一个ExecutorService来处理这些任务
// List<Future<Void>> futures = new ArrayList<>();
// // 提交任务给线程池执行
// for (int i = 0; i < 10; i++) {
// int index = i;
// futures.add(executor.submit(new Callable<Void>() {
// @Override
// public Void call() {
// accessDev(subLists.get(index), dictTreeMap, topicVersions);
// return null;
// }
// }));
// }
// // 等待所有任务完成
// for (Future<Void> future : futures) {
// try {
// future.get();
// } catch (InterruptedException | ExecutionException e) {
// throw new RuntimeException(e);
// }
// }
// // 关闭ExecutorService
// executor.shutdown();
// }
// };
// scheduler.schedule(task,ACCESS_TIME,TimeUnit.SECONDS);
// scheduler.shutdown();
// }
//
// public void accessDev(List<CsEquipmentDeliveryPO> list, Map<String, SysDicTreePO> dictTreeMap, Map<String,String> topicVersions) {
// if (CollUtil.isNotEmpty(list)) {
// try {
// list.forEach(item->{
// //System.out.println(Thread.currentThread().getName() + ": reboot : nDid : " + item.getNdid());
// //判断设备类型 便携式设备需要特殊处理 未注册的要先注册、再接入;已注册的直接重新接入
// if (Objects.equals(dictTreeMap.get(item.getDevType()).getCode(), DicDataEnum.PORTABLE.getCode()) && Objects.equals(item.getStatus(),1)) {
// //csDeviceService.wlDevRegister(item.getNdid());
// log.info("请先手动注册、接入");
// } else {
// String version = topicVersions.get(item.getNdid());
// if (Objects.isNull(version)) {
// version = "V1";
// }
// boolean result = csDeviceService.autoAccess(item.getNdid(),version,1);
// if (result) {
// redisUtil.saveByKey(AppRedisKey.DEVICE_MID + item.getNdid(), 1);
// }
// }
// });
// } catch (Exception e) {
// log.error(e.getMessage());
// }
// }
// }
//
//}

View File

@@ -4,161 +4,292 @@ import cn.hutool.core.collection.CollUtil;
import com.njcn.access.service.ICsEquipmentDeliveryService; import com.njcn.access.service.ICsEquipmentDeliveryService;
import com.njcn.access.service.ICsTopicService; import com.njcn.access.service.ICsTopicService;
import com.njcn.access.service.impl.CsDeviceServiceImpl; import com.njcn.access.service.impl.CsDeviceServiceImpl;
import com.njcn.access.utils.ChannelObjectUtil;
import com.njcn.csdevice.pojo.po.CsEquipmentDeliveryPO; import com.njcn.csdevice.pojo.po.CsEquipmentDeliveryPO;
import com.njcn.redis.pojo.enums.AppRedisKey; import com.njcn.redis.pojo.enums.AppRedisKey;
import com.njcn.redis.utils.RedisUtil; import com.njcn.redis.utils.RedisUtil;
import com.njcn.system.api.DictTreeFeignClient;
import com.njcn.system.enums.DicDataEnum; import com.njcn.system.enums.DicDataEnum;
import com.njcn.system.pojo.po.SysDicTreePO;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner; import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.*; import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* @author xy
* 定时轮询离线设备接入
*/
@Component @Component
@Slf4j @Slf4j
@RequiredArgsConstructor @RequiredArgsConstructor
public class AutoAccessTimer implements ApplicationRunner { public class AutoAccessTimer implements ApplicationRunner {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private static final long AUTO_TIME = 120L; private static final long AUTO_TIME = 120L;
private static final int BATCH_SIZE = 20;
private static final long BATCH_INTERVAL_MS = 500L;
private final RedisUtil redisUtil; private final RedisUtil redisUtil;
private final ICsEquipmentDeliveryService csEquipmentDeliveryService; private final ICsEquipmentDeliveryService csEquipmentDeliveryService;
private final ICsTopicService csTopicService; private final ICsTopicService csTopicService;
private final CsDeviceServiceImpl csDeviceService; private final CsDeviceServiceImpl csDeviceService;
private final DictTreeFeignClient dictTreeFeignClient; private final ChannelObjectUtil channelObjectUtil;
// ✅ 注入公共资源
private final ScheduledExecutorService sharedScheduler;
private final ExecutorService sharedWorkerPool;
private final Semaphore mqttSemaphore;
@Override @Override
public void run(ApplicationArguments args) { public void run(ApplicationArguments args) {
if (scheduler.isShutdown() || scheduler.isTerminated()) { sharedScheduler.scheduleWithFixedDelay(() -> {
scheduler = Executors.newScheduledThreadPool(1);
}
Runnable task = () -> {
try { try {
executeScheduledTask(); executeScheduledTask();
} catch (Throwable t) {
log.error("定时轮询任务异常", t);
} }
// 捕获所有Throwable包括Error }, AUTO_TIME, AUTO_TIME, TimeUnit.SECONDS);
catch (Throwable t) {
log.error("定时任务发生严重异常,尝试恢复", t);
// 可以添加重启逻辑或告警
}
};
ScheduledFuture<?> future = scheduler.scheduleWithFixedDelay(task, AUTO_TIME, AUTO_TIME, TimeUnit.SECONDS);
// 添加监控,如果任务被取消则重新调度
monitorScheduledTask(future);
}
//10分钟检查一下调度任务 log.info("自动接入定时任务已启动, 周期={}s", AUTO_TIME);
private void monitorScheduledTask(ScheduledFuture<?> future) {
Thread monitorThread = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
try {
//每10分钟检查一次
Thread.sleep(600000);
if (future.isCancelled() || future.isDone()) {
log.warn("定时任务被取消或完成,重新调度...");
// 重新启动任务
run(null);
break;
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.warn("监控线程被中断");
break;
} catch (Exception e) {
log.error("监控任务异常", e);
}
}
}, "Schedule-Monitor-Thread");
monitorThread.setDaemon(true);
monitorThread.start();
} }
private void executeScheduledTask() { private void executeScheduledTask() {
log.info("轮询定时任务执行中!");
List<CsEquipmentDeliveryPO> list = csEquipmentDeliveryService.getOfflineDev(); List<CsEquipmentDeliveryPO> list = csEquipmentDeliveryService.getOfflineDev();
if (CollUtil.isNotEmpty(list)) { if (CollUtil.isEmpty(list)) {
ExecutorService executor = Executors.newFixedThreadPool(10); return;
try { }
List<List<CsEquipmentDeliveryPO>> subLists = CollUtil.split(list, 10); log.info("轮询定时任务执行中, 待处理设备数={}", list.size());
List<Future<Void>> futures = new ArrayList<>();
for (List<CsEquipmentDeliveryPO> subList : subLists) { List<SysDicTreePO> dictTreeKey = channelObjectUtil.objectToList(
futures.add(executor.submit(() -> { redisUtil.getObjectByKey(AppRedisKey.DICT_TREE), SysDicTreePO.class);
try { Map<String, SysDicTreePO> dictTreeMap = dictTreeKey.stream()
accessDevSafely(subList); // 使用安全版本 .collect(Collectors.toMap(SysDicTreePO::getId, item -> item, (a, b) -> a));
} catch (Exception e) {
log.error("处理设备子列表异常", e); List<String> ndidIds = list.stream().map(CsEquipmentDeliveryPO::getNdid).collect(Collectors.toList());
} Map<String, String> topicVersions = csTopicService.getVersion(ndidIds);
return null;
})); List<List<CsEquipmentDeliveryPO>> batches = CollUtil.split(list, BATCH_SIZE);
}
for (Future<Void> future : futures) { int batchCount = 0;
try { for (List<CsEquipmentDeliveryPO> batch : batches) {
future.get(5, TimeUnit.MINUTES); sharedWorkerPool.submit(() -> accessDevSafely(batch, dictTreeMap, topicVersions));
} catch (TimeoutException e) {
log.error("任务执行超时", e); // 非最后一批时等待
} catch (Exception e) { if (++batchCount < batches.size()) {
log.error("任务执行异常", e);
}
}
} finally {
executor.shutdown();
try { try {
if (!executor.awaitTermination(1, TimeUnit.MINUTES)) { Thread.sleep(BATCH_INTERVAL_MS);
executor.shutdownNow();
}
} catch (InterruptedException e) { } catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
log.warn("批次间隔被中断,停止后续调度");
return;
} }
} }
} }
} }
//安全的accessDev版本 private void accessDevSafely(List<CsEquipmentDeliveryPO> list,
private void accessDevSafely(List<CsEquipmentDeliveryPO> list) { Map<String, SysDicTreePO> dictTreeMap,
if (CollUtil.isNotEmpty(list)) { Map<String, String> topicVersions) {
for (CsEquipmentDeliveryPO item : list) { for (CsEquipmentDeliveryPO item : list) {
try {
processSingleDevice(item);
} catch (Exception e) {
log.error("处理设备 {} 失败: {}", item.getNdid(), e.getMessage());
}
}
}
}
private void processSingleDevice(CsEquipmentDeliveryPO item) {
System.out.println(Thread.currentThread().getName() + ": auto : nDid : " + item.getNdid());
String code = dictTreeFeignClient.queryById(item.getDevType()).getData().getCode();
if (Objects.equals(code, DicDataEnum.PORTABLE.getCode()) && Objects.equals(item.getStatus(), 1)) {
log.info("设备 {} 需要手动注册、接入", item.getNdid());
} else {
String version = csTopicService.getVersion(item.getNdid());
if (Objects.isNull(version)) {
version = "V1";
}
// 使用try-catch确保单个设备失败不影响其他设备
try { try {
boolean success = csDeviceService.autoAccess2(item.getNdid(), version, 1); SysDicTreePO dicItem = dictTreeMap.get(item.getDevType());
if (success) { if (dicItem != null
redisUtil.saveByKey(AppRedisKey.DEVICE_MID + item.getNdid(), 1); && Objects.equals(dicItem.getCode(), DicDataEnum.PORTABLE.getCode())
} else { && Objects.equals(item.getStatus(), 1)) {
log.warn("设备 {} 接入失败", item.getNdid()); log.debug("设备 {} 需手动注册接入,跳过", item.getNdid());
continue;
} }
String version = topicVersions.getOrDefault(item.getNdid(), "V1");
mqttSemaphore.acquire();
try {
boolean success = csDeviceService.autoAccess2(item.getNdid(), version, 1);
if (success) {
redisUtil.saveByKey(AppRedisKey.DEVICE_MID + item.getNdid(), 1);
}
} finally {
mqttSemaphore.release();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.warn("设备 {} 处理被中断", item.getNdid());
return;
} catch (Exception e) { } catch (Exception e) {
log.error("设备 {} 接入异常: {}", item.getNdid(), e.getMessage()); log.error("设备 {} 接入异常: {}", item.getNdid(), e.getMessage());
} }
} }
} }
} }
//package com.njcn.access.runner;
//
//import cn.hutool.core.collection.CollUtil;
//import com.njcn.access.service.ICsEquipmentDeliveryService;
//import com.njcn.access.service.ICsTopicService;
//import com.njcn.access.service.impl.CsDeviceServiceImpl;
//import com.njcn.access.utils.ChannelObjectUtil;
//import com.njcn.csdevice.pojo.po.CsEquipmentDeliveryPO;
//import com.njcn.redis.pojo.enums.AppRedisKey;
//import com.njcn.redis.utils.RedisUtil;
//import com.njcn.system.enums.DicDataEnum;
//import com.njcn.system.pojo.po.SysDicTreePO;
//import lombok.RequiredArgsConstructor;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.boot.ApplicationArguments;
//import org.springframework.boot.ApplicationRunner;
//import org.springframework.stereotype.Component;
//
//import java.util.ArrayList;
//import java.util.List;
//import java.util.Map;
//import java.util.Objects;
//import java.util.concurrent.*;
// import java.util.stream.Collectors;
//
///**
// * @author xy
// * 定时轮询离线设备接入
// */
//@Component
//@Slf4j
//@RequiredArgsConstructor
//public class AutoAccessTimer implements ApplicationRunner {
// ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
// private static final long AUTO_TIME = 120L;
// private final RedisUtil redisUtil;
// private final ICsEquipmentDeliveryService csEquipmentDeliveryService;
// private final ICsTopicService csTopicService;
// private final CsDeviceServiceImpl csDeviceService;
// private final ChannelObjectUtil channelObjectUtil;
//
// @Override
// public void run(ApplicationArguments args) {
// if (scheduler.isShutdown() || scheduler.isTerminated()) {
// scheduler = Executors.newScheduledThreadPool(1);
// }
// Runnable task = () -> {
// try {
// executeScheduledTask();
// }
// // 捕获所有Throwable包括Error
// catch (Throwable t) {
// log.error("定时任务发生严重异常,尝试恢复", t);
// // 可以添加重启逻辑或告警
// }
// };
// ScheduledFuture<?> future = scheduler.scheduleWithFixedDelay(task, AUTO_TIME, AUTO_TIME, TimeUnit.SECONDS);
// // 添加监控,如果任务被取消则重新调度
// monitorScheduledTask(future);
// }
//
// //10分钟检查一下调度任务
// private void monitorScheduledTask(ScheduledFuture<?> future) {
// Thread monitorThread = new Thread(() -> {
// while (!Thread.currentThread().isInterrupted()) {
// try {
// //每10分钟检查一次
// Thread.sleep(600000);
// if (future.isCancelled() || future.isDone()) {
// log.warn("定时任务被取消或完成,重新调度...");
// // 重新启动任务
// run(null);
// break;
// }
// } catch (InterruptedException e) {
// Thread.currentThread().interrupt();
// log.warn("监控线程被中断");
// break;
// } catch (Exception e) {
// log.error("监控任务异常", e);
// }
// }
// }, "Schedule-Monitor-Thread");
//
// monitorThread.setDaemon(true);
// monitorThread.start();
// }
//
// private void executeScheduledTask() {
// log.info("轮询定时任务执行中!");
// List<CsEquipmentDeliveryPO> list = csEquipmentDeliveryService.getOfflineDev();
// if (CollUtil.isNotEmpty(list)) {
// //获取字典数据
// List<SysDicTreePO> dictTreeKey = channelObjectUtil.objectToList(redisUtil.getObjectByKey(AppRedisKey.DICT_TREE), SysDicTreePO.class);
// Map<String, SysDicTreePO> dictTreeMap = dictTreeKey.stream().collect(Collectors.toMap(SysDicTreePO::getId, item -> item));
// //获取主题版本信息
// List<String> nDidIds = list.stream().map(CsEquipmentDeliveryPO::getNdid).collect(Collectors.toList());
// Map<String,String> topicVersions = csTopicService.getVersion(nDidIds);
//
// ExecutorService executor = Executors.newFixedThreadPool(10);
// try {
// List<List<CsEquipmentDeliveryPO>> subLists = CollUtil.split(list, 10);
// List<Future<Void>> futures = new ArrayList<>();
// for (List<CsEquipmentDeliveryPO> subList : subLists) {
// futures.add(executor.submit(() -> {
// try {
// accessDevSafely(subList,dictTreeMap,topicVersions);
// } catch (Exception e) {
// log.error("处理设备子列表异常", e);
// }
// return null;
// }));
// }
// for (Future<Void> future : futures) {
// try {
// future.get(5, TimeUnit.MINUTES);
// } catch (TimeoutException e) {
// log.error("任务执行超时", e);
// } catch (Exception e) {
// log.error("任务执行异常", e);
// }
// }
// } finally {
// executor.shutdown();
// try {
// if (!executor.awaitTermination(1, TimeUnit.MINUTES)) {
// executor.shutdownNow();
// }
// } catch (InterruptedException e) {
// executor.shutdownNow();
// Thread.currentThread().interrupt();
// }
// }
// }
// }
//
// //安全的accessDev版本
// private void accessDevSafely(List<CsEquipmentDeliveryPO> list, Map<String, SysDicTreePO> dictTreeMap, Map<String,String> topicVersions) {
// if (CollUtil.isNotEmpty(list)) {
// for (CsEquipmentDeliveryPO item : list) {
// try {
// if (Objects.equals(dictTreeMap.get(item.getDevType()).getCode(), DicDataEnum.PORTABLE.getCode()) && Objects.equals(item.getStatus(), 1)) {
// log.info("设备 {} 需要手动注册、接入", item.getNdid());
// } else {
// String version = topicVersions.get(item.getNdid());
// if (Objects.isNull(version)) {
// version = "V1";
// }
// // 使用try-catch确保单个设备失败不影响其他设备
// try {
// boolean success = csDeviceService.autoAccess2(item.getNdid(), version, 1);
// if (success) {
// redisUtil.saveByKey(AppRedisKey.DEVICE_MID + item.getNdid(), 1);
// }
// } catch (Exception e) {
// log.error("设备 {} 接入异常: {}", item.getNdid(), e.getMessage());
// }
// }
// } catch (Exception e) {
// log.error("处理设备 {} 失败: {}", item.getNdid(), e.getMessage());
// }
// }
// }
//
// }
//}

View File

@@ -0,0 +1,26 @@
package com.njcn.access.runner;
import com.njcn.access.service.ICsHeartService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* @author xy
* 定时轮询离线设备接入
*/
@Component
@Slf4j
@RequiredArgsConstructor
public class UpdateDevStatusTimer {
private final ICsHeartService csHeartService;
@Scheduled(cron = "0 0/30 * * * ?")
public void timer() {
csHeartService.updateDevStatus();
}
}

View File

@@ -32,4 +32,6 @@ public interface ICsDataSetService extends IService<CsDataSet> {
*/ */
List<CsDataSet> getDataSetData(String modelId); List<CsDataSet> getDataSetData(String modelId);
List<CsDataSet> getDataSetData2(String modelId);
} }

View File

@@ -58,4 +58,11 @@ public interface ICsDeviceService {
String autoPortableLedger(); String autoPortableLedger();
String onlineRegister(String projectId,String nDid); String onlineRegister(String projectId,String nDid);
/**
* 设备修改mac之后需要手动重新接入因为已经存在台账了只要询问主题、发起接入请求即可
* @param nDid
* @return
*/
String accessByUpdateMac(String nDid);
} }

View File

@@ -24,6 +24,11 @@ public interface ICsEquipmentDeliveryService extends IService<CsEquipmentDeliver
*/ */
void updateStatusBynDid(String nDid,Integer status,String engineeringId, String projectId); void updateStatusBynDid(String nDid,Integer status,String engineeringId, String projectId);
/**
* 批量修改设备通讯状态和接入状态
*/
void updateStatusByList(List<String> list);
/** /**
* 根据网关id修改软件信息 * 根据网关id修改软件信息
* @param nDid 网关id * @param nDid 网关id
@@ -61,7 +66,7 @@ public interface ICsEquipmentDeliveryService extends IService<CsEquipmentDeliver
void devResetFactory(DeviceStatusParam param); void devResetFactory(DeviceStatusParam param);
/** /**
* 获取启用并且客户端在线的装置 * 获取启用并且未删除的装置
*/ */
List<CsEquipmentDeliveryPO> getOnlineDev(); List<CsEquipmentDeliveryPO> getOnlineDev();

View File

@@ -2,6 +2,8 @@ package com.njcn.access.service;
import com.njcn.mq.message.HeartbeatTimeoutMessage; import com.njcn.mq.message.HeartbeatTimeoutMessage;
import java.util.List;
/** /**
* @author xy * @author xy
*/ */
@@ -9,4 +11,8 @@ public interface ICsHeartService {
void handleHeartbeat(HeartbeatTimeoutMessage message); void handleHeartbeat(HeartbeatTimeoutMessage message);
List<String> getMissHeartbeat();
void updateDevStatus();
} }

View File

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
import com.njcn.access.pojo.po.CsTopic; import com.njcn.access.pojo.po.CsTopic;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* <p> * <p>
@@ -28,5 +29,7 @@ public interface ICsTopicService extends IService<CsTopic> {
*/ */
String getVersion(String nDid); String getVersion(String nDid);
Map<String,String> getVersion(List<String> list);
void deleteByNDid(String nDid); void deleteByNDid(String nDid);
} }

View File

@@ -10,7 +10,9 @@ import com.njcn.access.pojo.dto.ControlDto;
import com.njcn.access.pojo.dto.ReqAndResDto; import com.njcn.access.pojo.dto.ReqAndResDto;
import com.njcn.access.service.AskDeviceDataService; import com.njcn.access.service.AskDeviceDataService;
import com.njcn.common.pojo.exception.BusinessException; import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.csdevice.api.CsLineFeignClient;
import com.njcn.csdevice.enums.AlgorithmResponseEnum; import com.njcn.csdevice.enums.AlgorithmResponseEnum;
import com.njcn.csdevice.pojo.po.CsLinePO;
import com.njcn.mq.message.RealDataMessage; import com.njcn.mq.message.RealDataMessage;
import com.njcn.mq.template.RealDataMessageTemplate; import com.njcn.mq.template.RealDataMessageTemplate;
import com.njcn.redis.pojo.enums.AppRedisKey; import com.njcn.redis.pojo.enums.AppRedisKey;
@@ -33,6 +35,7 @@ public class AskDeviceDataServiceImpl implements AskDeviceDataService {
private static final Logger log = LoggerFactory.getLogger(AskDeviceDataServiceImpl.class); private static final Logger log = LoggerFactory.getLogger(AskDeviceDataServiceImpl.class);
private final MqttPublisher publisher; private final MqttPublisher publisher;
private final CsTopicFeignClient csTopicFeignClient; private final CsTopicFeignClient csTopicFeignClient;
private final CsLineFeignClient csLineFeignClient;
private final RedisUtil redisUtil; private final RedisUtil redisUtil;
private final RealDataMessageTemplate realDataMessageTemplate; private final RealDataMessageTemplate realDataMessageTemplate;
private static Integer mid = 1; private static Integer mid = 1;
@@ -218,8 +221,8 @@ public class AskDeviceDataServiceImpl implements AskDeviceDataService {
public void askCldRealData(String devId, String lineId, String nodeId, Integer idx) { public void askCldRealData(String devId, String lineId, String nodeId, Integer idx) {
RealDataMessage realDataMessage = new RealDataMessage(); RealDataMessage realDataMessage = new RealDataMessage();
realDataMessage.setDevSeries(devId); realDataMessage.setDevSeries(devId);
int lastDigit = Character.getNumericValue(lineId.charAt(lineId.length() - 1)); CsLinePO po = csLineFeignClient.getById(lineId).getData();
realDataMessage.setLine(lastDigit); realDataMessage.setLine(po.getLineNo());
realDataMessage.setRealData(true); realDataMessage.setRealData(true);
realDataMessage.setSoeData(true); realDataMessage.setSoeData(true);
realDataMessage.setLimit(20); realDataMessage.setLimit(20);

View File

@@ -6,6 +6,7 @@ import com.njcn.access.service.ICsDataSetService;
import com.njcn.csdevice.pojo.po.CsDataSet; import com.njcn.csdevice.pojo.po.CsDataSet;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List; import java.util.List;
/** /**
@@ -37,4 +38,13 @@ public class CsDataSetServiceImpl extends ServiceImpl<CsDataSetMapper, CsDataSet
.and(item->item.eq(CsDataSet::getDataType,"Stat").or().isNull(CsDataSet::getDataType)) .and(item->item.eq(CsDataSet::getDataType,"Stat").or().isNull(CsDataSet::getDataType))
.list(); .list();
} }
@Override
public List<CsDataSet> getDataSetData2(String modelId) {
return this.lambdaQuery()
.eq(CsDataSet::getPid, modelId)
.and(item->item.eq(CsDataSet::getDataType,"Stat").or().isNull(CsDataSet::getDataType))
.eq(CsDataSet::getStoreFlag,1)
.list();
}
} }

View File

@@ -20,15 +20,19 @@ import com.njcn.access.pojo.po.CsLineModel;
import com.njcn.access.service.*; import com.njcn.access.service.*;
import com.njcn.access.utils.CRC32Utils; import com.njcn.access.utils.CRC32Utils;
import com.njcn.access.utils.JsonUtil; import com.njcn.access.utils.JsonUtil;
import com.njcn.common.pojo.dto.DeviceLogDTO;
import com.njcn.common.pojo.exception.BusinessException; import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.csdevice.api.*; import com.njcn.csdevice.api.CsLineFeignClient;
import com.njcn.csdevice.api.DevModelFeignClient;
import com.njcn.csdevice.api.DevModelRelationFeignClient;
import com.njcn.csdevice.api.EquipmentFeignClient;
import com.njcn.csdevice.enums.AlgorithmResponseEnum; import com.njcn.csdevice.enums.AlgorithmResponseEnum;
import com.njcn.csdevice.pojo.param.CsDevModelAddParm; import com.njcn.csdevice.pojo.param.CsDevModelAddParm;
import com.njcn.csdevice.pojo.po.CsDataArray; import com.njcn.csdevice.pojo.po.CsDataArray;
import com.njcn.csdevice.pojo.po.CsDataSet; import com.njcn.csdevice.pojo.po.CsDataSet;
import com.njcn.csdevice.pojo.po.CsDevModelPO; import com.njcn.csdevice.pojo.po.CsDevModelPO;
import com.njcn.csdevice.pojo.po.CsEquipmentDeliveryPO; import com.njcn.csdevice.pojo.po.CsEquipmentDeliveryPO;
import com.njcn.mq.message.LogMessage;
import com.njcn.mq.template.LogMessageTemplate;
import com.njcn.oss.constant.OssPath; import com.njcn.oss.constant.OssPath;
import com.njcn.oss.utils.FileStorageUtil; import com.njcn.oss.utils.FileStorageUtil;
import com.njcn.redis.pojo.enums.AppRedisKey; import com.njcn.redis.pojo.enums.AppRedisKey;
@@ -43,6 +47,7 @@ import com.njcn.system.pojo.vo.DictTreeVO;
import com.njcn.web.utils.RequestUtil; import com.njcn.web.utils.RequestUtil;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@@ -74,7 +79,6 @@ public class CsDevModelServiceImpl implements ICsDevModelService {
private final ICsLineModelService csLineModelService; private final ICsLineModelService csLineModelService;
private final ICsGroupService csGroupService; private final ICsGroupService csGroupService;
private final ICsGroArrService csGroArrService; private final ICsGroArrService csGroArrService;
private final CsLogsFeignClient csLogsFeignClient;
private final EleWaveFeignClient waveFeignClient; private final EleWaveFeignClient waveFeignClient;
private final DictTreeFeignClient dictTreeFeignClient; private final DictTreeFeignClient dictTreeFeignClient;
private final MqttPublisher publisher; private final MqttPublisher publisher;
@@ -83,13 +87,15 @@ public class CsDevModelServiceImpl implements ICsDevModelService {
private final EquipmentFeignClient eequipmentFeignClient; private final EquipmentFeignClient eequipmentFeignClient;
private final DevModelRelationFeignClient devModelRelationFeignClient; private final DevModelRelationFeignClient devModelRelationFeignClient;
private final CsLineFeignClient csLineFeignClient; private final CsLineFeignClient csLineFeignClient;
private final LogMessageTemplate logMessageTemplate;
private final StringRedisTemplate stringRedisTemplate;
@Override @Override
@Transactional(rollbackFor = {Exception.class}) @Transactional(rollbackFor = {Exception.class})
public void addModel(MultipartFile file) { public void addModel(MultipartFile file) {
//日志实体 //日志实体
DeviceLogDTO logDto = new DeviceLogDTO(); LogMessage logDto = new LogMessage();
logDto.setUserName(RequestUtil.getUserNickname()); logDto.setUserIndex(RequestUtil.getUserNickname());
logDto.setLoginName(RequestUtil.getUsername()); logDto.setLoginName(RequestUtil.getUsername());
logDto.setResult(1); logDto.setResult(1);
String json = null; String json = null;
@@ -128,21 +134,24 @@ public class CsDevModelServiceImpl implements ICsDevModelService {
.filter(item -> Objects.equals(item.getDevAccessMethod(),"CLD")) .filter(item -> Objects.equals(item.getDevAccessMethod(),"CLD"))
.map(CsEquipmentDeliveryPO::getId) .map(CsEquipmentDeliveryPO::getId)
.collect(Collectors.toList()); .collect(Collectors.toList());
devModelRelationFeignClient.updateDataByList(devList,csDevModelPo.getId()); if (ObjectUtil.isNotEmpty(devList)) {
Object object = redisUtil.getObjectByKey("setId:" + csDevModelPo.getId()); devModelRelationFeignClient.updateDataByList(devList,csDevModelPo.getId());
if (ObjectUtil.isNotNull(object)) { Object object = redisUtil.getObjectByKey("setId:" + csDevModelPo.getId());
csLineFeignClient.updateDataByList(devList,csDevModelPo.getId(),object.toString()); if (ObjectUtil.isNotNull(object)) {
csLineFeignClient.updateDataByList(devList,csDevModelPo.getId(),object.toString());
}
} }
} }
} }
//5.清空模板缓存 //5.清空模板缓存
redisUtil.deleteKeysByString(AppRedisKey.DEV_MODEL); //redisUtil.deleteKeysByString(AppRedisKey.DEV_MODEL);
csLogsFeignClient.addUserLog(logDto); //6.通知其他服务节点清理本地缓存
stringRedisTemplate.convertAndSend("model_cache_clear", "clear");
logMessageTemplate.sendMember(logDto);
} catch (Exception e) { } catch (Exception e) {
logDto.setResult(0); logDto.setResult(0);
logDto.setFailReason(AccessResponseEnum.MODEL_ANALYSIS_ERROR.getMessage()); logDto.setFailReason(AccessResponseEnum.MODEL_ANALYSIS_ERROR.getMessage());
csLogsFeignClient.addUserLog(logDto); logMessageTemplate.sendMember(logDto);
throw new BusinessException(e.getMessage()); throw new BusinessException(e.getMessage());
} }
} }
@@ -151,8 +160,8 @@ public class CsDevModelServiceImpl implements ICsDevModelService {
@Transactional(rollbackFor = {Exception.class}) @Transactional(rollbackFor = {Exception.class})
public void addDict(MultipartFile file) { public void addDict(MultipartFile file) {
//日志实体 //日志实体
DeviceLogDTO logDto = new DeviceLogDTO(); LogMessage logDto = new LogMessage();
logDto.setUserName(RequestUtil.getUserNickname()); logDto.setUserIndex(RequestUtil.getUserNickname());
logDto.setLoginName(RequestUtil.getUsername()); logDto.setLoginName(RequestUtil.getUsername());
logDto.setResult(1); logDto.setResult(1);
String json = null; String json = null;
@@ -162,11 +171,11 @@ public class CsDevModelServiceImpl implements ICsDevModelService {
TemplateDto templateDto = gson.fromJson(json, TemplateDto.class); TemplateDto templateDto = gson.fromJson(json, TemplateDto.class);
logDto.setOperate(templateDto.getDevType() + "录入通用字典"); logDto.setOperate(templateDto.getDevType() + "录入通用字典");
analysisDict(templateDto); analysisDict(templateDto);
csLogsFeignClient.addUserLog(logDto); logMessageTemplate.sendMember(logDto);
} catch (Exception e) { } catch (Exception e) {
logDto.setResult(0); logDto.setResult(0);
logDto.setFailReason(AccessResponseEnum.DICT_ANALYSIS_ERROR.getMessage()); logDto.setFailReason(AccessResponseEnum.DICT_ANALYSIS_ERROR.getMessage());
csLogsFeignClient.addUserLog(logDto); logMessageTemplate.sendMember(logDto);
throw new BusinessException(AccessResponseEnum.DICT_ANALYSIS_ERROR); throw new BusinessException(AccessResponseEnum.DICT_ANALYSIS_ERROR);
} }
} }
@@ -200,7 +209,7 @@ public class CsDevModelServiceImpl implements ICsDevModelService {
//发送数据给前端 //发送数据给前端
String json = "{fileName:"+file.getOriginalFilename()+",allStep:"+times+",nowStep:"+i+"}"; String json = "{fileName:"+file.getOriginalFilename()+",allStep:"+times+",nowStep:"+i+"}";
publisher.send("/Web/Progress/" + id, new Gson().toJson(json), 1, false); publisher.send("/Web/Progress/" + id, new Gson().toJson(json), 1, false);
DeviceLogDTO logDto = new DeviceLogDTO(); LogMessage logDto = new LogMessage();
byte[] lsBytes; byte[] lsBytes;
if (length > 50*1024) { if (length > 50*1024) {
lsBytes = Arrays.copyOfRange(bytes, (i - 1) * cap, i * cap); lsBytes = Arrays.copyOfRange(bytes, (i - 1) * cap, i * cap);
@@ -226,25 +235,26 @@ public class CsDevModelServiceImpl implements ICsDevModelService {
//判断是否重发 //判断是否重发
sendNextStep(logDto,path,file,bytes.length,lsBytes,(i-1)*cap,version,id,i,hexString,true); sendNextStep(logDto,path,file,bytes.length,lsBytes,(i-1)*cap,version,id,i,hexString,true);
} }
csLogsFeignClient.addUserLog(logDto); logMessageTemplate.sendMember(logDto);
} }
} else { } else {
String json = "{fileName:"+file.getOriginalFilename()+",allStep:\""+1+"\",nowStep:"+1+"}"; String json = "{fileName:"+file.getOriginalFilename()+",allStep:\""+1+"\",nowStep:"+1+"}";
publisher.send("/Web/Progress", new Gson().toJson(json), 1, false); publisher.send("/Web/Progress", new Gson().toJson(json), 1, false);
ReqAndResDto.Req req = getPojo(1,path,file,length,bytes,0,hexString); ReqAndResDto.Req req = getPojo(1,path,file,length,bytes,0,hexString);
publisher.send("/Pfm/DevFileCmd/" + version + "/" + id, new Gson().toJson(req), 1, false); publisher.send("/Pfm/DevFileCmd/" + version + "/" + id, new Gson().toJson(req), 1, false);
DeviceLogDTO logDto = new DeviceLogDTO(); LogMessage logDto = new LogMessage();
logDto.setOperate(id + "系统上送文件,当前文件只有1帧"); logDto.setOperate(id + "系统上送文件,当前文件只有1帧");
logDto.setResult(1); logDto.setResult(1);
csLogsFeignClient.addUserLog(logDto); logMessageTemplate.sendMember(logDto);
//判断是否重发 //判断是否重发
sendNextStep(logDto,path,file,length,bytes,0,version,id,1,hexString,false); sendNextStep(logDto,path,file,length,bytes,0,version,id,1,hexString,false);
} }
} catch (Exception e) { } catch (Exception e) {
DeviceLogDTO logDto = new DeviceLogDTO(); LogMessage logDto = new LogMessage();
logDto.setResult(0); logDto.setResult(0);
logDto.setFailReason(AccessResponseEnum.UPLOAD_ERROR.getMessage()); logDto.setOperate("系统上传文件");
csLogsFeignClient.addUserLog(logDto); logDto.setFailReason(e.getMessage());
logMessageTemplate.sendMember(logDto);
throw new BusinessException(AccessResponseEnum.UPLOAD_ERROR); throw new BusinessException(AccessResponseEnum.UPLOAD_ERROR);
} }
} }
@@ -278,7 +288,7 @@ public class CsDevModelServiceImpl implements ICsDevModelService {
/** /**
* 根据装置响应来判断发送的内容 * 根据装置响应来判断发送的内容
*/ */
public void sendNextStep(DeviceLogDTO logDto, String path, MultipartFile file, int length, byte[] bytes, Integer offset, String version, String id, int mid, String fileCheck, boolean result) { public void sendNextStep(LogMessage logDto, String path, MultipartFile file, int length, byte[] bytes, Integer offset, String version, String id, int mid, String fileCheck, boolean result) {
try { try {
for (int i = 0; i < 30; i++) { for (int i = 0; i < 30; i++) {
if (result) { if (result) {
@@ -302,16 +312,17 @@ public class CsDevModelServiceImpl implements ICsDevModelService {
publisher.send("/Pfm/DevFileCmd/" + version + "/" + id, new Gson().toJson(req), 1, false); publisher.send("/Pfm/DevFileCmd/" + version + "/" + id, new Gson().toJson(req), 1, false);
logDto.setOperate(id + "系统上送文件,装置响应失败,重新发送,这是第" + (i+1) + ""); logDto.setOperate(id + "系统上送文件,装置响应失败,重新发送,这是第" + (i+1) + "");
logDto.setResult(1); logDto.setResult(1);
csLogsFeignClient.addUserLog(logDto); logMessageTemplate.sendMember(logDto);
} }
} }
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
assert logDto != null; assert logDto != null;
logDto.setResult(0); logDto.setResult(0);
logDto.setFailReason(AccessResponseEnum.RELOAD_UPLOAD_ERROR.getMessage()); logDto.setOperate("平台重新上送文件");
csLogsFeignClient.addUserLog(logDto); logDto.setFailReason(e.getMessage());
throw new RuntimeException(e); logMessageTemplate.sendMember(logDto);
throw new BusinessException(AccessResponseEnum.RELOAD_UPLOAD_ERROR);
} }
} }
@@ -321,8 +332,8 @@ public class CsDevModelServiceImpl implements ICsDevModelService {
*/ */
private CsDevModelPO addCsDevModel(TemplateDto templateDto, String filePath){ private CsDevModelPO addCsDevModel(TemplateDto templateDto, String filePath){
//日志实体 //日志实体
DeviceLogDTO logDto = new DeviceLogDTO(); LogMessage logDto = new LogMessage();
logDto.setUserName(RequestUtil.getUserNickname()); logDto.setUserIndex(RequestUtil.getUserNickname());
logDto.setLoginName(RequestUtil.getUsername()); logDto.setLoginName(RequestUtil.getUsername());
logDto.setOperate("新增"+templateDto.getDevType()+"模板数据"); logDto.setOperate("新增"+templateDto.getDevType()+"模板数据");
logDto.setResult(1); logDto.setResult(1);
@@ -330,23 +341,9 @@ public class CsDevModelServiceImpl implements ICsDevModelService {
if (!Objects.isNull(po)){ if (!Objects.isNull(po)){
logDto.setResult(0); logDto.setResult(0);
logDto.setFailReason(AccessResponseEnum.MODEL_REPEAT.getMessage()); logDto.setFailReason(AccessResponseEnum.MODEL_REPEAT.getMessage());
csLogsFeignClient.addUserLog(logDto); logMessageTemplate.sendMember(logDto);
throw new BusinessException(AccessResponseEnum.MODEL_REPEAT); throw new BusinessException(AccessResponseEnum.MODEL_REPEAT);
} }
// CsDevModelPO model = new CsDevModelPO();
// model.setDevTypeName(templateDto.getDevType());
// model.setName(templateDto.getDevType());
// model.setVersionNo(templateDto.getVersion());
// model.setVersionDate(Date.valueOf(templateDto.getTime()));
// model.setFilePath(filePath);
// model.setStatus ("1");
// //fixme 先用数据类型来区分模板的类型
// if (templateDto.getDataList().contains("Apf") || templateDto.getDataList().contains("Dvr")){
// model.setType(0);
// } else {
// model.setType(1);
// }
// csDevModelMapper.insert(model);
CsDevModelAddParm csDevModelAddParm = new CsDevModelAddParm(); CsDevModelAddParm csDevModelAddParm = new CsDevModelAddParm();
csDevModelAddParm.setDevTypeName(templateDto.getDevType()); csDevModelAddParm.setDevTypeName(templateDto.getDevType());
csDevModelAddParm.setName(templateDto.getDevType()); csDevModelAddParm.setName(templateDto.getDevType());
@@ -360,7 +357,7 @@ public class CsDevModelServiceImpl implements ICsDevModelService {
csDevModelAddParm.setType(1); csDevModelAddParm.setType(1);
} }
CsDevModelPO model = devModelFeignClient.addDevModel(csDevModelAddParm).getData(); CsDevModelPO model = devModelFeignClient.addDevModel(csDevModelAddParm).getData();
csLogsFeignClient.addUserLog(logDto); logMessageTemplate.sendMember(logDto);
return model; return model;
} }

View File

@@ -9,15 +9,15 @@ import com.njcn.access.mapper.CsEquipmentDeliveryMapper;
import com.njcn.access.pojo.param.DeviceStatusParam; import com.njcn.access.pojo.param.DeviceStatusParam;
import com.njcn.access.service.ICsEquipmentDeliveryService; import com.njcn.access.service.ICsEquipmentDeliveryService;
import com.njcn.access.utils.MqttUtil; import com.njcn.access.utils.MqttUtil;
import com.njcn.common.pojo.dto.DeviceLogDTO;
import com.njcn.csdevice.api.CsLogsFeignClient;
import com.njcn.csdevice.pojo.po.CsEquipmentDeliveryPO; import com.njcn.csdevice.pojo.po.CsEquipmentDeliveryPO;
import com.njcn.csdevice.pojo.vo.CsEquipmentDeliveryVO; import com.njcn.csdevice.pojo.vo.CsEquipmentDeliveryVO;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.*; import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@@ -35,8 +35,6 @@ public class CsEquipmentDeliveryServiceImpl extends ServiceImpl<CsEquipmentDeliv
private final MqttUtil mqttUtil; private final MqttUtil mqttUtil;
private final CsLogsFeignClient csLogsFeignClient;
@Override @Override
public void updateStatusBynDid(String nDid,Integer status,String engineeringId, String projectId) { public void updateStatusBynDid(String nDid,Integer status,String engineeringId, String projectId) {
LambdaUpdateWrapper<CsEquipmentDeliveryPO> lambdaUpdateWrapper = new LambdaUpdateWrapper<>(); LambdaUpdateWrapper<CsEquipmentDeliveryPO> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
@@ -50,6 +48,16 @@ public class CsEquipmentDeliveryServiceImpl extends ServiceImpl<CsEquipmentDeliv
this.update(lambdaUpdateWrapper); this.update(lambdaUpdateWrapper);
} }
@Override
public void updateStatusByList(List<String> list) {
LambdaUpdateWrapper<CsEquipmentDeliveryPO> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
lambdaUpdateWrapper
.set(CsEquipmentDeliveryPO::getRunStatus,AccessEnum.OFFLINE.getCode())
.set(CsEquipmentDeliveryPO::getStatus,AccessEnum.REGISTERED.getCode())
.in(CsEquipmentDeliveryPO::getNdid,list);
this.update(lambdaUpdateWrapper);
}
@Override @Override
public void updateSoftInfoBynDid(String nDid, String id, Integer moduleNumber) { public void updateSoftInfoBynDid(String nDid, String id, Integer moduleNumber) {
LambdaUpdateWrapper<CsEquipmentDeliveryPO> lambdaUpdateWrapper = new LambdaUpdateWrapper<>(); LambdaUpdateWrapper<CsEquipmentDeliveryPO> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
@@ -102,6 +110,7 @@ public class CsEquipmentDeliveryServiceImpl extends ServiceImpl<CsEquipmentDeliv
List<CsEquipmentDeliveryPO> result = new ArrayList<>(); List<CsEquipmentDeliveryPO> result = new ArrayList<>();
List<CsEquipmentDeliveryPO> list = this.lambdaQuery() List<CsEquipmentDeliveryPO> list = this.lambdaQuery()
.ne(CsEquipmentDeliveryPO::getRunStatus,AccessEnum.DEL.getCode()) .ne(CsEquipmentDeliveryPO::getRunStatus,AccessEnum.DEL.getCode())
.ne(CsEquipmentDeliveryPO::getStatus,AccessEnum.UNREGISTERED.getCode())
.eq(CsEquipmentDeliveryPO::getUsageStatus,1) .eq(CsEquipmentDeliveryPO::getUsageStatus,1)
.list(); .list();
if (CollUtil.isNotEmpty(list)) { if (CollUtil.isNotEmpty(list)) {
@@ -110,13 +119,6 @@ public class CsEquipmentDeliveryServiceImpl extends ServiceImpl<CsEquipmentDeliv
boolean mqttClient = mqttUtil.judgeClientOnline(clientName); boolean mqttClient = mqttUtil.judgeClientOnline(clientName);
if (mqttClient) { if (mqttClient) {
result.add(item); result.add(item);
} else {
DeviceLogDTO logDto = new DeviceLogDTO();
logDto.setUserName("运维管理员");
logDto.setLoginName("njcnyw");
logDto.setResult(1);
logDto.setOperate(item.getNdid() + "接入失败,装置客户端不在线");
csLogsFeignClient.addUserLog(logDto);
} }
}); });
} }
@@ -133,12 +135,12 @@ public class CsEquipmentDeliveryServiceImpl extends ServiceImpl<CsEquipmentDeliv
} }
@Override @Override
public List<CsEquipmentDeliveryPO> getOfflineDev() { public List<CsEquipmentDeliveryPO> getOfflineDev() {
List<CsEquipmentDeliveryPO> result = new ArrayList<>(); List<CsEquipmentDeliveryPO> result = new ArrayList<>();
List<CsEquipmentDeliveryPO> list = this.lambdaQuery() List<CsEquipmentDeliveryPO> list = this.lambdaQuery()
.eq(CsEquipmentDeliveryPO::getRunStatus,AccessEnum.OFFLINE.getCode()) .eq(CsEquipmentDeliveryPO::getRunStatus,AccessEnum.OFFLINE.getCode())
.eq(CsEquipmentDeliveryPO::getUsageStatus,1) .eq(CsEquipmentDeliveryPO::getUsageStatus,1)
.in(CsEquipmentDeliveryPO::getStatus, Arrays.asList(2,3)) .ne(CsEquipmentDeliveryPO::getStatus,AccessEnum.UNREGISTERED.getCode())
.isNull(CsEquipmentDeliveryPO::getNodeId) .isNull(CsEquipmentDeliveryPO::getNodeId)
.list(); .list();
if (CollUtil.isNotEmpty(list)) { if (CollUtil.isNotEmpty(list)) {
@@ -147,13 +149,6 @@ public class CsEquipmentDeliveryServiceImpl extends ServiceImpl<CsEquipmentDeliv
boolean mqttClient = mqttUtil.judgeClientOnline(clientName); boolean mqttClient = mqttUtil.judgeClientOnline(clientName);
if (mqttClient) { if (mqttClient) {
result.add(item); result.add(item);
} else {
DeviceLogDTO logDto = new DeviceLogDTO();
logDto.setUserName("运维管理员");
logDto.setLoginName("njcnyw");
logDto.setResult(1);
logDto.setOperate(item.getNdid() + "接入失败,装置客户端不在线");
csLogsFeignClient.addUserLog(logDto);
} }
}); });
} }

View File

@@ -1,15 +1,19 @@
package com.njcn.access.service.impl; package com.njcn.access.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DatePattern;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.njcn.access.enums.AccessEnum; import com.njcn.access.enums.AccessEnum;
import com.njcn.access.pojo.dto.NoticeUserDto; import com.njcn.access.pojo.dto.NoticeUserDto;
import com.njcn.access.service.ICsEquipmentDeliveryService; import com.njcn.access.service.ICsEquipmentDeliveryService;
import com.njcn.access.service.ICsHeartService; import com.njcn.access.service.ICsHeartService;
import com.njcn.access.service.IHeartbeatService; import com.njcn.access.service.IHeartbeatService;
import com.njcn.access.utils.SendMessageUtil; import com.njcn.access.utils.SendMessageUtil;
import com.njcn.common.pojo.dto.DeviceLogDTO; import com.njcn.csdevice.api.CsCommunicateFeignClient;
import com.njcn.csdevice.api.*; import com.njcn.csdevice.api.CsLedgerFeignClient;
import com.njcn.csdevice.api.DeviceMessageFeignClient;
import com.njcn.csdevice.api.EquipmentFeignClient;
import com.njcn.csdevice.param.DeviceMessageParam; import com.njcn.csdevice.param.DeviceMessageParam;
import com.njcn.csdevice.pojo.dto.DevDetailDTO; import com.njcn.csdevice.pojo.dto.DevDetailDTO;
import com.njcn.csdevice.pojo.dto.PqsCommunicateDto; import com.njcn.csdevice.pojo.dto.PqsCommunicateDto;
@@ -17,8 +21,6 @@ import com.njcn.csdevice.pojo.po.CsEquipmentDeliveryPO;
import com.njcn.mq.message.HeartbeatTimeoutMessage; import com.njcn.mq.message.HeartbeatTimeoutMessage;
import com.njcn.redis.pojo.enums.AppRedisKey; import com.njcn.redis.pojo.enums.AppRedisKey;
import com.njcn.redis.utils.RedisUtil; import com.njcn.redis.utils.RedisUtil;
import com.njcn.user.api.AppUserFeignClient;
import com.njcn.user.api.UserFeignClient;
import com.njcn.user.pojo.po.User; import com.njcn.user.pojo.po.User;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -26,8 +28,10 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@@ -45,20 +49,12 @@ public class CsHeartServiceImpl implements ICsHeartService {
@Resource @Resource
private ICsEquipmentDeliveryService csEquipmentDeliveryService; private ICsEquipmentDeliveryService csEquipmentDeliveryService;
@Resource @Resource
private CsLogsFeignClient csLogsFeignClient;
@Resource
private EquipmentFeignClient equipmentFeignClient; private EquipmentFeignClient equipmentFeignClient;
@Resource @Resource
private SendMessageUtil sendMessageUtil; private SendMessageUtil sendMessageUtil;
@Resource @Resource
private CsLedgerFeignClient csLedgerFeignclient; private CsLedgerFeignClient csLedgerFeignclient;
@Resource @Resource
private AppUserFeignClient appUserFeignClient;
@Resource
private CsDeviceUserFeignClient csDeviceUserFeignClient;
@Resource
private UserFeignClient userFeignClient;
@Resource
private IHeartbeatService heartbeatService; private IHeartbeatService heartbeatService;
@Resource @Resource
private CsCommunicateFeignClient csCommunicateFeignClient; private CsCommunicateFeignClient csCommunicateFeignClient;
@@ -78,15 +74,54 @@ public class CsHeartServiceImpl implements ICsHeartService {
handleDeviceOffline(nDid); handleDeviceOffline(nDid);
} }
@Override
public List<String> getMissHeartbeat() {
List<String> result = new ArrayList<>();
LambdaQueryWrapper<CsEquipmentDeliveryPO> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(CsEquipmentDeliveryPO::getRunStatus, 2).eq(CsEquipmentDeliveryPO::getUsageStatus,1);
List<CsEquipmentDeliveryPO> list = csEquipmentDeliveryService.list(queryWrapper);
//获取redis的数据
Set<String> keys = redisUtil.scanKeysByPattern("HEARTBEAT:*",100);
if (CollUtil.isNotEmpty(list)) {
list.forEach(item -> {
if (Objects.equals(item.getDevAccessMethod(),"CLD")) {
return;
}
String nDid = item.getNdid();
boolean hasHeartbeat = keys.stream().anyMatch(key -> key.contains(nDid));
if (!hasHeartbeat) {
result.add(nDid);
}
});
}
return result;
}
@Override
public void updateDevStatus() {
List<String> missHeartbeat = getMissHeartbeat();
if (CollUtil.isNotEmpty(missHeartbeat)) {
List<PqsCommunicateDto> list = new ArrayList<>();
//修改状态
csEquipmentDeliveryService.updateStatusByList(missHeartbeat);
//记录掉线
missHeartbeat.forEach(item->{
PqsCommunicateDto dto = new PqsCommunicateDto();
dto.setTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
dto.setDevId(item);
dto.setType(0);
dto.setDescription("通讯中断");
list.add(dto);
});
csCommunicateFeignClient.insertionList(list);
}
}
private void handleDeviceOffline(String nDid) { private void handleDeviceOffline(String nDid) {
DeviceLogDTO logDto = new DeviceLogDTO();
logDto.setUserName("运维管理员");
logDto.setLoginName("njcnyw");
//装置下线 //装置下线
csEquipmentDeliveryService.updateRunStatusBynDid(nDid, AccessEnum.OFFLINE.getCode()); csEquipmentDeliveryService.updateRunStatusBynDid(nDid, AccessEnum.OFFLINE.getCode());
//装置调整为注册状态 //装置调整为注册状态
csEquipmentDeliveryService.updateStatusBynDid(nDid,AccessEnum.REGISTERED.getCode(),null,null); csEquipmentDeliveryService.updateStatusBynDid(nDid,AccessEnum.REGISTERED.getCode(),null,null);
logDto.setOperate(nDid +"装置离线");
sendMessage(nDid); sendMessage(nDid);
//记录装置掉线时间 //记录装置掉线时间
PqsCommunicateDto dto = new PqsCommunicateDto(); PqsCommunicateDto dto = new PqsCommunicateDto();
@@ -95,7 +130,6 @@ public class CsHeartServiceImpl implements ICsHeartService {
dto.setType(0); dto.setType(0);
dto.setDescription("通讯中断"); dto.setDescription("通讯中断");
csCommunicateFeignClient.insertion(dto); csCommunicateFeignClient.insertion(dto);
csLogsFeignClient.addUserLog(logDto);
//清空缓存 //清空缓存
redisUtil.deleteKeysByString(AppRedisKey.LINE_POSITION+nDid); redisUtil.deleteKeysByString(AppRedisKey.LINE_POSITION+nDid);
} }
@@ -106,7 +140,6 @@ public class CsHeartServiceImpl implements ICsHeartService {
NoticeUserDto dto = sendOffLine(nDid); NoticeUserDto dto = sendOffLine(nDid);
if (CollectionUtil.isNotEmpty(dto.getPushClientId())) { if (CollectionUtil.isNotEmpty(dto.getPushClientId())) {
sendMessageUtil.sendEventToUser(dto); sendMessageUtil.sendEventToUser(dto);
addLogs(dto);
} }
} }
} }
@@ -135,12 +168,4 @@ public class CsHeartServiceImpl implements ICsHeartService {
} }
return dto; return dto;
} }
private void addLogs(NoticeUserDto noticeUserDto) {
DeviceLogDTO dto = new DeviceLogDTO();
dto.setUserName("运维管理员");
dto.setLoginName("njcnyw");
dto.setOperate(noticeUserDto.getContent());
csLogsFeignClient.addUserLog(dto);
}
} }

View File

@@ -8,7 +8,10 @@ import com.njcn.access.pojo.po.CsTopic;
import com.njcn.access.service.ICsTopicService; import com.njcn.access.service.ICsTopicService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/** /**
* <p> * <p>
@@ -42,6 +45,17 @@ public class CsTopicServiceImpl extends ServiceImpl<CsTopicMapper, CsTopic> impl
return version; return version;
} }
@Override
public Map<String, String> getVersion(List<String> list) {
Map<String, String> map = new HashMap<>();
List<CsTopic> topicList = this.lambdaQuery().in(CsTopic::getNDid,list).isNotNull(CsTopic::getVersion).list();
Map<String, List<CsTopic>> topicMap = topicList.stream().collect(Collectors.groupingBy(CsTopic::getNDid));
topicMap.forEach((key,value)->{
map.put(key,value.get(0).getVersion());
});
return map;
}
@Override @Override
public void deleteByNDid(String nDid) { public void deleteByNDid(String nDid) {
LambdaQueryWrapper<CsTopic> lambdaQueryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<CsTopic> lambdaQueryWrapper = new LambdaQueryWrapper<>();

View File

@@ -23,9 +23,13 @@ spring:
discovery: discovery:
ip: @service.server.url@ ip: @service.server.url@
server-addr: @nacos.url@ server-addr: @nacos.url@
username: @nacos.username@
password: @nacos.password@
namespace: @nacos.namespace@ namespace: @nacos.namespace@
config: config:
server-addr: @nacos.url@ server-addr: @nacos.url@
username: @nacos.username@
password: @nacos.password@
namespace: @nacos.namespace@ namespace: @nacos.namespace@
file-extension: yaml file-extension: yaml
shared-configs: shared-configs:
@@ -42,6 +46,7 @@ spring:
#项目日志的配置 #项目日志的配置
logging: logging:
# config: http://@nacos.url@/nacos/v1/cs/configs?tenant=@nacos.namespace@&username=@nacos.username@&password=@nacos.password@&group=DEFAULT_GROUP&dataId=logback.xml
config: http://@nacos.url@/nacos/v1/cs/configs?tenant=@nacos.namespace@&group=DEFAULT_GROUP&dataId=logback.xml config: http://@nacos.url@/nacos/v1/cs/configs?tenant=@nacos.namespace@&group=DEFAULT_GROUP&dataId=logback.xml
level: level:
root: info root: info

View File

@@ -8,14 +8,8 @@ import com.njcn.access.utils.ChannelObjectUtil;
import com.njcn.access.utils.RedisSetUtil; import com.njcn.access.utils.RedisSetUtil;
import com.njcn.common.pojo.exception.BusinessException; import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.common.utils.PubUtils; import com.njcn.common.utils.PubUtils;
import com.njcn.csdevice.api.CsLineFeignClient; import com.njcn.csdevice.api.*;
import com.njcn.csdevice.api.DataArrayFeignClient; import com.njcn.csdevice.pojo.po.*;
import com.njcn.csdevice.api.DataSetFeignClient;
import com.njcn.csdevice.api.EquipmentFeignClient;
import com.njcn.csdevice.pojo.po.CsDataArray;
import com.njcn.csdevice.pojo.po.CsDataSet;
import com.njcn.csdevice.pojo.po.CsEquipmentDeliveryPO;
import com.njcn.csdevice.pojo.po.CsLinePO;
import com.njcn.mq.message.AppAutoDataMessage; import com.njcn.mq.message.AppAutoDataMessage;
import com.njcn.redis.utils.RedisUtil; import com.njcn.redis.utils.RedisUtil;
import com.njcn.rt.enums.RtResponseEnum; import com.njcn.rt.enums.RtResponseEnum;
@@ -53,12 +47,19 @@ public class RtServiceImpl implements IRtService {
private final MqttPublisher publisher; private final MqttPublisher publisher;
private final RedisSetUtil redisSetUtil; private final RedisSetUtil redisSetUtil;
private final EquipmentFeignClient equipmentFeignClient; private final EquipmentFeignClient equipmentFeignClient;
private final CsDeviceRegistryFeignClient csDeviceRegistryFeignClient;
@Override @Override
public void analysis(AppAutoDataMessage appAutoDataMessage) { public void analysis(AppAutoDataMessage appAutoDataMessage) {
List<CsDataArray> dataArrayList; List<CsDataArray> dataArrayList;
//监测点id //监测点id
String lineId = appAutoDataMessage.getId() + appAutoDataMessage.getMsg().getClDid(); String lineId;
CsDeviceRegistry csDeviceRegistry = csDeviceRegistryFeignClient.queryByCurrentNdidAndClDid(appAutoDataMessage.getId(),appAutoDataMessage.getMsg().getClDid()).getData();
if (Objects.isNull(csDeviceRegistry)) {
lineId = appAutoDataMessage.getId() + appAutoDataMessage.getMsg().getClDid();
} else {
lineId = csDeviceRegistry.getId();
}
redisUtil.delete("cldRtDataOverTime:"+lineId); redisUtil.delete("cldRtDataOverTime:"+lineId);
//获取监测点基础信息 //获取监测点基础信息
CsLinePO po = csLineFeignClient.getById(lineId).getData(); CsLinePO po = csLineFeignClient.getById(lineId).getData();
@@ -96,6 +97,7 @@ public class RtServiceImpl implements IRtService {
long timestamp = item.getDataTimeSec() - 8*3600; long timestamp = item.getDataTimeSec() - 8*3600;
baseRealDataSet.setDataTime(getTime(timestamp)); baseRealDataSet.setDataTime(getTime(timestamp));
publisher.send("/Web/RealData/" + lineId, new Gson().toJson(baseRealDataSet), 1, false); publisher.send("/Web/RealData/" + lineId, new Gson().toJson(baseRealDataSet), 1, false);
redisUtil.saveByKeyWithExpire("devResponse:" + po1.getNdid() ,200,5L);
} }
} else if (dataSet.getName().contains("实时数据") || dataSet.getName().contains("Ds$Pqd$Rt$01")) { } else if (dataSet.getName().contains("实时数据") || dataSet.getName().contains("Ds$Pqd$Rt$01")) {
//用户Id //用户Id
@@ -112,6 +114,7 @@ public class RtServiceImpl implements IRtService {
long timestamp = item.getDataTimeSec(); long timestamp = item.getDataTimeSec();
baseRealDataSet.setDataTime(getTime(timestamp)); baseRealDataSet.setDataTime(getTime(timestamp));
publisher.send("/Web/RealData/" + lineId, new Gson().toJson(baseRealDataSet), 1, false); publisher.send("/Web/RealData/" + lineId, new Gson().toJson(baseRealDataSet), 1, false);
redisUtil.saveByKeyWithExpire("devResponse:" + lineId,200,5L);
}); });
} }
} }
@@ -135,6 +138,7 @@ public class RtServiceImpl implements IRtService {
} }
harmRealDataSet.setDataTime(getTime(timestamp)); harmRealDataSet.setDataTime(getTime(timestamp));
publisher.send("/Web/RealData/" + lineId, new Gson().toJson(harmRealDataSet), 1, false); publisher.send("/Web/RealData/" + lineId, new Gson().toJson(harmRealDataSet), 1, false);
redisUtil.saveByKeyWithExpire("devResponse:" + lineId,200,5L);
} }
} }
} }
@@ -142,12 +146,17 @@ public class RtServiceImpl implements IRtService {
@Override @Override
public void apfRtAnalysis(AppAutoDataMessage appAutoDataMessage) { public void apfRtAnalysis(AppAutoDataMessage appAutoDataMessage) {
List<CsDataArray> dataArrayList; List<CsDataArray> dataArrayList;
String lineId;
//监测点id //监测点id
if (appAutoDataMessage.getDid() == 1){ String lineId;
lineId = appAutoDataMessage.getId() + "0"; CsDeviceRegistry csDeviceRegistry = csDeviceRegistryFeignClient.queryByCurrentNdidAndClDid(appAutoDataMessage.getId(),appAutoDataMessage.getMsg().getClDid()).getData();
if (Objects.isNull(csDeviceRegistry)) {
if (appAutoDataMessage.getDid() == 1){
lineId = appAutoDataMessage.getId() + "0";
} else {
lineId = appAutoDataMessage.getId() + appAutoDataMessage.getMsg().getClDid();
}
} else { } else {
lineId = appAutoDataMessage.getId() + appAutoDataMessage.getMsg().getClDid(); lineId = csDeviceRegistry.getId();
} }
//获取监测点基础信息 //获取监测点基础信息
CsLinePO po = csLineFeignClient.getById(lineId).getData(); CsLinePO po = csLineFeignClient.getById(lineId).getData();
@@ -165,7 +174,7 @@ public class RtServiceImpl implements IRtService {
//根据dataArray解析数据 //根据dataArray解析数据
AppAutoDataMessage.DataArray item = appAutoDataMessage.getMsg().getDataArray().get(0); AppAutoDataMessage.DataArray item = appAutoDataMessage.getMsg().getDataArray().get(0);
Map<String,Float> map = getData(dataArrayList,item); Map<String,Float> map = getData(dataArrayList,item);
int data = Math.round(map.get("Apf_ModWorkingSts" + "M")); int data = Math.round(map.get("Apf_ModWorkingSts" + "T"));
redisUtil.saveByKeyWithExpire("ApfRtData:" + appAutoDataMessage.getMid(),data,10L); redisUtil.saveByKeyWithExpire("ApfRtData:" + appAutoDataMessage.getMid(),data,10L);
} }

View File

@@ -23,9 +23,13 @@ spring:
discovery: discovery:
ip: @service.server.url@ ip: @service.server.url@
server-addr: @nacos.url@ server-addr: @nacos.url@
username: @nacos.username@
password: @nacos.password@
namespace: @nacos.namespace@ namespace: @nacos.namespace@
config: config:
server-addr: @nacos.url@ server-addr: @nacos.url@
username: @nacos.username@
password: @nacos.password@
namespace: @nacos.namespace@ namespace: @nacos.namespace@
file-extension: yaml file-extension: yaml
shared-configs: shared-configs:
@@ -38,6 +42,7 @@ spring:
#项目日志的配置 #项目日志的配置
logging: logging:
# config: http://@nacos.url@/nacos/v1/cs/configs?tenant=@nacos.namespace@&username=@nacos.username@&password=@nacos.password@&group=DEFAULT_GROUP&dataId=logback.xml
config: http://@nacos.url@/nacos/v1/cs/configs?tenant=@nacos.namespace@&group=DEFAULT_GROUP&dataId=logback.xml config: http://@nacos.url@/nacos/v1/cs/configs?tenant=@nacos.namespace@&group=DEFAULT_GROUP&dataId=logback.xml
level: level:
root: info root: info

View File

@@ -0,0 +1,15 @@
package com.njcn.stat.dto;
import lombok.Data;
import java.io.Serializable;
/**
* @author 徐扬
*/
@Data
public class DataArrayLiteDto implements Serializable {
private String name;
private String influxDbName;
private String phase;
}

View File

@@ -21,7 +21,7 @@ public enum StatResponseEnum {
DICT_NULL("A10002","字典数据为空"), DICT_NULL("A10002","字典数据为空"),
LINE_NULL("A10002","监测点为空"), LINE_NULL("A10002","监测点为空"),
ARRAY_DATA_NOT_MATCH("A10003","上送数据与模板匹配失败"), ARRAY_DATA_NOT_MATCH("A10003","上送数据个数与模板指标个数不一致"),
; ;

View File

@@ -25,6 +25,11 @@
<groupId>com.github.tocrhz</groupId> <groupId>com.github.tocrhz</groupId>
<artifactId>mqtt-spring-boot-starter</artifactId> <artifactId>mqtt-spring-boot-starter</artifactId>
</dependency> </dependency>
<!-- caffeine 本地缓存 -->
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.njcn</groupId> <groupId>com.njcn</groupId>
<artifactId>common-web</artifactId> <artifactId>common-web</artifactId>

View File

@@ -0,0 +1,40 @@
package com.njcn.stat.listener;
import com.njcn.stat.service.IStatService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
/**
* @author 徐扬
*/
@Slf4j
@Component
public class ModelCacheClearListener implements MessageListener {
public static final String MODEL_CACHE_CLEAR_CHANNEL = "model_cache_clear";
@Resource
private RedisMessageListenerContainer redisMessageListenerContainer;
@Resource
private IStatService statService;
@PostConstruct
public void init() {
redisMessageListenerContainer.addMessageListener(this, new ChannelTopic(MODEL_CACHE_CLEAR_CHANNEL));
}
@Override
public void onMessage(Message message, byte[] pattern) {
log.info("收到模板缓存清理通知channel={}", new String(message.getChannel()));
statService.clearModelCache();
log.info("本地模板缓存已清理");
}
}

View File

@@ -1,67 +0,0 @@
//package com.njcn.stat.listener;
//
//import cn.hutool.core.collection.CollectionUtil;
//import com.njcn.common.pojo.exception.BusinessException;
//import com.njcn.redis.pojo.enums.AppRedisKey;
//import com.njcn.redis.utils.RedisUtil;
//import com.njcn.stat.enums.StatResponseEnum;
//import com.njcn.system.api.EpdFeignClient;
//import com.njcn.system.pojo.dto.EpdDTO;
//import lombok.extern.slf4j.Slf4j;
//import org.apache.commons.lang3.StringUtils;
//import org.springframework.core.annotation.Order;
//import org.springframework.data.redis.connection.Message;
//import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
//import org.springframework.data.redis.listener.RedisMessageListenerContainer;
//import org.springframework.stereotype.Component;
//
//import javax.annotation.Resource;
//import java.util.HashMap;
//import java.util.List;
//import java.util.Map;
//
///**
// * @author hongawen
// * @version 1.0.0
// * @date 2022年04月02日 14:31
// */
//@Slf4j
//@Component
//public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
//
// @Resource
// private EpdFeignClient epdFeignClient;
//
// @Resource
// private RedisUtil redisUtil;
//
// public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
// super(listenerContainer);
// }
//
//
// /**
// * 针对redis数据失效事件进行数据处理
// * 注意message.toString()可以获取失效的key
// */
// @Override
// @Order(0)
// public void onMessage(Message message, byte[] pattern) {
// if (StringUtils.isBlank(message.toString())) {
// return;
// }
// //判断失效的key
// String expiredKey = message.toString();
// if(expiredKey.equals(AppRedisKey.ELE_EPD_PQD)){
// Map<String,String> map = new HashMap<>();
// List<EpdDTO> list = epdFeignClient.findAll().getData();
// if (CollectionUtil.isEmpty(list)){
// throw new BusinessException(StatResponseEnum.DICT_NULL);
// }
// list.forEach(item->{
// map.put(item.getDictName(),item.getTableName());
// });
// redisUtil.saveByKeyWithExpire(AppRedisKey.ELE_EPD_PQD,map,3600L);
// }
// }
//}

View File

@@ -15,4 +15,5 @@ public interface IStatService {
void electricityMeterAnalysis(AppAutoDataMessage appAutoDataMessage); void electricityMeterAnalysis(AppAutoDataMessage appAutoDataMessage);
void clearModelCache();
} }

View File

@@ -3,6 +3,8 @@ package com.njcn.stat.service.impl;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DatePattern;
import com.alibaba.nacos.shaded.com.google.gson.Gson; import com.alibaba.nacos.shaded.com.google.gson.Gson;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.njcn.access.api.CsDeviceFeignClient; import com.njcn.access.api.CsDeviceFeignClient;
import com.njcn.access.api.CsLineLatestDataFeignClient; import com.njcn.access.api.CsLineLatestDataFeignClient;
import com.njcn.access.enums.AccessEnum; import com.njcn.access.enums.AccessEnum;
@@ -23,6 +25,7 @@ import com.njcn.influx.utils.InfluxDbUtils;
import com.njcn.mq.message.AppAutoDataMessage; import com.njcn.mq.message.AppAutoDataMessage;
import com.njcn.redis.pojo.enums.AppRedisKey; import com.njcn.redis.pojo.enums.AppRedisKey;
import com.njcn.redis.utils.RedisUtil; import com.njcn.redis.utils.RedisUtil;
import com.njcn.stat.dto.DataArrayLiteDto;
import com.njcn.stat.enums.StatResponseEnum; import com.njcn.stat.enums.StatResponseEnum;
import com.njcn.stat.service.IStatService; import com.njcn.stat.service.IStatService;
import com.njcn.system.enums.DicDataEnum; import com.njcn.system.enums.DicDataEnum;
@@ -63,6 +66,12 @@ public class StatServiceImpl implements IStatService {
private final DeviceMessageFeignClient deviceMessageFeignClient; private final DeviceMessageFeignClient deviceMessageFeignClient;
private final CsCommunicateFeignClient csCommunicateFeignClient; private final CsCommunicateFeignClient csCommunicateFeignClient;
// 本地缓存模板数据变更极少60分钟过期足够最大缓存50000条
private final Cache<String, List<DataArrayLiteDto>> modelCache = Caffeine.newBuilder()
.expireAfterWrite(60, TimeUnit.MINUTES)
.softValues()
.build();
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void analysis(AppAutoDataMessage appAutoDataMessage) { public void analysis(AppAutoDataMessage appAutoDataMessage) {
@@ -107,7 +116,7 @@ public class StatServiceImpl implements IStatService {
} }
//云前置设备 //云前置设备
else if (Objects.equals(DicDataEnum.DEV_CLD.getCode(),code)) { else if (Objects.equals(DicDataEnum.DEV_CLD.getCode(),code)) {
lineId = appAutoDataMessage.getId() + appAutoDataMessage.getMsg().getClDid(); lineId = new Gson().fromJson(String.valueOf(redisUtil.getObjectByKey(AppRedisKey.LINE_POSITION+appAutoDataMessage.getId())), Map.class).get(appAutoDataMessage.getMsg().getClDid().toString()).toString();
} }
//获取当前设备信息 //获取当前设备信息
@@ -115,21 +124,22 @@ public class StatServiceImpl implements IStatService {
Map<String,String> map = new Gson().fromJson(String.valueOf(redisUtil.getObjectByKey(AppRedisKey.ELE_EPD_PQD)), Map.class); Map<String,String> map = new Gson().fromJson(String.valueOf(redisUtil.getObjectByKey(AppRedisKey.ELE_EPD_PQD)), Map.class);
List<String> recordList = new ArrayList<>(); List<String> recordList = new ArrayList<>();
for (AppAutoDataMessage.DataArray item : list) { for (AppAutoDataMessage.DataArray item : list) {
log.info("{}-->处理分钟数据", po.getNdid());
switch (item.getDataAttr()) { switch (item.getDataAttr()) {
case 1: case 1:
log.info("{}-->处理最大值", po.getNdid() + appAutoDataMessage.getDid() + appAutoDataMessage.getMsg().getClDid()); //log.info("{}-->处理最大值", po.getNdid() + appAutoDataMessage.getDid() + appAutoDataMessage.getMsg().getClDid());
dataArrayParam.setStatMethod("max"); dataArrayParam.setStatMethod("max");
break; break;
case 2: case 2:
log.info("{}-->处理最小值", po.getNdid() + appAutoDataMessage.getDid() + appAutoDataMessage.getMsg().getClDid()); //log.info("{}-->处理最小值", po.getNdid() + appAutoDataMessage.getDid() + appAutoDataMessage.getMsg().getClDid());
dataArrayParam.setStatMethod("min"); dataArrayParam.setStatMethod("min");
break; break;
case 3: case 3:
log.info("{}-->处理avg", po.getNdid() + appAutoDataMessage.getDid() + appAutoDataMessage.getMsg().getClDid()); //log.info("{}-->处理avg", po.getNdid() + appAutoDataMessage.getDid() + appAutoDataMessage.getMsg().getClDid());
dataArrayParam.setStatMethod("avg"); dataArrayParam.setStatMethod("avg");
break; break;
case 4: case 4:
log.info("{}-->处理cp95", po.getNdid() + appAutoDataMessage.getDid() + appAutoDataMessage.getMsg().getClDid()); //log.info("{}-->处理cp95", po.getNdid() + appAutoDataMessage.getDid() + appAutoDataMessage.getMsg().getClDid());
dataArrayParam.setStatMethod("cp95"); dataArrayParam.setStatMethod("cp95");
break; break;
default: default:
@@ -137,15 +147,8 @@ public class StatServiceImpl implements IStatService {
} }
boolean flag = Objects.equals(DicDataEnum.DEV_CLD.getCode(), code) && Objects.equals(po.getDevAccessMethod(), "CLD"); boolean flag = Objects.equals(DicDataEnum.DEV_CLD.getCode(), code) && Objects.equals(po.getDevAccessMethod(), "CLD");
int clDid = flag?1:appAutoDataMessage.getMsg().getClDid(); int clDid = flag?1:appAutoDataMessage.getMsg().getClDid();
// String key = AppRedisKey.DEV_MODEL.concat(dataArrayParam.getId() + dataArrayParam.getDid() + clDid + dataArrayParam.getStatMethod() + dataArrayParam.getIdx());
String key = AppRedisKey.DEV_MODEL.concat(dataArrayParam.getId() + dataArrayParam.getDid() + clDid + dataArrayParam.getIdx()); String key = AppRedisKey.DEV_MODEL.concat(dataArrayParam.getId() + dataArrayParam.getDid() + clDid + dataArrayParam.getIdx());
Object object = redisUtil.getObjectByKey(key); List<DataArrayLiteDto> dataArrayList = getModelData(dataArrayParam, key);
List<CsDataArray> dataArrayList;
if (Objects.isNull(object)){
dataArrayList = saveModelData(dataArrayParam,key);
} else {
dataArrayList = objectToList(object);
}
List<String> result = assembleData(lineId,dataArrayList,item,appAutoDataMessage.getMsg().getClDid(),dataArrayParam.getStatMethod(),po.getProcess(),code,po.getDevAccessMethod(),map); List<String> result = assembleData(lineId,dataArrayList,item,appAutoDataMessage.getMsg().getClDid(),dataArrayParam.getStatMethod(),po.getProcess(),code,po.getDevAccessMethod(),map);
recordList.addAll(result); recordList.addAll(result);
//获取时间 //获取时间
@@ -176,7 +179,6 @@ public class StatServiceImpl implements IStatService {
csCommunicateFeignClient.insertion(dto); csCommunicateFeignClient.insertion(dto);
} }
} }
System.gc();
} }
@Override @Override
@@ -217,7 +219,7 @@ public class StatServiceImpl implements IStatService {
} }
//云前置设备 //云前置设备
else if (Objects.equals(DicDataEnum.DEV_CLD.getCode(),code)) { else if (Objects.equals(DicDataEnum.DEV_CLD.getCode(),code)) {
lineId = appAutoDataMessage.getId() + appAutoDataMessage.getMsg().getClDid(); lineId = new Gson().fromJson(String.valueOf(redisUtil.getObjectByKey(AppRedisKey.LINE_POSITION+appAutoDataMessage.getId())), Map.class).get(appAutoDataMessage.getMsg().getClDid().toString()).toString();
} }
//获取当前设备信息 //获取当前设备信息
@@ -229,13 +231,7 @@ public class StatServiceImpl implements IStatService {
boolean flag = Objects.equals(DicDataEnum.DEV_CLD.getCode(), code) && Objects.equals(po.getDevAccessMethod(), "CLD"); boolean flag = Objects.equals(DicDataEnum.DEV_CLD.getCode(), code) && Objects.equals(po.getDevAccessMethod(), "CLD");
int clDid = flag?1:appAutoDataMessage.getMsg().getClDid(); int clDid = flag?1:appAutoDataMessage.getMsg().getClDid();
String key = AppRedisKey.DEV_MODEL.concat(dataArrayParam.getId() + dataArrayParam.getDid() + clDid + dataArrayParam.getIdx()); String key = AppRedisKey.DEV_MODEL.concat(dataArrayParam.getId() + dataArrayParam.getDid() + clDid + dataArrayParam.getIdx());
Object object = redisUtil.getObjectByKey(key); List<DataArrayLiteDto> dataArrayList = getModelData(dataArrayParam, key);
List<CsDataArray> dataArrayList;
if (Objects.isNull(object)){
dataArrayList = saveModelData(dataArrayParam,key);
} else {
dataArrayList = objectToList(object);
}
List<String> result = assembleDdData(lineId,dataArrayList,item,appAutoDataMessage.getMsg().getClDid(),code,po.getDevAccessMethod(),map); List<String> result = assembleDdData(lineId,dataArrayList,item,appAutoDataMessage.getMsg().getClDid(),code,po.getDevAccessMethod(),map);
recordList.addAll(result); recordList.addAll(result);
//获取时间 //获取时间
@@ -266,26 +262,20 @@ public class StatServiceImpl implements IStatService {
csCommunicateFeignClient.insertion(dto); csCommunicateFeignClient.insertion(dto);
} }
} }
System.gc();
} }
/** /**
* 缓存设备模板信息 * 清理本地模板缓存由Redis Pub/Sub通知触发
*/ */
public List<CsDataArray> saveModelData(DataArrayParam dataArrayParam,String key) { @Override
List<CsDataArray> dataArrayList = dataArrayFeignClient.findListByParam(dataArrayParam).getData(); public void clearModelCache() {
if (CollectionUtil.isEmpty(dataArrayList)){ modelCache.invalidateAll();
throw new BusinessException(StatResponseEnum.DATA_ARRAY_NULL);
}
redisUtil.saveByKey(key,dataArrayList);
return dataArrayList;
} }
/** /**
* influxDB数据组装 * influxDB数据组装
*/ */
public List<String> assembleData(String lineId,List<CsDataArray> dataArrayList,AppAutoDataMessage.DataArray item,Integer clDid,String statMethod,Integer process,String devType,String accessMethod, Map<String,String> map) { public List<String> assembleData(String lineId,List<DataArrayLiteDto> dataArrayList,AppAutoDataMessage.DataArray item,Integer clDid,String statMethod,Integer process,String devType,String accessMethod, Map<String,String> map) {
List<String> records = new ArrayList<String>(); List<String> records = new ArrayList<String>();
List<Float> floats = PubUtils.byteArrayToFloatList(Base64.getDecoder().decode(item.getData())); List<Float> floats = PubUtils.byteArrayToFloatList(Base64.getDecoder().decode(item.getData()));
if (CollectionUtil.isEmpty(floats)){ if (CollectionUtil.isEmpty(floats)){
@@ -345,7 +335,7 @@ public class StatServiceImpl implements IStatService {
* 电度influxDB数据组装 * 电度influxDB数据组装
* 电度数据15分钟入库一次 * 电度数据15分钟入库一次
*/ */
public List<String> assembleDdData(String lineId,List<CsDataArray> dataArrayList,AppAutoDataMessage.DataArray item,Integer clDid,String devType,String accessMethod, Map<String,String> map) { public List<String> assembleDdData(String lineId,List<DataArrayLiteDto> dataArrayList,AppAutoDataMessage.DataArray item,Integer clDid,String devType,String accessMethod, Map<String,String> map) {
List<String> records = new ArrayList<String>(); List<String> records = new ArrayList<String>();
List<Float> floats = PubUtils.byteArrayToFloatList(Base64.getDecoder().decode(item.getData())); List<Float> floats = PubUtils.byteArrayToFloatList(Base64.getDecoder().decode(item.getData()));
if (CollectionUtil.isEmpty(floats)){ if (CollectionUtil.isEmpty(floats)){
@@ -386,16 +376,25 @@ public class StatServiceImpl implements IStatService {
return records; return records;
} }
public List<CsDataArray> objectToList(Object object) { public List<DataArrayLiteDto> getModelData(DataArrayParam dataArrayParam, String key) {
List<CsDataArray> urlList = new ArrayList<>(); List<DataArrayLiteDto> result = new ArrayList<>();
if (object != null) { List<DataArrayLiteDto> dataArrayList = modelCache.getIfPresent(key);
if (object instanceof ArrayList<?>) { if (CollectionUtil.isEmpty(dataArrayList)) {
for (Object o : (List<?>) object) { List<CsDataArray> data = dataArrayFeignClient.findListByParam(dataArrayParam).getData();
urlList.add((CsDataArray) o); if (CollectionUtil.isEmpty(data)){
} throw new BusinessException(StatResponseEnum.DATA_ARRAY_NULL);
} else {
data.forEach(item->{
DataArrayLiteDto dataArrayLiteDto = new DataArrayLiteDto();
dataArrayLiteDto.setName(item.getName());
dataArrayLiteDto.setInfluxDbName(item.getInfluxDbName());
dataArrayLiteDto.setPhase(item.getPhase());
result.add(dataArrayLiteDto);
});
} }
modelCache.put(key, result);
} }
return urlList; return dataArrayList;
} }
} }

View File

@@ -23,9 +23,13 @@ spring:
discovery: discovery:
ip: @service.server.url@ ip: @service.server.url@
server-addr: @nacos.url@ server-addr: @nacos.url@
username: @nacos.username@
password: @nacos.password@
namespace: @nacos.namespace@ namespace: @nacos.namespace@
config: config:
server-addr: @nacos.url@ server-addr: @nacos.url@
username: @nacos.username@
password: @nacos.password@
namespace: @nacos.namespace@ namespace: @nacos.namespace@
file-extension: yaml file-extension: yaml
shared-configs: shared-configs:
@@ -38,6 +42,7 @@ spring:
#项目日志的配置 #项目日志的配置
logging: logging:
# config: http://@nacos.url@/nacos/v1/cs/configs?tenant=@nacos.namespace@&username=@nacos.username@&password=@nacos.password@&group=DEFAULT_GROUP&dataId=logback.xml
config: http://@nacos.url@/nacos/v1/cs/configs?tenant=@nacos.namespace@&group=DEFAULT_GROUP&dataId=logback.xml config: http://@nacos.url@/nacos/v1/cs/configs?tenant=@nacos.namespace@&group=DEFAULT_GROUP&dataId=logback.xml
level: level:
root: info root: info

View File

@@ -41,9 +41,29 @@ public interface ZlConstant {
*/ */
String EVT_PARAM_TM = "Evt_Param_Tm"; String EVT_PARAM_TM = "Evt_Param_Tm";
/**
* 相别
*/
String EVT_PARAM_PHASE = "Evt_Param_Phase";
/** /**
* 幅值 * 幅值
*/ */
String EVT_PARAM_VVADEPTH = "Evt_Param_VVaDepth"; String EVT_PARAM_VVADEPTH = "Evt_Param_VVaDepth";
/**
* 暂降源与监测位置关系 0-未知、1-上游、2-下游
*/
String SAG_SOURCE = "Evt_Param_QvvrPos";
/**
* 瞬态-有效值
*/
String EVT_PARAM_RMS = "Evt_Param_Rms";
/**
* 瞬态-电压变化
*/
String EVT_PARAM_UCHG = "Evt_Param_UCHG";
} }

View File

@@ -5,10 +5,14 @@ import com.njcn.access.utils.ChannelObjectUtil;
import com.njcn.access.utils.FileCommonUtils; import com.njcn.access.utils.FileCommonUtils;
import com.njcn.access.utils.MqttUtil; import com.njcn.access.utils.MqttUtil;
import com.njcn.common.pojo.exception.BusinessException; import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.csdevice.api.CsDeviceRegistryFeignClient;
import com.njcn.csdevice.api.CsLineFeignClient;
import com.njcn.csdevice.api.DeviceMessageFeignClient; import com.njcn.csdevice.api.DeviceMessageFeignClient;
import com.njcn.csdevice.api.EquipmentFeignClient; import com.njcn.csdevice.api.EquipmentFeignClient;
import com.njcn.csdevice.enums.AlgorithmResponseEnum; import com.njcn.csdevice.enums.AlgorithmResponseEnum;
import com.njcn.csdevice.param.LineInfoParam; import com.njcn.csdevice.param.LineInfoParam;
import com.njcn.csdevice.pojo.po.CsDeviceRegistry;
import com.njcn.csdevice.pojo.po.CsLinePO;
import com.njcn.mq.message.AppEventMessage; import com.njcn.mq.message.AppEventMessage;
import com.njcn.redis.pojo.enums.AppRedisKey; import com.njcn.redis.pojo.enums.AppRedisKey;
import com.njcn.redis.utils.RedisUtil; import com.njcn.redis.utils.RedisUtil;
@@ -45,6 +49,8 @@ public class CsWaveAnalysisServiceImpl implements ICsWaveAnalysisService {
private final FileCommonUtils fileCommonUtils; private final FileCommonUtils fileCommonUtils;
private final DeviceMessageFeignClient deviceMessageFeignClient; private final DeviceMessageFeignClient deviceMessageFeignClient;
private static Integer mid = 1; private static Integer mid = 1;
private final CsDeviceRegistryFeignClient csDeviceRegistryFeignClient;
private final CsLineFeignClient csLineFeignClient;
@Override @Override
public void analysis(AppEventMessage appEventMessage) { public void analysis(AppEventMessage appEventMessage) {
@@ -58,6 +64,24 @@ public class CsWaveAnalysisServiceImpl implements ICsWaveAnalysisService {
} }
//获取装置id //获取装置id
String deviceId = equipmentFeignClient.findDevByNDid(appEventMessage.getId()).getData().getId(); String deviceId = equipmentFeignClient.findDevByNDid(appEventMessage.getId()).getData().getId();
//获取监测点id
String nDid = appEventMessage.getId();
Integer clDid = appEventMessage.getMsg().getClDid();
CsDeviceRegistry csDeviceRegistry = csDeviceRegistryFeignClient.queryByCurrentNdidAndClDid(nDid, clDid).getData();
String lineId;
if (Objects.isNull(csDeviceRegistry)) {
List<CsLinePO> lines = csLineFeignClient.findByNdid(nDid).getData();
if (CollectionUtil.isEmpty(lines)) {
throw new BusinessException("通过装置NDID获取监测点信息失败");
}
CsLinePO line = lines.stream().filter(item->Objects.equals(item.getClDid(),clDid)).findFirst().orElse(null);
if (Objects.isNull(line)) {
throw new BusinessException("通过逻辑子设备ID获取监测点信息失败");
}
lineId = line.getLineId();
} else {
lineId = csDeviceRegistry.getId();
}
//获取波形文件名称 //获取波形文件名称
List<AppEventMessage.DataArray> dataArrayList = appEventMessage.getMsg().getDataArray(); List<AppEventMessage.DataArray> dataArrayList = appEventMessage.getMsg().getDataArray();
if (CollectionUtil.isNotEmpty(dataArrayList)){ if (CollectionUtil.isNotEmpty(dataArrayList)){
@@ -66,7 +90,6 @@ public class CsWaveAnalysisServiceImpl implements ICsWaveAnalysisService {
Object object = paramList.stream().filter(item2 -> ZlConstant.WAVE_NAME.equals(item2.getName())).findFirst().map(AppEventMessage.Param::getData).orElse(null); Object object = paramList.stream().filter(item2 -> ZlConstant.WAVE_NAME.equals(item2.getName())).findFirst().map(AppEventMessage.Param::getData).orElse(null);
Object object2 = paramList.stream().filter(item2 -> ZlConstant.WAVE_PARAM_RCDKEEPTIME.equals(item2.getName())).findFirst().map(AppEventMessage.Param::getData).orElse(null); Object object2 = paramList.stream().filter(item2 -> ZlConstant.WAVE_PARAM_RCDKEEPTIME.equals(item2.getName())).findFirst().map(AppEventMessage.Param::getData).orElse(null);
Object object3 = paramList.stream().filter(item2->ZlConstant.WAVE_POSITION.equals(item2.getName())).findFirst().map(AppEventMessage.Param::getData).orElse(null); Object object3 = paramList.stream().filter(item2->ZlConstant.WAVE_POSITION.equals(item2.getName())).findFirst().map(AppEventMessage.Param::getData).orElse(null);
String lineId = appEventMessage.getId() + appEventMessage.getMsg().getClDid();
String fileName = object.toString().replaceAll("\\[","").replaceAll("]",""); String fileName = object.toString().replaceAll("\\[","").replaceAll("]","");
List<String> fileList = Arrays.stream(fileName.split(",")).collect(Collectors.toList()); List<String> fileList = Arrays.stream(fileName.split(",")).collect(Collectors.toList());
//获取到录波文件,将文件信息存储起来 //获取到录波文件,将文件信息存储起来

View File

@@ -37,10 +37,8 @@ import com.njcn.system.enums.DicDataEnum;
import com.njcn.system.pojo.dto.EpdDTO; import com.njcn.system.pojo.dto.EpdDTO;
import com.njcn.system.pojo.po.DictData; import com.njcn.system.pojo.po.DictData;
import com.njcn.zlevent.pojo.constant.ZlConstant; import com.njcn.zlevent.pojo.constant.ZlConstant;
//import com.njcn.zlevent.service.AppNotificationService;
import com.njcn.zlevent.service.ICsEventService; import com.njcn.zlevent.service.ICsEventService;
import com.njcn.zlevent.service.IEventService; import com.njcn.zlevent.service.IEventService;
//import com.njcn.zlevent.service.SmsNotificationService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.influxdb.InfluxDB; import org.influxdb.InfluxDB;
@@ -51,6 +49,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.time.Instant; import java.time.Instant;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@@ -83,8 +82,6 @@ public class EventServiceImpl implements IEventService {
private final WlRmpEventDetailMapper wlRmpEventDetailMapper; private final WlRmpEventDetailMapper wlRmpEventDetailMapper;
private final DictTreeFeignClient dictTreeFeignClient; private final DictTreeFeignClient dictTreeFeignClient;
private final DeviceMessageFeignClient deviceMessageFeignClient; private final DeviceMessageFeignClient deviceMessageFeignClient;
// private final AppNotificationService appNotificationService;
// private final SmsNotificationService smsNotificationService;
private final EventAnalysisService eventAnalysisService; private final EventAnalysisService eventAnalysisService;
private final MsgSendFeignClient msgSendFeignClient; private final MsgSendFeignClient msgSendFeignClient;
@@ -176,12 +173,15 @@ public class EventServiceImpl implements IEventService {
if (Objects.equals(param.getName(),ZlConstant.EVT_PARAM_TM)){ if (Objects.equals(param.getName(),ZlConstant.EVT_PARAM_TM)){
csEvent.setPersistTime(Double.parseDouble(param.getData().toString())); csEvent.setPersistTime(Double.parseDouble(param.getData().toString()));
} }
if (Objects.equals(param.getName(),ZlConstant.EVT_PARAM_VVADEPTH)) { if (Objects.equals(param.getName(),ZlConstant.EVT_PARAM_VVADEPTH) || Objects.equals(param.getName(),ZlConstant.EVT_PARAM_RMS)) {
csEvent.setAmplitude(Double.parseDouble(param.getData().toString())); csEvent.setAmplitude(Double.parseDouble(param.getData().toString()));
} }
if (Objects.equals(param.getName(),"Evt_Param_Phase")) { if (Objects.equals(param.getName(),ZlConstant.EVT_PARAM_PHASE)) {
csEvent.setPhase(param.getData().toString()); csEvent.setPhase(param.getData().toString());
} }
if (Objects.equals(param.getName(),ZlConstant.SAG_SOURCE)) {
csEvent.setSagSource(param.getData().toString());
}
fields.put(param.getName(),param.getData()); fields.put(param.getName(),param.getData());
} }
//只有治理型号的设备有监测位置 //只有治理型号的设备有监测位置
@@ -194,7 +194,13 @@ public class EventServiceImpl implements IEventService {
csEvent.setLocation("load"); csEvent.setLocation("load");
} }
} }
String dropZone = eventAnalysisService.determineDropZone(String.valueOf(csEvent.getAmplitude()),String.valueOf(csEvent.getPersistTime())); String dropZone = null;
if (!Objects.isNull(csEvent.getAmplitude()) && !Objects.isNull(csEvent.getPersistTime())) {
dropZone = eventAnalysisService.determineDropZone(String.valueOf(csEvent.getAmplitude()),String.valueOf(csEvent.getPersistTime()));
if (Objects.equals(tag,"Evt_Sys_DipStr")) {
csEvent.setSeverity(Double.valueOf(getYzd(csEvent.getPersistTime()*1000,csEvent.getAmplitude()/100)));
}
}
csEvent.setLandPoint(dropZone); csEvent.setLandPoint(dropZone);
AppEventMessage.Param param = new AppEventMessage.Param(); AppEventMessage.Param param = new AppEventMessage.Param();
param.setName("Evt_Param_DropZone"); param.setName("Evt_Param_DropZone");
@@ -252,7 +258,6 @@ public class EventServiceImpl implements IEventService {
msgSendParam.setAmplitude(amplitude); msgSendParam.setAmplitude(amplitude);
msgSendParam.setPersistTime(persistTime); msgSendParam.setPersistTime(persistTime);
msgSendParam.setDropZone(dropZone); msgSendParam.setDropZone(dropZone);
// appNotificationService.sendAppNotification(1, item.getType(), po.getId(), item.getName(), eventTime, id, po.getNdid(),amplitude,persistTime,dropZone);
msgSendFeignClient.appMsgSend(msgSendParam); msgSendFeignClient.appMsgSend(msgSendParam);
//如果是暂降事件,则异步发送短信 //如果是暂降事件,则异步发送短信
if (Objects.equals(item.getName(), "Evt_Sys_DipStr")) { if (Objects.equals(item.getName(), "Evt_Sys_DipStr")) {
@@ -263,7 +268,6 @@ public class EventServiceImpl implements IEventService {
msgSendParam2.setPersistTime(persistTime); msgSendParam2.setPersistTime(persistTime);
msgSendParam2.setDropZone(dropZone); msgSendParam2.setDropZone(dropZone);
msgSendFeignClient.smsMsgSend(msgSendParam2); msgSendFeignClient.smsMsgSend(msgSendParam2);
// smsNotificationService.sendSmsForDipEvent(po.getId(), eventTime,amplitude,persistTime,dropZone);
} }
} }
} }
@@ -272,6 +276,30 @@ public class EventServiceImpl implements IEventService {
} }
} }
/**
* 获取该事件的严重度
*
* @param persistTime 持续时间 ms单位
* @param eventValue 暂降、暂升幅值
*/
public String getYzd(Double persistTime, Double eventValue) {
Double yzd;
// 格式化小数
DecimalFormat df = new DecimalFormat("0.000");
if (persistTime <= 20) {
yzd = 1.0 - eventValue;
} else if (persistTime > 20 && persistTime <= 200) {
yzd = 2.0 * (1 - eventValue);
} else if (persistTime > 200 && persistTime <= 500) {
yzd = 3.3 * (1 - eventValue);
} else if (persistTime > 500 && persistTime <= 10000) {
yzd = 5.0 * (1 - eventValue);
} else {
yzd = 10.0 * (1 - eventValue);
}
return df.format(yzd);
}
public void insertEvent(CsEventPO item) { public void insertEvent(CsEventPO item) {
RmpEventDetailPO rmpEventDetailPo = new RmpEventDetailPO(); RmpEventDetailPO rmpEventDetailPo = new RmpEventDetailPO();
rmpEventDetailPo.setEventId(item.getId()); rmpEventDetailPo.setEventId(item.getId());
@@ -284,9 +312,26 @@ public class EventServiceImpl implements IEventService {
rmpEventDetailPo.setDealFlag(0); rmpEventDetailPo.setDealFlag(0);
rmpEventDetailPo.setFileFlag(0); rmpEventDetailPo.setFileFlag(0);
rmpEventDetailPo.setPhase(item.getPhase()); rmpEventDetailPo.setPhase(item.getPhase());
rmpEventDetailPo.setSagsource(getSagSource(item.getSagSource()));
rmpEventDetailPo.setSeverity(item.getSeverity());
wlRmpEventDetailMapper.insert(rmpEventDetailPo); wlRmpEventDetailMapper.insert(rmpEventDetailPo);
} }
public String getSagSource(String tag) {
switch (tag) {
case "1":
tag = "Upper";
break;
case "2":
tag = "Lower";
break;
default:
tag = "Unknown";
break;
}
return tag;
}
public String getEventType(String tag) { public String getEventType(String tag) {
switch (tag) { switch (tag) {
case "Evt_Sys_DipStr": case "Evt_Sys_DipStr":
@@ -392,7 +437,7 @@ public class EventServiceImpl implements IEventService {
//前置告警 //前置告警
if (Objects.equals(cldLogMessage.getLevel(),"process")) { if (Objects.equals(cldLogMessage.getLevel(),"process")) {
//这边将前置服务器id当作设备id //这边将前置服务器id当作设备id
po.setDeviceId(cldLogMessage.getNodeId()); po.setDeviceId(cldLogMessage.getNodeId());
po.setClDid(Integer.valueOf(cldLogMessage.getProcessNo())); po.setClDid(Integer.valueOf(cldLogMessage.getProcessNo()));
po.setType(4); po.setType(4);
} }
@@ -401,9 +446,11 @@ public class EventServiceImpl implements IEventService {
if (Objects.equals(cldLogMessage.getLevel(),"terminal")) { if (Objects.equals(cldLogMessage.getLevel(),"terminal")) {
po.setDeviceId(cldLogMessage.getBusinessId()); po.setDeviceId(cldLogMessage.getBusinessId());
} else { } else {
CsLinePO line = csLineFeignClient.getById(cldLogMessage.getBusinessId()).getData(); if (!Objects.isNull(cldLogMessage.getBusinessId()) && !Objects.equals(cldLogMessage.getBusinessId(),"")) {
po.setDeviceId(line.getDeviceId()); CsLinePO line = csLineFeignClient.getById(cldLogMessage.getBusinessId()).getData();
po.setLineId(cldLogMessage.getBusinessId()); po.setDeviceId(line.getDeviceId());
po.setLineId(cldLogMessage.getBusinessId());
}
} }
po.setType(3); po.setType(3);
} }

View File

@@ -23,9 +23,13 @@ spring:
discovery: discovery:
ip: @service.server.url@ ip: @service.server.url@
server-addr: @nacos.url@ server-addr: @nacos.url@
username: @nacos.username@
password: @nacos.password@
namespace: @nacos.namespace@ namespace: @nacos.namespace@
config: config:
server-addr: @nacos.url@ server-addr: @nacos.url@
username: @nacos.username@
password: @nacos.password@
namespace: @nacos.namespace@ namespace: @nacos.namespace@
file-extension: yaml file-extension: yaml
shared-configs: shared-configs:
@@ -38,6 +42,7 @@ spring:
#项目日志的配置 #项目日志的配置
logging: logging:
# config: http://@nacos.url@/nacos/v1/cs/configs?tenant=@nacos.namespace@&username=@nacos.username@&password=@nacos.password@&group=DEFAULT_GROUP&dataId=logback.xml
config: http://@nacos.url@/nacos/v1/cs/configs?tenant=@nacos.namespace@&group=DEFAULT_GROUP&dataId=logback.xml config: http://@nacos.url@/nacos/v1/cs/configs?tenant=@nacos.namespace@&group=DEFAULT_GROUP&dataId=logback.xml
level: level:
root: info root: info

View File

@@ -20,6 +20,11 @@
</properties> </properties>
<dependencies> <dependencies>
<dependency>
<groupId>com.njcn</groupId>
<artifactId>cs-system-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.njcn</groupId> <groupId>com.njcn</groupId>
<artifactId>common-web</artifactId> <artifactId>common-web</artifactId>

View File

@@ -0,0 +1,138 @@
package com.njcn.message.consumer;
import com.njcn.common.pojo.dto.DeviceLogDTO;
import com.njcn.cssystem.api.CsLogsFeignClient;
import com.njcn.middle.rocket.constant.EnhanceMessageConstant;
import com.njcn.middle.rocket.handler.EnhanceConsumerMessageHandler;
import com.njcn.mq.constant.BusinessTopic;
import com.njcn.mq.constant.MessageStatus;
import com.njcn.mq.message.LogMessage;
import com.njcn.redis.pojo.enums.AppRedisKey;
import com.njcn.redis.pojo.enums.RedisKeyEnum;
import com.njcn.redis.utils.RedisUtil;
import com.njcn.system.api.RocketMqLogFeignClient;
import com.njcn.system.pojo.po.RocketmqMsgErrorLog;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Objects;
/**
* 类的介绍:
*
* @author xuyang
* @version 1.0.0
* @createTime 2023/8/11 15:32
*/
@Service
@RocketMQMessageListener(
topic = BusinessTopic.ZL_LOG_TOPIC,
consumerGroup = BusinessTopic.ZL_LOG_TOPIC,
selectorExpression = BusinessTopic.LogTag.LOG_TAG,
consumeThreadNumber = 10,
enableMsgTrace = true
)
@Slf4j
public class LogConsumer extends EnhanceConsumerMessageHandler<LogMessage> implements RocketMQListener<LogMessage> {
@Resource
private RedisUtil redisUtil;
@Resource
private RocketMqLogFeignClient rocketMqLogFeignClient;
@Resource
private CsLogsFeignClient csLogsFeignClient;
@Override
protected void handleMessage(LogMessage logMessage) {
DeviceLogDTO deviceLogDTO = new DeviceLogDTO();
BeanUtils.copyProperties(logMessage,deviceLogDTO);
csLogsFeignClient.addUserLog(deviceLogDTO);
}
/***
* 通过redis分布式锁判断当前消息所处状态
* 1、null 查不到该key的数据属于第一次消费放行
* 2、fail 上次消息消费时发生异常,放行
* 3、being processed 正在处理,打回去
* 4、success 最近72小时消费成功避免重复消费打回去
*/
@Override
public boolean filter(LogMessage message) {
String keyStatus = redisUtil.getStringByKey(AppRedisKey.RMQ_CONSUME_KEY.concat(message.getKey()));
if (Objects.isNull(keyStatus) || keyStatus.equalsIgnoreCase(MessageStatus.FAIL)) {
redisUtil.saveByKeyWithExpire(AppRedisKey.RMQ_CONSUME_KEY.concat(message.getKey()), MessageStatus.BEING_PROCESSED, 60L);
return false;
}
return true;
}
/**
* 消费成功缓存到redis 5分钟避免重复消费
*/
@Override
protected void consumeSuccess(LogMessage message) {
redisUtil.saveByKeyWithExpire(AppRedisKey.RMQ_CONSUME_KEY.concat(message.getKey()), MessageStatus.SUCCESS, 5 * 60L);
}
/**
* 发生异常时,进行错误信息入库保存
* 默认没有实现类子类可以实现该方法调用feign接口进行入库保存
*/
@Override
protected void saveExceptionMsgLog(LogMessage message, String identity, Exception exception) {
redisUtil.saveByKeyWithExpire(AppRedisKey.RMQ_CONSUME_KEY.concat(message.getKey()), MessageStatus.FAIL, RedisKeyEnum.ROCKET_MQ_KEY.getTime());
RocketmqMsgErrorLog rocketmqMsgErrorLog = new RocketmqMsgErrorLog();
rocketmqMsgErrorLog.setMsgKey(message.getKey());
rocketmqMsgErrorLog.setResource(message.getSource());
if (identity.equalsIgnoreCase(EnhanceMessageConstant.IDENTITY_SINGLE)) {
//数据库字段配置长度200避免插入失败大致分析异常原因
String exceptionMsg = exception.getMessage();
if(exceptionMsg.length() > 200){
exceptionMsg = exceptionMsg.substring(0,180);
}
rocketmqMsgErrorLog.setRecord(exceptionMsg);
//如果是当前消息重试的则略过
if(!message.getSource().startsWith(EnhanceMessageConstant.RETRY_PREFIX)){
//单次消费异常
rocketMqLogFeignClient.add(rocketmqMsgErrorLog);
}
} else {
rocketmqMsgErrorLog.setRecord("重试消费" + super.getMaxRetryTimes() + "次,依旧消费失败。");
//重试N次后依然消费异常
rocketMqLogFeignClient.add(rocketmqMsgErrorLog);
}
}
/***
* 处理失败后,是否重试
* 一般开启
*/
@Override
protected boolean isRetry() {
return true;
}
/***
* 消费失败是否抛出异常,抛出异常后就不再消费了
*/
@Override
protected boolean throwException() {
return false;
}
/***
* 调用父类handler处理消息的元信息
*/
@Override
public void onMessage(LogMessage appAutoDataMessage) {
super.dispatchMessage(appAutoDataMessage);
}
}

View File

@@ -47,8 +47,6 @@ public class RealDataConsumer extends EnhanceConsumerMessageHandler<AppAutoDataM
@Override @Override
protected void handleMessage(AppAutoDataMessage appAutoDataMessage) { protected void handleMessage(AppAutoDataMessage appAutoDataMessage) {
log.info("分发至实时数据"); log.info("分发至实时数据");
String lineId = appAutoDataMessage.getId() + appAutoDataMessage.getMsg().getClDid();
redisUtil.saveByKeyWithExpire("devResponse:" + lineId,200,5L);
rtFeignClient.analysis(appAutoDataMessage); rtFeignClient.analysis(appAutoDataMessage);
} }

View File

@@ -23,9 +23,13 @@ spring:
discovery: discovery:
ip: @service.server.url@ ip: @service.server.url@
server-addr: @nacos.url@ server-addr: @nacos.url@
username: @nacos.username@
password: @nacos.password@
namespace: @nacos.namespace@ namespace: @nacos.namespace@
config: config:
server-addr: @nacos.url@ server-addr: @nacos.url@
username: @nacos.username@
password: @nacos.password@
namespace: @nacos.namespace@ namespace: @nacos.namespace@
file-extension: yaml file-extension: yaml
shared-configs: shared-configs:
@@ -39,6 +43,7 @@ spring:
#项目日志的配置 #项目日志的配置
logging: logging:
# config: http://@nacos.url@/nacos/v1/cs/configs?tenant=@nacos.namespace@&username=@nacos.username@&password=@nacos.password@&group=DEFAULT_GROUP&dataId=logback.xml
config: http://@nacos.url@/nacos/v1/cs/configs?tenant=@nacos.namespace@&group=DEFAULT_GROUP&dataId=logback.xml config: http://@nacos.url@/nacos/v1/cs/configs?tenant=@nacos.namespace@&group=DEFAULT_GROUP&dataId=logback.xml
level: level:
root: info root: info

20
pom.xml
View File

@@ -32,6 +32,13 @@
<properties> <properties>
<!--李凡测试环境-->
<!-- <middle.server.url>192.168.2.134</middle.server.url>-->
<!-- <service.server.url>192.168.2.134</service.server.url>-->
<!-- <docker.server.url>192.168.2.134</docker.server.url>-->
<!-- <nacos.url>${middle.server.url}:18848</nacos.url>-->
<!-- <nacos.namespace></nacos.namespace>-->
<!--103本地--> <!--103本地-->
<!-- <middle.server.url>192.168.1.103</middle.server.url>--> <!-- <middle.server.url>192.168.1.103</middle.server.url>-->
<!-- <service.server.url>192.168.2.126</service.server.url>--> <!-- <service.server.url>192.168.2.126</service.server.url>-->
@@ -52,6 +59,12 @@
<nacos.url>${middle.server.url}:18848</nacos.url> <nacos.url>${middle.server.url}:18848</nacos.url>
<nacos.namespace></nacos.namespace> <nacos.namespace></nacos.namespace>
<!-- <middle.server.url>192.168.1.103</middle.server.url>-->
<!-- <service.server.url>192.168.2.126</service.server.url>-->
<!-- <docker.server.url>192.168.1.103</docker.server.url>-->
<!-- <nacos.url>${middle.server.url}:18848</nacos.url>-->
<!-- <nacos.namespace></nacos.namespace>-->
<!-- <middle.server.url>192.168.1.22</middle.server.url>--> <!-- <middle.server.url>192.168.1.22</middle.server.url>-->
<!-- <service.server.url>192.168.1.126</service.server.url>--> <!-- <service.server.url>192.168.1.126</service.server.url>-->
<!-- <docker.server.url>192.168.1.22</docker.server.url>--> <!-- <docker.server.url>192.168.1.22</docker.server.url>-->
@@ -149,6 +162,7 @@
<minio.version>8.2.1</minio.version> <minio.version>8.2.1</minio.version>
<spring-cloud-huawei.version>1.7.0-Hoxton</spring-cloud-huawei.version> <spring-cloud-huawei.version>1.7.0-Hoxton</spring-cloud-huawei.version>
<kafka.version>2.9.6</kafka.version> <kafka.version>2.9.6</kafka.version>
<caffeine.version>2.9.3</caffeine.version>
</properties> </properties>
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
@@ -396,6 +410,12 @@
<artifactId>spring-kafka</artifactId> <artifactId>spring-kafka</artifactId>
<version>${kafka.version}</version> <version>${kafka.version}</version>
</dependency> </dependency>
<!-- caffeine 本地缓存 -->
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>${caffeine.version}</version>
</dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>