diff --git a/das/pom.xml b/das/pom.xml index aea4ba76..6666105e 100644 --- a/das/pom.xml +++ b/das/pom.xml @@ -32,7 +32,6 @@ 3.4.4 5.4.3 8.4.3 - 1.5.3 @@ -217,11 +216,6 @@ minio ${minio.version} - - org.jfree - jfreechart - ${jfreechart.version} - diff --git a/das/src/main/java/com/das/modules/cache/domain/DeviceInfoCache.java b/das/src/main/java/com/das/modules/cache/domain/DeviceInfoCache.java index 892f7f9b..60e1f351 100644 --- a/das/src/main/java/com/das/modules/cache/domain/DeviceInfoCache.java +++ b/das/src/main/java/com/das/modules/cache/domain/DeviceInfoCache.java @@ -34,6 +34,8 @@ public class DeviceInfoCache { */ private Long iotModelId; + private String iotModelCode; + /** * 制造商 */ diff --git a/das/src/main/java/com/das/modules/cache/domain/IotFieldInfoCache.java b/das/src/main/java/com/das/modules/cache/domain/IotFieldInfoCache.java index 5aa11e2e..a815a885 100644 --- a/das/src/main/java/com/das/modules/cache/domain/IotFieldInfoCache.java +++ b/das/src/main/java/com/das/modules/cache/domain/IotFieldInfoCache.java @@ -1,5 +1,6 @@ package com.das.modules.cache.domain; +import com.baomidou.mybatisplus.annotation.TableField; import lombok.Data; @Data @@ -10,6 +11,8 @@ public class IotFieldInfoCache { private Integer porder; private Integer highspeed; private String datatype; + private Integer level; + private String stateDesc; public boolean isHighSpeed() { return highspeed.equals(1) && attributeType.equals(138); diff --git a/das/src/main/java/com/das/modules/cache/service/IotModelCache.java b/das/src/main/java/com/das/modules/cache/service/IotModelCache.java index 315538f3..0bc32e6d 100644 --- a/das/src/main/java/com/das/modules/cache/service/IotModelCache.java +++ b/das/src/main/java/com/das/modules/cache/service/IotModelCache.java @@ -1,7 +1,16 @@ package com.das.modules.cache.service; +import com.das.modules.cache.domain.IotFieldInfoCache; +import com.das.modules.equipment.entity.SysIotModel; +import com.das.modules.equipment.entity.SysIotModelField; + public interface IotModelCache { public boolean isHighSpeed(Long modelId, String attr); public boolean isLowSpeed(Long modelId, String attr); public boolean isCalculate(Long modelId, String attr); + void refreshIotFieldCache(SysIotModelField sysIotModelField); + void removeIotFieldCache(Long modelId, String attributeCode); + void refreshIotModelInfoIdMap(SysIotModel sysIotModel); + void removeIotModelInfoIdMap(Long modelId); + IotFieldInfoCache getIotFiledCache(Long modelId,String attr); } diff --git a/das/src/main/java/com/das/modules/cache/service/impl/EquipmentCacheImpl.java b/das/src/main/java/com/das/modules/cache/service/impl/EquipmentCacheImpl.java index 6426fa40..0812d2b1 100644 --- a/das/src/main/java/com/das/modules/cache/service/impl/EquipmentCacheImpl.java +++ b/das/src/main/java/com/das/modules/cache/service/impl/EquipmentCacheImpl.java @@ -1,11 +1,14 @@ package com.das.modules.cache.service.impl; +import cn.hutool.core.util.StrUtil; import com.das.modules.cache.domain.DeviceInfoCache; import com.das.modules.cache.service.EquipmentCache; import com.das.modules.equipment.entity.SysEquipment; import com.das.modules.equipment.mapper.SysEquipmentMapper; +import com.das.modules.equipment.mapper.SysIotModelMapper; import jakarta.annotation.PostConstruct; import jakarta.annotation.PreDestroy; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -14,11 +17,13 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.ConcurrentHashMap; +@Slf4j @Service public class EquipmentCacheImpl implements EquipmentCache { @Autowired SysEquipmentMapper sysEquipmentMapper; - + @Autowired + SysIotModelMapper sysIotModelMapper; /** * 设备CODE索引,用于通过设备CODE访问设备缓存信息 @@ -43,6 +48,12 @@ public class EquipmentCacheImpl implements EquipmentCache { deviceInfoCache.setMadeinFactory(equipment.getMadeinFactory()); deviceInfoCache.setParentDeviceId(equipment.getParentEquipmentId()); deviceInfoCache.setIotModelId(equipment.getIotModelId()); + String iotModelCode = sysIotModelMapper.getIodModelCode(equipment.getIotModelId()); + log.debug("iotModelId: {}", equipment.getIotModelId()); + if (StrUtil.isNotBlank(iotModelCode)){ + log.debug("iotModelCode: {}", iotModelCode); + deviceInfoCache.setIotModelCode(iotModelCode); + } //创建Code索引 deviceCodeIndex.put(deviceInfoCache.getDeviceCode(),deviceInfoCache); //创建Id索引 diff --git a/das/src/main/java/com/das/modules/cache/service/impl/IotModelCacheImpl.java b/das/src/main/java/com/das/modules/cache/service/impl/IotModelCacheImpl.java index fa302467..449fb3fe 100644 --- a/das/src/main/java/com/das/modules/cache/service/impl/IotModelCacheImpl.java +++ b/das/src/main/java/com/das/modules/cache/service/impl/IotModelCacheImpl.java @@ -3,6 +3,8 @@ package com.das.modules.cache.service.impl; import com.das.modules.cache.domain.IotFieldInfoCache; import com.das.modules.cache.domain.IotModelInfoCache; import com.das.modules.cache.service.IotModelCache; +import com.das.modules.equipment.entity.SysIotModel; +import com.das.modules.equipment.entity.SysIotModelField; import com.das.modules.equipment.mapper.SysIotModelMapper; import jakarta.annotation.PostConstruct; import jakarta.annotation.PreDestroy; @@ -38,6 +40,8 @@ public class IotModelCacheImpl implements IotModelCache { fieldInfoCache.setAttributeType(item.getAttributeType()); fieldInfoCache.setHighspeed(item.getHighSpeed()); fieldInfoCache.setDatatype(item.getDataType()); + fieldInfoCache.setLevel(item.getLevel()); + fieldInfoCache.setStateDesc(item.getStateDesc()); iotFieldsMap.put(String.format("%d_%s", k, item.getAttributeCode()), fieldInfoCache); }); }); @@ -75,4 +79,42 @@ public class IotModelCacheImpl implements IotModelCache { } return fieldInfoCache.isCalculate(); } + + @Override + public void refreshIotFieldCache(SysIotModelField sysIotModelField) { + IotFieldInfoCache fieldInfoCache = new IotFieldInfoCache(); + fieldInfoCache.setAttributeCode(sysIotModelField.getAttributeCode()); + fieldInfoCache.setPorder(sysIotModelField.getPorder()); + fieldInfoCache.setAttributeName(sysIotModelField.getAttributeName()); + fieldInfoCache.setAttributeType(sysIotModelField.getAttributeType()); + fieldInfoCache.setHighspeed(sysIotModelField.getHighSpeed()); + fieldInfoCache.setDatatype(sysIotModelField.getDataType()); + fieldInfoCache.setLevel(sysIotModelField.getLevel()); + fieldInfoCache.setStateDesc(sysIotModelField.getStateDesc()); + iotFieldsMap.put(String.format("%d_%s", sysIotModelField.getIotModelId(), sysIotModelField.getAttributeCode()), fieldInfoCache); + } + + @Override + public void removeIotFieldCache(Long modelId, String attributeCode){ + iotFieldsMap.remove(String.format("%d_%s", modelId, attributeCode)); + } + + + @Override + public void refreshIotModelInfoIdMap(SysIotModel sysIotModel){ + IotModelInfoCache info = new IotModelInfoCache(); + info.setIotModelId(sysIotModel.getId()); + info.setIodModelCode(sysIotModel.getIotModelCode()); + iotModelInfoIdMap.put(sysIotModel.getId(), info); + } + + @Override + public void removeIotModelInfoIdMap(Long modelId) { + iotModelInfoIdMap.remove(modelId); + } + + @Override + public IotFieldInfoCache getIotFiledCache(Long modelId, String attr) { + return iotFieldsMap.get(String.format("%d_%s", modelId, attr)); + } } diff --git a/das/src/main/java/com/das/modules/data/service/TDEngineService.java b/das/src/main/java/com/das/modules/data/service/TDEngineService.java index b0d66f3a..184ed25a 100644 --- a/das/src/main/java/com/das/modules/data/service/TDEngineService.java +++ b/das/src/main/java/com/das/modules/data/service/TDEngineService.java @@ -277,6 +277,9 @@ public class TDEngineService { @Async public void updateYCHighValues(List values, String iotModelCode) { + if (values.isEmpty()) { + return; + } StringBuilder sb = new StringBuilder(1024 * 1024); try (Connection conn = hikariDataSource.getConnection(); Statement pstmt = conn.createStatement()) { @@ -315,6 +318,9 @@ public class TDEngineService { @Async public void updateYCLowValues(List values, String iotModelCode) { + if (values.isEmpty()) { + return; + } StringBuilder sb = new StringBuilder(1024 * 1024); try (Connection conn = hikariDataSource.getConnection(); Statement pstmt = conn.createStatement()) { @@ -353,6 +359,9 @@ public class TDEngineService { @Async public void updateCalFieldValues(List values) { + if (values.isEmpty()) { + return; + } StringBuilder sb = new StringBuilder(1024 * 1024); try (Connection conn = hikariDataSource.getConnection(); Statement pstmt = conn.createStatement()) { @@ -387,6 +396,9 @@ public class TDEngineService { @Async public void updateDeviceEventValues(List values) { + if (values.isEmpty()) { + return; + } StringBuilder sb = new StringBuilder(1024 * 1024); try (Connection conn = hikariDataSource.getConnection(); Statement pstmt = conn.createStatement()) { diff --git a/das/src/main/java/com/das/modules/equipment/mapper/SysIotModelMapper.java b/das/src/main/java/com/das/modules/equipment/mapper/SysIotModelMapper.java index 71fad7fd..8b6950ee 100644 --- a/das/src/main/java/com/das/modules/equipment/mapper/SysIotModelMapper.java +++ b/das/src/main/java/com/das/modules/equipment/mapper/SysIotModelMapper.java @@ -31,6 +31,8 @@ public interface SysIotModelMapper extends BaseMapper { String getIotModel(Long id); + String getIodModelCode(Long id); + List getAllIotModelField(Long id); SysIotModelVo selectIotModelByCode(String code); diff --git a/das/src/main/java/com/das/modules/equipment/service/impl/SysIotModelServiceImpl.java b/das/src/main/java/com/das/modules/equipment/service/impl/SysIotModelServiceImpl.java index 7e0a3b6c..29087a52 100644 --- a/das/src/main/java/com/das/modules/equipment/service/impl/SysIotModelServiceImpl.java +++ b/das/src/main/java/com/das/modules/equipment/service/impl/SysIotModelServiceImpl.java @@ -10,6 +10,7 @@ import com.das.common.config.SessionUtil; import com.das.common.exceptions.ServiceException; import com.das.common.utils.*; import com.das.modules.auth.domain.vo.SysUserVo; +import com.das.modules.cache.service.CacheService; import com.das.modules.data.service.impl.DataServiceImpl; import com.das.modules.equipment.domain.dto.SysIotModelDto; import com.das.modules.equipment.domain.dto.SysIotModelFieldDto; @@ -65,6 +66,9 @@ public class SysIotModelServiceImpl implements SysIotModelService { @Autowired SysRecordLogService sysRecordLogService; + @Autowired + CacheService cacheService; + public SysIotModelVo creatSysIotModel(SysIotModelDto sysIotModelDto) { SysIotModel sysIotModel = new SysIotModel(); BeanCopyUtils.copy(sysIotModelDto, sysIotModel); @@ -81,7 +85,9 @@ public class SysIotModelServiceImpl implements SysIotModelService { sysIotModel.setRevision(1); sysIotModelMapper.insert(sysIotModel); + //刷新缓存 addModelCache(sysIotModel); + cacheService.getIotModelCache().refreshIotModelInfoIdMap(sysIotModel); SysIotModelVo sysIotModelVo = new SysIotModelVo(); BeanCopyUtils.copy(sysIotModel, sysIotModelVo); sysIotModelVo.setIotModelCode(sysIotModelDto.getIotModelCode()); @@ -119,6 +125,8 @@ public class SysIotModelServiceImpl implements SysIotModelService { throw new RuntimeException("该物模型下面有类型,不能删除"); } sysIotModelMapper.deleteById(sysIotModelDto.getId()); + //刷新缓存 + cacheService.getIotModelCache().removeIotModelInfoIdMap(sysIotModelDto.getId()); deleteModelCache(sysIotModelDto.getId()); } @@ -184,6 +192,7 @@ public class SysIotModelServiceImpl implements SysIotModelService { sysIotModelFieldMapper.insert(sysIotModelField); //新增物模型属性缓存 + cacheService.getIotModelCache().refreshIotFieldCache(sysIotModelField); addModelFieldCache(sysIotModelField); SysIotModelFieldVo sysIotModelFieldVo = new SysIotModelFieldVo(); BeanCopyUtils.copy(sysIotModelField, sysIotModelFieldVo); @@ -216,6 +225,7 @@ public class SysIotModelServiceImpl implements SysIotModelService { if (!oldSysIotField.getAttributeCode().equals(sysIotModelField.getAttributeCode()) || !oldSysIotField.getDataType().equals(sysIotModelField.getDataType()) || Objects.equals(oldSysIotField.getHighSpeed(), sysIotModelField.getHighSpeed())) { //更新td表结构 updateTDStableOrColumn(sysIotModelField, oldSysIotField); + cacheService.getIotModelCache().refreshIotFieldCache(sysIotModelField); updateModelFieldCache(sysIotModelField, oldSysIotField); } sysIotModelFieldMapper.updateById(sysIotModelField); @@ -232,6 +242,7 @@ public class SysIotModelServiceImpl implements SysIotModelService { sysIotModelFieldMapper.deleteById(sysIotModelFieldDto.getId()); //删除物模型属性缓存 + cacheService.getIotModelCache().removeIotFieldCache(sysIotModelField.getIotModelId(), sysIotModelField.getAttributeCode()); deleteModelFieldCache(sysIotModelField); } @@ -488,6 +499,10 @@ public class SysIotModelServiceImpl implements SysIotModelService { } //新增pg数据库 sysIotModelFieldMapper.insertBatch(sysIotModelFieldList); + //刷新缓存 + for (SysIotModelField item : sysIotModelFieldList){ + cacheService.getIotModelCache().refreshIotFieldCache(item); + } } if (CollectionUtils.isNotEmpty(updateSysIotModelFieldList)) { for (SysIotModelField item : updateSysIotModelFieldList) { @@ -496,6 +511,7 @@ public class SysIotModelServiceImpl implements SysIotModelService { if (!oldSysIotField.getAttributeCode().equals(item.getAttributeCode()) && oldSysIotField.getDataType().equals(item.getDataType()) && Objects.equals(oldSysIotField.getHighSpeed(), item.getHighSpeed())) { //更新td表结构 updateTDStableOrColumn(item, oldSysIotField); + cacheService.getIotModelCache().refreshIotFieldCache(item); updateModelFieldCache(item, oldSysIotField); } } @@ -509,6 +525,7 @@ public class SysIotModelServiceImpl implements SysIotModelService { for (SysIotModelField item : delSysIotModelFieldList) { deleteTDStableOrColumn(item); sysIotModelFieldMapper.deleteById(item); + cacheService.getIotModelCache().removeIotFieldCache(item.getIotModelId(), item.getAttributeCode()); deleteModelFieldCache(item); } } diff --git a/das/src/main/java/com/das/modules/node/command/AnalogDataCommand.java b/das/src/main/java/com/das/modules/node/command/AnalogDataCommand.java index fcb1717c..4849cbbe 100644 --- a/das/src/main/java/com/das/modules/node/command/AnalogDataCommand.java +++ b/das/src/main/java/com/das/modules/node/command/AnalogDataCommand.java @@ -1,26 +1,110 @@ package com.das.modules.node.command; +import com.das.common.exceptions.ServiceException; +import com.das.modules.cache.domain.DeviceInfoCache; +import com.das.modules.cache.service.CacheService; +import com.das.modules.cache.service.IotModelCache; +import com.das.modules.data.service.TDEngineService; import com.das.modules.node.constant.NodeConstant; +import com.das.modules.node.domain.bo.RTData; import com.das.modules.node.domain.bo.TerminalMessage; import com.das.modules.node.service.NodeMessageService; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; +import java.util.*; + @Service(value = NodeConstant.ANALOG_DATA) @Slf4j public class AnalogDataCommand implements BaseCommand { @Autowired - NodeMessageService nodeMessageService; + CacheService cacheService; + + @Autowired + TDEngineService tdEngineService; + + @Autowired + RedisTemplate redisTemplate; + + /** + * 执行命令方法 + * 当接收到终端消息时,此方法被调用以处理数据 + * 主要负责处理模拟量数据的接收和处理 + * + * @param data 包含模拟量数据的TerminalMessage对象 + */ @Override public void doCommand(TerminalMessage data) { + if (log.isDebugEnabled()){ + log.debug("收到实时数据[模拟量]"); + log.debug("数据内容: {}", data.toJsonString()); + } try { - //analogData值只存入redis - nodeMessageService.handleData(data); + processAnalogData(data); } catch (Exception e) { - log.error("解析数据异常", e); + log.error("处理实时数据时产生异常", e); } } + + /** + * 处理实时数据 + * @param data + */ + + private void processAnalogData(TerminalMessage data){ + JsonNode dataNode = Optional.of(data.getData()).orElseThrow(() -> new ServiceException("data字段缺失")); + String deviceId = Optional.of(dataNode.get("deviceId")).orElseThrow(() -> new ServiceException("deviceId字段缺失")).asText(); + Long dataTime = Optional.of(dataNode.get("dataTime")).orElseThrow( () -> new ServiceException("dataTime字段缺失")).asLong(); + JsonNode values = dataNode.get("values"); + JsonNode archiveValues = dataNode.get("archiveValues"); + //排除空数据 + if (values == null && archiveValues == null){ + return; + } + //如果values有值,则存入redis + Map redisValues = new HashMap<>(); + if (values != null && values.isObject()){ + for (Iterator it = values.fieldNames(); it.hasNext(); ) { + String valueName = it.next(); + String key = String.format("RT:%s:%s", deviceId, valueName.toLowerCase()); + redisValues.put(key, values.get(valueName)); + } + } + DeviceInfoCache dev = cacheService.getEquipmentCache().getDeviceInfoCacheById(Long.parseLong(deviceId)); + IotModelCache iotCache = cacheService.getIotModelCache(); + //如果archiveValues有值,则存入td,同时也更新redis + if (archiveValues != null && archiveValues.isObject()){ + RTData hiSpeedData = new RTData(); + hiSpeedData.setDeviceId(Long.parseLong(deviceId)); + hiSpeedData.setDataTime(dataTime); + Map hiSpeedValues = new HashMap<>(); + RTData lowSpeedData = new RTData(); + lowSpeedData.setDeviceId(Long.parseLong(deviceId)); + lowSpeedData.setDataTime(dataTime); + Map lowSpeedValues = new HashMap<>(); + for (Iterator it = archiveValues.fieldNames(); it.hasNext(); ) { + //加入redis更新列表 + String valueName = it.next(); + String key = String.format("RT:%s:%s", deviceId, valueName.toLowerCase()); + redisValues.put(key, archiveValues.get(valueName)); + //加入td更新列表 + if (iotCache.isHighSpeed(dev.getIotModelId(), valueName)) { + hiSpeedValues.put(valueName, archiveValues.get(valueName)); + } else if (iotCache.isLowSpeed(dev.getIotModelId(), valueName)) { + lowSpeedValues.put(valueName, archiveValues.get(valueName)); + } + } + hiSpeedData.setValues(hiSpeedValues); + lowSpeedData.setValues(lowSpeedValues); + tdEngineService.updateYCHighValues(List.of(hiSpeedData), dev.getIotModelCode()); + tdEngineService.updateYCLowValues(List.of(lowSpeedData), dev.getIotModelCode()); + } + redisTemplate.opsForValue().multiSet(redisValues); + } } diff --git a/das/src/main/java/com/das/modules/node/command/DeviceEventCommand.java b/das/src/main/java/com/das/modules/node/command/DeviceEventCommand.java index aeb96bcf..e8de4c2e 100644 --- a/das/src/main/java/com/das/modules/node/command/DeviceEventCommand.java +++ b/das/src/main/java/com/das/modules/node/command/DeviceEventCommand.java @@ -1,25 +1,127 @@ package com.das.modules.node.command; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.das.common.exceptions.ServiceException; +import com.das.common.utils.AdminRedisTemplate; +import com.das.common.utils.StringUtils; +import com.das.modules.cache.domain.DeviceInfoCache; +import com.das.modules.cache.domain.IotFieldInfoCache; +import com.das.modules.cache.service.CacheService; +import com.das.modules.data.domain.DeviceEventInfo; +import com.das.modules.data.service.TDEngineService; import com.das.modules.node.constant.NodeConstant; import com.das.modules.node.domain.bo.TerminalMessage; -import com.das.modules.node.service.NodeMessageService; +import com.das.modules.node.domain.vo.DeviceEventVo; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + @Service(value = NodeConstant.DEVICE_EVENT) @Slf4j public class DeviceEventCommand implements BaseCommand{ @Autowired - private NodeMessageService nodeMessageService; + AdminRedisTemplate adminRedisTemplate; + + @Autowired + TDEngineService tdEngineService; + + + @Autowired + CacheService cacheService; @Override public void doCommand(TerminalMessage data) { + log.debug("收到实时[事件告警]"); try { - nodeMessageService.handleDeviceEvent(data); + handleDeviceEvent(data); } catch (Exception e) { log.error("解析数据异常", e); } } + + private void handleDeviceEvent(TerminalMessage data) { + + JsonNode dataEvent = data.getData(); + ObjectMapper objectMapper = new ObjectMapper(); + List valueList = new ArrayList<>(); + + // 使用 TypeReference 来指定转换目标类型 + List list = objectMapper.convertValue(dataEvent, new TypeReference>() { + }); + log.debug("消息data转化deviceVo,{}", list); + for (DeviceEventVo item : list) { + DeviceInfoCache deviceInfoCache = cacheService.getEquipmentCache().getDeviceInfoCacheById(Long.valueOf(item.getDeviceId())); + Integer firstTriggeredCode = adminRedisTemplate.get(String.format("RT:%s:%s", item.getDeviceId(), "FirstTriggeredCode".toLowerCase())); + DeviceEventInfo deviceEventInfo = new DeviceEventInfo(); + deviceEventInfo.setEventTime(item.getEventTime()); + deviceEventInfo.setEventId(IdWorker.getId()); + deviceEventInfo.setAttributeCode(item.getAttrCode()); + deviceEventInfo.setDeviceId(item.getDeviceId()); + deviceEventInfo.setDeviceName(deviceInfoCache.getDeviceName()); + deviceEventInfo.setDeviceCode(deviceInfoCache.getDeviceCode()); + deviceEventInfo.setFirstTriggeredCode(firstTriggeredCode); + String eventType = getEventType(item.getEventType()); + Long iotModelId = deviceInfoCache.getIotModelId(); + if (iotModelId == null) { + log.debug("未查询到物模型code,设备id:{}", item.getDeviceId()); + } + IotFieldInfoCache iotFiledCache = cacheService.getIotModelCache().getIotFiledCache(iotModelId, item.getAttrCode()); + if (iotFiledCache == null) { + log.debug("未查询到物模型属性,设备id:{},属性AttrCode:{}", item.getDeviceId(),item.getAttrCode()); + throw new ServiceException("未查询到物模型属性,设备id:"+item.getDeviceId()+",属性AttrCode:"+item.getAttrCode()); + } + String fieldName = iotFiledCache.getAttributeName(); + deviceEventInfo.setEventType(item.getEventType()); + deviceEventInfo.setConfirmed(0); + if (!StringUtils.isEmpty(eventType) && eventType.equals("遥信变位")) { + String stateDesc = iotFiledCache.getStateDesc(); + if (item.getAttrValue().equals(0)) { + deviceEventInfo.setEventText(item.getAttrCode() + fieldName + " 复归"); + if (StringUtils.isNotEmpty(stateDesc)) { + List descList = Arrays.stream(stateDesc.split("\\|")).toList(); + deviceEventInfo.setEventText(item.getAttrCode() + fieldName + descList.get(0)); + } + deviceEventInfo.setEventLevel(0); + } else { + deviceEventInfo.setEventText(item.getAttrCode() + fieldName + " 动作"); + if (StringUtils.isNotEmpty(stateDesc)) { + List descList = Arrays.stream(stateDesc.split("\\|")).toList(); + deviceEventInfo.setEventText(item.getAttrCode() + fieldName + descList.get(1)); + } + Integer level = iotFiledCache.getLevel(); + log.debug("level:{}", level); + log.debug("fieldname{}", fieldName); + deviceEventInfo.setEventLevel(level == null ? 0 : level); + } + } else { + deviceEventInfo.setEventText(item.getAttrCode() + fieldName + eventType + ",属性值为:" + item.getAttrValue() + ",越限值为:" + item.getLimitValue()); + deviceEventInfo.setEventLevel(1); + } + valueList.add(deviceEventInfo); + } + try { + tdEngineService.updateDeviceEventValues(valueList); + } catch (Exception e) { + log.error("事件信息存入Td失败,失败原因", e); + } + } + + private String getEventType(int eventType) { + return switch (eventType) { + case 0 -> "遥信变位"; + case 1 -> "越上限"; + case 2 -> "越下限"; + case 3 -> "越上上限"; + case 4 -> "越下下限"; + default -> ""; + }; + } } diff --git a/das/src/main/java/com/das/modules/node/command/HeartbeatCommand.java b/das/src/main/java/com/das/modules/node/command/HeartbeatCommand.java index a646940c..9eb13de7 100644 --- a/das/src/main/java/com/das/modules/node/command/HeartbeatCommand.java +++ b/das/src/main/java/com/das/modules/node/command/HeartbeatCommand.java @@ -34,7 +34,7 @@ public class HeartbeatCommand implements BaseCommand{ */ @Override public void doCommand(TerminalMessage data) { - log.info("收到[heartbeat]报文"); + log.debug("收到[heartbeat]报文"); // 解析心跳报文中的数据信息 JsonNode dataInfo = data.getData(); diff --git a/das/src/main/java/com/das/modules/node/command/HisHighSpeedCommand.java b/das/src/main/java/com/das/modules/node/command/HisHighSpeedCommand.java index 78662a09..b682ebb8 100644 --- a/das/src/main/java/com/das/modules/node/command/HisHighSpeedCommand.java +++ b/das/src/main/java/com/das/modules/node/command/HisHighSpeedCommand.java @@ -1,26 +1,63 @@ package com.das.modules.node.command; +import com.das.common.exceptions.ServiceException; +import com.das.modules.cache.domain.DeviceInfoCache; +import com.das.modules.cache.service.CacheService; +import com.das.modules.data.service.TDEngineService; import com.das.modules.node.constant.NodeConstant; +import com.das.modules.node.domain.bo.RTData; import com.das.modules.node.domain.bo.TerminalMessage; import com.das.modules.node.service.NodeMessageService; +import com.fasterxml.jackson.databind.JsonNode; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.*; + @Service(value = NodeConstant.HIS_HIGH_SPEED_DATA) @Slf4j public class HisHighSpeedCommand implements BaseCommand { @Autowired - NodeMessageService nodeMessageService; + CacheService cacheService; + + @Autowired + TDEngineService tdEngineService; + @Override public void doCommand(TerminalMessage data) { + log.debug("收到[历史高频数据]"); try { - //analogData值只存入redis - nodeMessageService.handleHighSpeed(data); + processHisHighSpeedData(data); } catch (Exception e) { log.error("解析数据异常", e); } } + + public void processHisHighSpeedData(TerminalMessage data) { + JsonNode jsonNode = Optional.of(data.getData()).orElseThrow(() -> new ServiceException("data字段缺失")); + String deviceId = Optional.of(jsonNode.get("deviceId")).orElseThrow( () -> new ServiceException("deviceId字段缺失")).asText(); + Long dataTime = Optional.of(jsonNode.get("dataTime")).orElseThrow( ()-> new ServiceException("dataTime字段缺失")).asLong(); + JsonNode values = jsonNode.get("values"); + Map keyValueMap = new HashMap<>(); + // 根据设备ID获取对应的物模型属性 + DeviceInfoCache dev = cacheService.getEquipmentCache().getDeviceInfoCacheById(Long.valueOf(deviceId)); + //High数据 + Iterator keysHigh = values.fieldNames(); + while (keysHigh.hasNext()) { + String fieldName = keysHigh.next(); + if (cacheService.getIotModelCache().isHighSpeed(dev.getIotModelId(), fieldName)) { + keyValueMap.put(fieldName, values.get(fieldName)); + } + } + + RTData rtHighData = RTData.builder() + .dataTime(dataTime) + .deviceId(Long.valueOf(deviceId)) + .values(keyValueMap) + .build(); + tdEngineService.updateYCHighValues(List.of(rtHighData), dev.getIotModelCode()); + } } diff --git a/das/src/main/java/com/das/modules/node/command/HisLowSpeedCommand.java b/das/src/main/java/com/das/modules/node/command/HisLowSpeedCommand.java index 82d5497f..476766a2 100644 --- a/das/src/main/java/com/das/modules/node/command/HisLowSpeedCommand.java +++ b/das/src/main/java/com/das/modules/node/command/HisLowSpeedCommand.java @@ -1,26 +1,72 @@ package com.das.modules.node.command; +import com.das.modules.cache.domain.DeviceInfoCache; +import com.das.modules.cache.service.CacheService; +import com.das.modules.data.service.TDEngineService; import com.das.modules.node.constant.NodeConstant; +import com.das.modules.node.domain.bo.RTData; import com.das.modules.node.domain.bo.TerminalMessage; import com.das.modules.node.service.NodeMessageService; +import com.fasterxml.jackson.databind.JsonNode; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.*; + @Service(value = NodeConstant.HIS_LOW_SPEED_DATA) @Slf4j public class HisLowSpeedCommand implements BaseCommand { @Autowired - NodeMessageService nodeMessageService; + CacheService cacheService; + + @Autowired + TDEngineService tdEngineService; + @Override public void doCommand(TerminalMessage data) { + log.debug("收到[历史低频数据]"); try { //analogData值只存入redis - nodeMessageService.handleLowSpeed(data); + processHisLowSpeedData(data); } catch (Exception e) { log.error("解析数据异常", e); } } + + private void processHisLowSpeedData(TerminalMessage data) { + JsonNode dataNode = data.getData(); + if (dataNode == null ) { + log.error("收到无效历史低频数据报文"); + return; + } + String deviceId = Optional.of(dataNode.get("deviceId")).orElseThrow(() -> new RuntimeException("设备ID为空")).asText(); + Long dataTime = Optional.of(dataNode.get("dataTime")).orElseThrow(() -> new RuntimeException("数据时间为空")).asLong(); + + JsonNode values = dataNode.get("values"); + Map keyValueMap = new HashMap<>(); + // 根据设备ID获取对应的物模型属性 + + DeviceInfoCache device = cacheService.getEquipmentCache().getDeviceInfoCacheById(Long.valueOf(deviceId)); + + String iotModelCode = device.getIotModelCode(); + + //Low数据 + Iterator keysLow = values.fieldNames(); + while (keysLow.hasNext()) { + String fieldName = keysLow.next(); + if (cacheService.getIotModelCache().isLowSpeed(device.getIotModelId(), fieldName)){ + keyValueMap.put(fieldName, values.get(fieldName)); + } + } + RTData rtLowData = RTData.builder() + .dataTime(dataTime) + .deviceId(Long.valueOf(deviceId)) + .values(keyValueMap) + .build(); + + tdEngineService.updateYCLowValues(List.of(rtLowData), iotModelCode); + } } diff --git a/das/src/main/java/com/das/modules/node/command/StateDataCommand.java b/das/src/main/java/com/das/modules/node/command/StateDataCommand.java index eb61758a..63289c59 100644 --- a/das/src/main/java/com/das/modules/node/command/StateDataCommand.java +++ b/das/src/main/java/com/das/modules/node/command/StateDataCommand.java @@ -1,26 +1,95 @@ package com.das.modules.node.command; +import com.das.common.exceptions.ServiceException; +import com.das.modules.cache.domain.DeviceInfoCache; +import com.das.modules.cache.service.CacheService; +import com.das.modules.cache.service.IotModelCache; +import com.das.modules.data.service.TDEngineService; import com.das.modules.node.constant.NodeConstant; +import com.das.modules.node.domain.bo.RTData; import com.das.modules.node.domain.bo.TerminalMessage; import com.das.modules.node.service.NodeMessageService; +import com.fasterxml.jackson.databind.JsonNode; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; +import java.util.*; + @Service(value = NodeConstant.STATE_DATA) @Slf4j public class StateDataCommand implements BaseCommand { @Autowired - NodeMessageService nodeMessageService; + CacheService cacheService; + + @Autowired + RedisTemplate redisTemplate; + + @Autowired + TDEngineService tdEngineService; @Override public void doCommand(TerminalMessage data) { + log.debug("收到实时数据[状态量]"); try { //只存入redis - nodeMessageService.handleData(data); + processStateData(data); } catch (Exception e) { log.error("解析数据异常", e); } } + + private void processStateData(TerminalMessage data) { + JsonNode dataNode = Optional.of(data.getData()).orElseThrow(() -> new ServiceException("data字段缺失")); + String deviceId = Optional.of(dataNode.get("deviceId")).orElseThrow(() -> new ServiceException("deviceId字段缺失")).asText(); + Long dataTime = Optional.of(dataNode.get("dataTime")).orElseThrow( () -> new ServiceException("dataTime字段缺失")).asLong(); + JsonNode values = dataNode.get("values"); + JsonNode archiveValues = dataNode.get("archiveValues"); + //排除空数据 + if (values == null && archiveValues == null){ + return; + } + //如果values有值,则存入redis + Map redisValues = new HashMap<>(); + if (values != null && values.isObject()){ + for (Iterator it = values.fieldNames(); it.hasNext(); ) { + String valueName = it.next(); + String key = String.format("RT:%s:%s", deviceId, valueName.toLowerCase()); + redisValues.put(key, values.get(valueName)); + } + } + DeviceInfoCache dev = cacheService.getEquipmentCache().getDeviceInfoCacheById(Long.parseLong(deviceId)); + IotModelCache iotCache = cacheService.getIotModelCache(); + //如果archiveValues有值,则存入td,同时也更新redis + if (archiveValues != null && archiveValues.isObject()){ + RTData hiSpeedData = new RTData(); + hiSpeedData.setDeviceId(Long.parseLong(deviceId)); + hiSpeedData.setDataTime(dataTime); + Map hiSpeedValues = new HashMap<>(); + RTData lowSpeedData = new RTData(); + lowSpeedData.setDeviceId(Long.parseLong(deviceId)); + lowSpeedData.setDataTime(dataTime); + Map lowSpeedValues = new HashMap<>(); + for (Iterator it = archiveValues.fieldNames(); it.hasNext(); ) { + //加入redis更新列表 + String valueName = it.next(); + String key = String.format("RT:%s:%s", deviceId, valueName.toLowerCase()); + redisValues.put(key, archiveValues.get(valueName)); + //加入td更新列表 + if (iotCache.isHighSpeed(dev.getIotModelId(), valueName)) { + hiSpeedValues.put(valueName, archiveValues.get(valueName)); + } else if (iotCache.isLowSpeed(dev.getIotModelId(), valueName)) { + lowSpeedValues.put(valueName, archiveValues.get(valueName)); + } + } + hiSpeedData.setValues(hiSpeedValues); + lowSpeedData.setValues(lowSpeedValues); + + tdEngineService.updateYCHighValues(List.of(hiSpeedData), dev.getIotModelCode()); + tdEngineService.updateYCLowValues(List.of(lowSpeedData),dev.getIotModelCode()); + } + redisTemplate.opsForValue().multiSet(redisValues); + } } diff --git a/das/src/main/java/com/das/modules/node/controller/SysNodeController.java b/das/src/main/java/com/das/modules/node/controller/SysNodeController.java index f2fa9e6c..1cef87e9 100644 --- a/das/src/main/java/com/das/modules/node/controller/SysNodeController.java +++ b/das/src/main/java/com/das/modules/node/controller/SysNodeController.java @@ -19,6 +19,8 @@ import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; /** * 物模型Controller @@ -84,7 +86,7 @@ public class SysNodeController { /** 配置下发 */ @PostMapping("/configUpdate") - public R configUpdate(@RequestBody SysNodeDto sysNodeDto) { + public R configUpdate(@RequestBody SysNodeDto sysNodeDto) throws ExecutionException, InterruptedException, TimeoutException { nodeMessageService.sendTerminalConfig(sysNodeDto.getId()); return R.success(); } diff --git a/das/src/main/java/com/das/modules/node/service/NodeMessageService.java b/das/src/main/java/com/das/modules/node/service/NodeMessageService.java index 1953a9d5..ba373be5 100644 --- a/das/src/main/java/com/das/modules/node/service/NodeMessageService.java +++ b/das/src/main/java/com/das/modules/node/service/NodeMessageService.java @@ -12,15 +12,7 @@ import java.util.concurrent.TimeoutException; public interface NodeMessageService { - JsonNode sendTerminalConfig(Long nodeId); - - void handleData(TerminalMessage data); - - void handleHighSpeed(TerminalMessage data); - - void handleLowSpeed(TerminalMessage data); - - void handleDeviceEvent(TerminalMessage data); + JsonNode sendTerminalConfig(Long nodeId) throws ExecutionException, InterruptedException, TimeoutException; /** * 向指定采集节点发送指令(无返回值) diff --git a/das/src/main/java/com/das/modules/node/service/impl/NodeMessageServiceImpl.java b/das/src/main/java/com/das/modules/node/service/impl/NodeMessageServiceImpl.java index e9e14da1..afa1131d 100644 --- a/das/src/main/java/com/das/modules/node/service/impl/NodeMessageServiceImpl.java +++ b/das/src/main/java/com/das/modules/node/service/impl/NodeMessageServiceImpl.java @@ -75,22 +75,6 @@ public class NodeMessageServiceImpl extends TextWebSocketHandler implements Node @Resource SysImpTabMappingMapper sysImptabmappingMapper; - @Autowired - AdminRedisTemplate adminRedisTemplate; - - @Autowired - SysIotModelMapper sysIotModelMapper; - - @Autowired - TDEngineService tdEngineService; - - @Autowired - private CacheService cacheService; - - @Autowired - private DataServiceImpl dataService; - - @PostConstruct public void init() { //初始化高性能队列 @@ -135,7 +119,7 @@ public class NodeMessageServiceImpl extends TextWebSocketHandler implements Node } @Override - public JsonNode sendTerminalConfig(Long nodeId) { + public JsonNode sendTerminalConfig(Long nodeId) throws ExecutionException, InterruptedException, TimeoutException { ConfigUpdateVo configUpdateVo = new ConfigUpdateVo(); List links = new ArrayList<>(); try { @@ -232,199 +216,11 @@ public class NodeMessageServiceImpl extends TextWebSocketHandler implements Node .time(time) .data(jsonNode) .build(); - sendActionMessage(nodeId, configUpdate); - System.out.println(jsonNode); + sendTerminalMessageWithResult(nodeId,configUpdate); return jsonNode; } - @Override - public void handleData(TerminalMessage data) { - JsonNode jsonNode = data.getData(); - log.debug("收到消息:{}",data.getData()); - String deviceId = jsonNode.get("deviceId").asText(); - JsonNode values = jsonNode.get("values"); - JsonNode archiveValues = jsonNode.get("archiveValues"); - Long dataTime = jsonNode.get("dataTime").asLong(); - Map keyValueMap = new HashMap<>(); - String modelCode = dataService.deviceModelMap.get(deviceId); - Set highKey = dataService.highIotFieldMap.get(modelCode).keySet(); - Set lowKey = dataService.lowIotFieldMap.get(modelCode).keySet(); - Map highSpeedValueMap = new HashMap<>(); - Map lowSpeedValueMap = new HashMap<>(); - - //数据入redis - if (values != null){ - Iterator keysHigh = values.fieldNames(); - while (keysHigh.hasNext()) { - String fieldName = keysHigh.next(); - String key = String.format("RT:%s:%s", deviceId, fieldName.toLowerCase()); - keyValueMap.put(key, values.get(fieldName)); - } - } - - if (archiveValues != null){ - Iterator archiveKeys = archiveValues.fieldNames(); - while (archiveKeys.hasNext()) { - String fieldName = archiveKeys.next(); - String key = String.format("RT:%s:%s", deviceId, fieldName.toLowerCase()); - keyValueMap.put(key, archiveValues.get(fieldName)); - if (highKey.contains(fieldName)) { - highSpeedValueMap.put(fieldName, archiveValues.get(fieldName)); - } - if (lowKey.contains(fieldName)) { - lowSpeedValueMap.put(fieldName, archiveValues.get(fieldName)); - } - } - } - //更新td - if (!highSpeedValueMap.isEmpty()) { - List highSpeedData = new ArrayList<>(); - RTData rtHighData = RTData.builder().dataTime(dataTime).deviceId(Long.valueOf(deviceId)).values(highSpeedValueMap).build(); - highSpeedData.add(rtHighData); - tdEngineService.updateYCHighValues(highSpeedData, modelCode); - } - - if (!lowSpeedValueMap.isEmpty()) { - List lowSpeedData = new ArrayList<>(); - RTData rtLowData = RTData.builder().dataTime(dataTime).deviceId(Long.valueOf(deviceId)).values(lowSpeedValueMap).build(); - lowSpeedData.add(rtLowData); - tdEngineService.updateYCLowValues(lowSpeedData, modelCode); - } - adminRedisTemplate.mSet(keyValueMap); - } - - @Override - public void handleHighSpeed(TerminalMessage data) { - JsonNode jsonNode = data.getData(); - String deviceId = jsonNode.get("deviceId").asText(); - JsonNode values = jsonNode.get("values"); - Map keyValueMap = new HashMap<>(); - // 根据设备ID获取对应的物模型属性 - String iotModelCode = sysIotModelMapper.getIotModel(jsonNode.get("deviceId").asLong()); - - //High数据 - Iterator keysHigh = values.fieldNames(); - while (keysHigh.hasNext()) { - String fieldName = keysHigh.next(); - keyValueMap.put(fieldName, values.get(fieldName)); - - } - Long dataTime = jsonNode.get("dataTime").asLong(); - List highList = new ArrayList<>(); - RTData rtHighData = RTData.builder() - .dataTime(dataTime) - .deviceId(Long.valueOf(deviceId)) - .values(keyValueMap) - .build(); - highList.add(rtHighData); - tdEngineService.updateYCHighValues(highList, iotModelCode); - } - - @Override - public void handleLowSpeed(TerminalMessage data) { - JsonNode jsonNode = data.getData(); - String deviceId = jsonNode.get("deviceId").asText(); - JsonNode values = jsonNode.get("values"); - Map keyValueMap = new HashMap<>(); - // 根据设备ID获取对应的物模型属性 - String iotModelCode = sysIotModelMapper.getIotModel(jsonNode.get("deviceId").asLong()); - - //Low数据 - Iterator keysLow = values.fieldNames(); - while (keysLow.hasNext()) { - String fieldName = keysLow.next(); - keyValueMap.put(fieldName, values.get(fieldName)); - - } - Long dataTime = jsonNode.get("dataTime").asLong(); - List highList = new ArrayList<>(); - RTData rtHighData = RTData.builder() - .dataTime(dataTime) - .deviceId(Long.valueOf(deviceId)) - .values(keyValueMap) - .build(); - highList.add(rtHighData); - tdEngineService.updateYCLowValues(highList, iotModelCode); - } - - @Override - public void handleDeviceEvent(TerminalMessage data) { - - JsonNode dataEvent = data.getData(); - ObjectMapper objectMapper = new ObjectMapper(); - List valueList = new ArrayList<>(); - - // 使用 TypeReference 来指定转换目标类型 - List list = objectMapper.convertValue(dataEvent, new TypeReference>() { - }); - log.debug("消息data转化deviceVo,{}", list); - for (DeviceEventVo item : list) { - DeviceInfoCache deviceInfoCache = cacheService.getEquipmentCache().getDeviceInfoCacheById(Long.valueOf(item.getDeviceId())); - Integer firstTriggeredCode = adminRedisTemplate.get(String.format("RT:%s:%s", item.getDeviceId(), "FirstTriggeredCode".toLowerCase())); - DeviceEventInfo deviceEventInfo = new DeviceEventInfo(); - deviceEventInfo.setEventTime(item.getEventTime()); - deviceEventInfo.setEventId(IdWorker.getId()); - deviceEventInfo.setAttributeCode(item.getAttrCode()); - deviceEventInfo.setDeviceId(item.getDeviceId()); - deviceEventInfo.setDeviceName(deviceInfoCache.getDeviceName()); - deviceEventInfo.setDeviceCode(deviceInfoCache.getDeviceCode()); - deviceEventInfo.setFirstTriggeredCode(firstTriggeredCode); - String eventType = getEventType(item.getEventType()); - String model = dataService.deviceModelMap.get(item.getDeviceId()); - if (StringUtils.isEmpty(model)) { - log.debug("未查询到物模型code,设备id:{}", item.getDeviceId()); - } - String fieldName = dataService.fieldCodeNameMap.get(model).get(item.getAttrCode()); - if (StringUtils.isEmpty(fieldName)) { - log.debug("未查询到物模型属性code,设备id:{}", item.getDeviceId()); - } - deviceEventInfo.setEventType(item.getEventType()); - deviceEventInfo.setConfirmed(0); - if (!StringUtils.isEmpty(eventType) && eventType.equals("遥信变位")) { - String stateDesc = dataService.stateDescMap.get(model).get(item.getAttrCode()); - if (item.getAttrValue().equals(0)) { - deviceEventInfo.setEventText(item.getAttrCode() + fieldName + " 复归"); - if (StringUtils.isNotEmpty(stateDesc)) { - List descList = Arrays.stream(stateDesc.split("\\|")).toList(); - deviceEventInfo.setEventText(item.getAttrCode() + fieldName + descList.get(0)); - } - deviceEventInfo.setEventLevel(0); - } else { - deviceEventInfo.setEventText(item.getAttrCode() + fieldName + " 动作"); - if (StringUtils.isNotEmpty(stateDesc)) { - List descList = Arrays.stream(stateDesc.split("\\|")).toList(); - deviceEventInfo.setEventText(item.getAttrCode() + fieldName + descList.get(1)); - } - Integer level = dataService.eventLevelMap.get(model).get(item.getAttrCode()); - log.debug("level:{}", level); - log.debug("fieldname{}", fieldName); - deviceEventInfo.setEventLevel(level == null ? 0 : level); - } - } else { - deviceEventInfo.setEventText(item.getAttrCode() + fieldName + eventType + ",属性值为:" + item.getAttrValue() + ",越限值为:" + item.getLimitValue()); - deviceEventInfo.setEventLevel(1); - } - valueList.add(deviceEventInfo); - } - try { - tdEngineService.updateDeviceEventValues(valueList); - } catch (Exception e) { - log.error("事件信息存入Td失败,失败原因", e); - } - } - - private String getEventType(int eventType) { - return switch (eventType) { - case 0 -> "遥信变位"; - case 1 -> "越上限"; - case 2 -> "越下限"; - case 3 -> "越上上限"; - case 4 -> "越下下限"; - default -> ""; - }; - } - @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { String remoteIp = (String) session.getAttributes().getOrDefault(NodeConstant.REMOTE_IP, ""); diff --git a/das/src/main/java/com/das/modules/page/service/impl/StatisticalAnalysisServiceImpl.java b/das/src/main/java/com/das/modules/page/service/impl/StatisticalAnalysisServiceImpl.java index 22f6c198..b3ee1b0a 100644 --- a/das/src/main/java/com/das/modules/page/service/impl/StatisticalAnalysisServiceImpl.java +++ b/das/src/main/java/com/das/modules/page/service/impl/StatisticalAnalysisServiceImpl.java @@ -28,35 +28,18 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.poi.ss.usermodel.ClientAnchor; import org.apache.poi.ss.usermodel.HorizontalAlignment; import org.apache.poi.ss.usermodel.VerticalAlignment; -import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.xddf.usermodel.chart.*; import org.apache.poi.xssf.usermodel.XSSFChart; -import org.apache.poi.xssf.usermodel.XSSFClientAnchor; import org.apache.poi.xssf.usermodel.XSSFDrawing; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.jetbrains.annotations.NotNull; -import org.jfree.chart.ChartFactory; -import org.jfree.chart.ChartUtils; -import org.jfree.chart.JFreeChart; -import org.jfree.chart.axis.CategoryAxis; -import org.jfree.chart.axis.CategoryLabelPositions; -import org.jfree.chart.plot.CategoryPlot; -import org.jfree.chart.plot.PlotOrientation; -import org.jfree.chart.renderer.category.CategoryItemRenderer; -import org.jfree.chart.title.LegendTitle; -import org.jfree.chart.title.TextTitle; -import org.jfree.data.category.DefaultCategoryDataset; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.awt.*; -import java.io.File; -import java.io.IOException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; -import java.util.List; import java.util.*; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -105,13 +88,9 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic List> dataList = new ArrayList<>(); // 遍历数据,填充Excel数据集 setTrendAnalyseExcelValue(mapsList, dataList); - //获取图表类别集 - List chartKey = getCharKey(map); ExcelWriter writer = ExcelUtil.getWriter(RandomUtil.randomInt(100, 1000) + "statistics" + ".xlsx"); //设置Excel样式 setExcelStyle(writer, map, dataList); - //生成折线图 - addChartToExcel(writer,dataList,StatisticalAnalysisConstant.TREND_ANALYSE,chartKey); //下载Excel downloadExcel(response, writer,StatisticalAnalysisConstant.TREND_ANALYSE); } @@ -150,18 +129,9 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic setPowerCurveExcelValue(resultMap, dataList, curveItemEntitieList); //获取功率曲线的列 LinkedHashMap map = getPowerCurveColumnName(param); - //获取图表类别集 - List chartKey = getCharKey(map); ExcelWriter writer = ExcelUtil.getWriter(RandomUtil.randomInt(100, 1000) + "statistics" + ".xlsx"); //设置Excel样式 setExcelStyle(writer, map, dataList); - //生成折线图 - if (param.getDisplayCurve()==1){ - addChartToExcel(writer,dataList,StatisticalAnalysisConstant.POWER_CURVE,chartKey); - }else { - //生成散点图 - addScattersChartToExcel(writer,dataList,StatisticalAnalysisConstant.POWER_CURVE,chartKey); - } //下载Excel downloadExcel(response, writer,StatisticalAnalysisConstant.POWER_CURVE); } @@ -191,15 +161,11 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic //自定义别名 别名的key和实体类中的名称要对应上! LinkedHashMap map = gettrendContrastColumnName(param); List> dataList = new ArrayList<>(); - //图表类别集 - List charKey = getCharKey(map); // 遍历数据,将数据添加到dataList中 setTrendContrastExcelValue(maps, dataList); ExcelWriter writer = ExcelUtil.getWriter(RandomUtil.randomInt(100, 1000) + "statistics" + ".xlsx"); //设置Excel样式 setExcelStyle(writer, map, dataList); - //生成折线图 - addChartToExcel(writer,dataList,StatisticalAnalysisConstant.TREND_CONTRAST,charKey); //下载Excel downloadExcel(response, writer,StatisticalAnalysisConstant.TREND_CONTRAST); } @@ -284,22 +250,7 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic } } - /** - * 获取图表类别集 - * @param map Excel的列 - * @return 图表类别集 - */ - private List getCharKey(LinkedHashMap map) { - //获取图表类别集 - List chartKey = new ArrayList<>(); - for (Map.Entry stringStringEntry : map.entrySet()) { - String value = stringStringEntry.getValue(); - if (!value.contains("时间")){ - chartKey.add(value); - } - } - return chartKey; - } + /** * 趋势对比填充Excel数据集 @@ -542,75 +493,20 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic } /** - * 使用JFreeChart生成折线图(图片),已弃用 - * @param data excel数据集 - * @param writer excel对象 - * @param dataset 图表数据集 - * @param titleStr 标题 + * 获取图表类别集 + * @param map Excel的列 + * @return 图表类别集 */ - private void createChart(List> data, ExcelWriter writer, - DefaultCategoryDataset dataset, String titleStr) { - // 获取Sheet对象 - XSSFSheet xssfSheet = (XSSFSheet) writer.getSheet(); - Workbook workbook = writer.getWorkbook(); - JFreeChart chart = ChartFactory.createLineChart( - titleStr, // 图表标题 - "", // 横轴标签 - "", // 纵轴标签 - dataset, // 数据集 - PlotOrientation.VERTICAL, // 图表方向 - true, // 是否显示图例 - true, // 是否使用工具提示 - false // 是否生成URL链接 - ); - // 设置图表标题的字体 - TextTitle title = chart.getTitle(); - title.setFont(new java.awt.Font("SimSun", java.awt.Font.BOLD, 16)); - // 获取图表的绘图区域 - CategoryPlot plot = chart.getCategoryPlot(); - // 设置横轴标签 - CategoryAxis domainAxis = plot.getDomainAxis(); - domainAxis.setLabelFont(new java.awt.Font("SimSun", java.awt.Font.PLAIN, 12)); - domainAxis.setMaximumCategoryLabelLines(1); // 可以控制标签行数 - domainAxis.setCategoryMargin(3); // 控制类别之间的间距 - domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45); // 旋转横轴标签为45度,90度为:UP_90 - domainAxis.setLabelFont(new Font("SansSerif", Font.PLAIN, 7));//调整字体大小 -// if (data.size() > 50) { -// domainAxis.setVisible(false); // 隐藏横坐标 -// } - // 设置图例的字体 - LegendTitle legend = chart.getLegend(); - if (legend != null) { - legend.setItemFont(new java.awt.Font("SimSun", java.awt.Font.PLAIN, 12)); + private List getCharKey(LinkedHashMap map) { + //获取图表类别集 + List chartKey = new ArrayList<>(); + for (Map.Entry stringStringEntry : map.entrySet()) { + String value = stringStringEntry.getValue(); + if (!value.contains("时间")){ + chartKey.add(value); + } } - // 设置绘图区域的背景颜色 - plot.setBackgroundPaint(Color.WHITE); - // 设置绘图区域的边框 - plot.setOutlinePaint(Color.LIGHT_GRAY); - plot.setOutlineVisible(true); - // 设置网格线的颜色 - plot.setDomainGridlinePaint(Color.LIGHT_GRAY); - plot.setRangeGridlinePaint(Color.LIGHT_GRAY); - // 设置线条的宽度 - CategoryItemRenderer renderer1 = plot.getRenderer(); - renderer1.setSeriesStroke(0, new BasicStroke(2.0f)); // 设置线条宽度 - // 将图表保存为 PNG 文件 - String chartFilePath = "lineChart.png"; - // 调整图表尺寸 - int width = 750; - int height = 400; - try { - ChartUtils.saveChartAsPNG(new File(chartFilePath), chart, width, height); - byte[] bytes = java.nio.file.Files.readAllBytes(java.nio.file.Paths.get(chartFilePath)); - int pictureIdx = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_PNG); - // 计算数据的最后一行,创建图表插入位置的锚点 - XSSFClientAnchor anchor = new XSSFClientAnchor(0, 1, 0, 1, 0, data.size() + 2, 15, data.size() + 30); - XSSFDrawing drawing = xssfSheet.createDrawingPatriarch(); - drawing.createPicture(anchor, pictureIdx); - } catch (IOException e) { - throw new ServiceException("图表保存失败==" + e); - } - + return chartKey; } /** diff --git a/das/src/main/resources/mapper/SysIotModelMapper.xml b/das/src/main/resources/mapper/SysIotModelMapper.xml index 271248f8..297189d5 100644 --- a/das/src/main/resources/mapper/SysIotModelMapper.xml +++ b/das/src/main/resources/mapper/SysIotModelMapper.xml @@ -77,6 +77,10 @@ select sim.iot_model_code from sys_iot_model sim left join sys_equipment se on sim.id = se.iot_model_id where se.id = #{id} + + diff --git a/ui/dasadmin/src/api/backend/deviceModel/request.ts b/ui/dasadmin/src/api/backend/deviceModel/request.ts index 143105a2..67c524b7 100644 --- a/ui/dasadmin/src/api/backend/deviceModel/request.ts +++ b/ui/dasadmin/src/api/backend/deviceModel/request.ts @@ -157,6 +157,8 @@ export const getRealValueListReq = (data: { deviceId: string, attributes?: (stri method: 'post', data: data, timeout: 60 * 1000 + },{ + showErrorMessage: false }) } @@ -166,6 +168,8 @@ export const getRealValueRangeReq = (data: { startTime: number, endTime: number, method: 'post', data: data, timeout: 60 * 1000 + },{ + showErrorMessage: false }) } diff --git a/ui/dasadmin/src/views/backend/auth/model/index.vue b/ui/dasadmin/src/views/backend/auth/model/index.vue index 5f9a4019..231d42ab 100644 --- a/ui/dasadmin/src/views/backend/auth/model/index.vue +++ b/ui/dasadmin/src/views/backend/auth/model/index.vue @@ -274,7 +274,7 @@ - + diff --git a/ui/dasadmin/src/views/backend/linkMonitor/index.vue b/ui/dasadmin/src/views/backend/linkMonitor/index.vue index 66c7f331..142d48dd 100644 --- a/ui/dasadmin/src/views/backend/linkMonitor/index.vue +++ b/ui/dasadmin/src/views/backend/linkMonitor/index.vue @@ -43,16 +43,25 @@
- + + + + - - - +