diff --git a/iot-access/access-api/src/main/java/com/njcn/access/api/AskDeviceDataFeignClient.java b/iot-access/access-api/src/main/java/com/njcn/access/api/AskDeviceDataFeignClient.java new file mode 100644 index 0000000..01c043e --- /dev/null +++ b/iot-access/access-api/src/main/java/com/njcn/access/api/AskDeviceDataFeignClient.java @@ -0,0 +1,27 @@ +package com.njcn.access.api; + +import com.njcn.access.api.fallback.AskDeviceDataClientFallbackFactory; +import com.njcn.common.pojo.constant.ServerInfo; +import com.njcn.common.pojo.response.HttpResult; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * @author xy + */ +@FeignClient(value = ServerInfo.ACCESS_BOOT, path = "/askDeviceData", fallbackFactory = AskDeviceDataClientFallbackFactory.class,contextId = "askDeviceData") +public interface AskDeviceDataFeignClient { + + @PostMapping("/askDeviceRootPath") + HttpResult askDeviceRootPath(@RequestParam("nDid") String nDid); + + @PostMapping("/askDeviceFileOrDir") + HttpResult askDeviceFileOrDir(@RequestParam("nDid") String nDid, @RequestParam("name") String name); + + @PostMapping("/downloadFile") + HttpResult downloadFile(@RequestParam("nDid") String nDid, @RequestParam("name") String name, @RequestParam("size") Integer size, @RequestParam("fileCheck") String fileCheck); + + @PostMapping("/rebootDevice") + HttpResult rebootDevice(@RequestParam("nDid") String nDid); +} diff --git a/iot-access/access-api/src/main/java/com/njcn/access/api/CsSoftInfoFeignClient.java b/iot-access/access-api/src/main/java/com/njcn/access/api/CsSoftInfoFeignClient.java new file mode 100644 index 0000000..8f2b1df --- /dev/null +++ b/iot-access/access-api/src/main/java/com/njcn/access/api/CsSoftInfoFeignClient.java @@ -0,0 +1,20 @@ +package com.njcn.access.api; + +import com.njcn.access.api.fallback.CsSoftInfoClientFallbackFactory; +import com.njcn.access.pojo.po.CsSoftInfoPO; +import com.njcn.common.pojo.constant.ServerInfo; +import com.njcn.common.pojo.response.HttpResult; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * @author xy + */ +@FeignClient(value = ServerInfo.ACCESS_BOOT, path = "/csSoftInfo", fallbackFactory = CsSoftInfoClientFallbackFactory.class,contextId = "csSoftInfo") +public interface CsSoftInfoFeignClient { + + @PostMapping("/findSoftInfo") + HttpResult findSoftInfo(@RequestParam("id") String id); + +} diff --git a/iot-access/access-api/src/main/java/com/njcn/access/api/fallback/AskDeviceDataClientFallbackFactory.java b/iot-access/access-api/src/main/java/com/njcn/access/api/fallback/AskDeviceDataClientFallbackFactory.java new file mode 100644 index 0000000..f6f3780 --- /dev/null +++ b/iot-access/access-api/src/main/java/com/njcn/access/api/fallback/AskDeviceDataClientFallbackFactory.java @@ -0,0 +1,60 @@ +package com.njcn.access.api.fallback; + +import com.njcn.access.api.AskDeviceDataFeignClient; +import com.njcn.common.pojo.enums.response.CommonResponseEnum; +import com.njcn.common.pojo.exception.BusinessException; +import com.njcn.common.pojo.response.HttpResult; +import com.njcn.redis.utils.RedisUtil; +import feign.hystrix.FallbackFactory; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * @author xy + */ +@Slf4j +@Component +public class AskDeviceDataClientFallbackFactory implements FallbackFactory { + + @Resource + private RedisUtil redisUtil; + + @Override + public AskDeviceDataFeignClient create(Throwable cause) { + //判断抛出异常是否为解码器抛出的业务异常 + Enum exceptionEnum = CommonResponseEnum.SERVICE_FALLBACK; + if (cause.getCause() instanceof BusinessException) { + BusinessException businessException = (BusinessException) cause.getCause(); + } + Enum finalExceptionEnum = exceptionEnum; + return new AskDeviceDataFeignClient() { + @Override + public HttpResult askDeviceRootPath(String nDid) { + log.error("{}异常,降级处理,异常为:{}","平台询问装置报文",cause.toString()); + throw new BusinessException(finalExceptionEnum); + } + + @Override + public HttpResult askDeviceFileOrDir(String nDid, String name) { + log.error("{}异常,降级处理,异常为:{}","设备文件/目录信息询问",cause.toString()); + throw new BusinessException(finalExceptionEnum); + } + + @Override + public HttpResult downloadFile(String nDid, String name, Integer size, String fileCheck) { + log.error("{}异常,降级处理,异常为:{}","文件下载",cause.toString()); + redisUtil.delete("fileDowning"); + redisUtil.delete("fileCheck"+name); + throw new BusinessException(finalExceptionEnum); + } + + @Override + public HttpResult rebootDevice(String nDid) { + log.error("{}异常,降级处理,异常为:{}","设备重启",cause.toString()); + throw new BusinessException(finalExceptionEnum); + } + }; + } +} diff --git a/iot-access/access-api/src/main/java/com/njcn/access/api/fallback/CsSoftInfoClientFallbackFactory.java b/iot-access/access-api/src/main/java/com/njcn/access/api/fallback/CsSoftInfoClientFallbackFactory.java new file mode 100644 index 0000000..303931a --- /dev/null +++ b/iot-access/access-api/src/main/java/com/njcn/access/api/fallback/CsSoftInfoClientFallbackFactory.java @@ -0,0 +1,34 @@ +package com.njcn.access.api.fallback; + +import com.njcn.access.api.CsSoftInfoFeignClient; +import com.njcn.access.pojo.po.CsSoftInfoPO; +import com.njcn.common.pojo.enums.response.CommonResponseEnum; +import com.njcn.common.pojo.exception.BusinessException; +import com.njcn.common.pojo.response.HttpResult; +import feign.hystrix.FallbackFactory; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * @author xy + */ +@Slf4j +@Component +public class CsSoftInfoClientFallbackFactory implements FallbackFactory { + @Override + public CsSoftInfoFeignClient create(Throwable cause) { + //判断抛出异常是否为解码器抛出的业务异常 + Enum exceptionEnum = CommonResponseEnum.SERVICE_FALLBACK; + if (cause.getCause() instanceof BusinessException) { + BusinessException businessException = (BusinessException) cause.getCause(); + } + Enum finalExceptionEnum = exceptionEnum; + return new CsSoftInfoFeignClient() { + @Override + public HttpResult findSoftInfo(String id) { + log.error("{}异常,降级处理,异常为:{}","获取装置软件信息",cause.toString()); + throw new BusinessException(finalExceptionEnum); + } + }; + } +} diff --git a/iot-access/access-api/src/main/java/com/njcn/access/enums/AccessResponseEnum.java b/iot-access/access-api/src/main/java/com/njcn/access/enums/AccessResponseEnum.java index d3fd6fe..bbbd639 100644 --- a/iot-access/access-api/src/main/java/com/njcn/access/enums/AccessResponseEnum.java +++ b/iot-access/access-api/src/main/java/com/njcn/access/enums/AccessResponseEnum.java @@ -14,10 +14,10 @@ public enum AccessResponseEnum { * A0301 ~ A0399 用于用户模块的枚举 *

*/ - NDID_NO_FIND("A0301", "此设备未录入!"), - NDID_SAME_STEP("A0301", "此设备已注册!"), + NDID_NO_FIND("A0301", "此装置未录入!"), + NDID_SAME_STEP("A0301", "此装置已注册!"), - MISSING_CLIENT("A0302","设备客户端不在线!"), + MISSING_CLIENT("A0302","装置端不在线!"), MODEL_REPEAT("A0302", "模板存在,请勿重复录入!"), MODEL_NO_FIND("A0302", "模板不存在,请先录入模板数据!"), MODEL_ERROR("A0302", "模板未找到,生成监测点失败!"), @@ -30,7 +30,7 @@ public enum AccessResponseEnum { DEV_MODEL_NOT_FIND("A0303","装置型号未找到!"), DEV_IS_NOT_ZL("A0303","注册装置不是直连装置!"), DEV_IS_NOT_WG("A0303","注册装置不是网关!"), - DEV_IS_NOT_PORTABLE("A0303","注册装置不是便携式设备!"), + DEV_IS_NOT_PORTABLE("A0303","注册装置不是便携式装置!"), REGISTER_RESPONSE_ERROR("A0304","装置注册,装置侧应答失败!"), ACCESS_RESPONSE_ERROR("A0304","装置注册,装置侧应答失败!"), @@ -62,7 +62,7 @@ public enum AccessResponseEnum { RELOAD_UPLOAD_ERROR("A0308","平台重新上送文件异常"), CLDID_IS_NULL("A0309","逻辑子设备标识为空"), - MODULE_NUMBER_IS_NULL("A0309","设备子模块个数为空"), + MODULE_NUMBER_IS_NULL("A0309","装置子模块个数为空"), LDEVINFO_IS_NULL("A0309","逻辑设备信息为空"), SOFTINFO_IS_NULL("A0309","软件信息为空"), @@ -71,6 +71,8 @@ public enum AccessResponseEnum { PROCESS_SAME_ERROR("A0311","当前调试已完成,请勿重复调试"), PROCESS_MISSING_ERROR("A0311","调试流程缺失,请核查功能调试、出厂调试"), PROCESS_ERROR("A0311","调试流程异常,请先进行功能调试、出厂调试!"), + + FILE_CHECK_ERROR("A0312","文件校验码不一致!"), ; private final String code; diff --git a/iot-access/access-api/src/main/java/com/njcn/access/enums/TypeEnum.java b/iot-access/access-api/src/main/java/com/njcn/access/enums/TypeEnum.java index 08ca8fe..5652355 100644 --- a/iot-access/access-api/src/main/java/com/njcn/access/enums/TypeEnum.java +++ b/iot-access/access-api/src/main/java/com/njcn/access/enums/TypeEnum.java @@ -44,6 +44,7 @@ public enum TypeEnum { TYPE_28("4662","设备根目录查询应答"), TYPE_29("9217","设备心跳请求"), TYPE_30("4865","设备数据主动上送"), + TYPE_31("8503","设备控制命令"), /** * 数据类型 @@ -63,6 +64,7 @@ public enum TypeEnum { DATA_13("13","内部定值InSet"), DATA_14("14","控制Ctrl"), DATA_16("16","波形文件"), + DATA_48("48","工程信息"), /** * 数据模型列表 diff --git a/iot-access/access-api/src/main/java/com/njcn/access/pojo/RspDataDto.java b/iot-access/access-api/src/main/java/com/njcn/access/pojo/RspDataDto.java index 05e4246..dda6299 100644 --- a/iot-access/access-api/src/main/java/com/njcn/access/pojo/RspDataDto.java +++ b/iot-access/access-api/src/main/java/com/njcn/access/pojo/RspDataDto.java @@ -84,4 +84,83 @@ public class RspDataDto { private Double capacityA; } + /** + * 工程信息 + */ + @Data + public static class ProjectInfo { + + @SerializedName("PrjName") + @ApiModelProperty("项目名称") + private String prjName; + + @SerializedName("PrjTimeStart") + @ApiModelProperty("项目起始时间") + private Long prjTimeStart; + + @SerializedName("PrjTimeEnd") + @ApiModelProperty("项目结束时间") + private Long prjTimeEnd; + + @SerializedName("PrjDataPath") + @ApiModelProperty("文件路径") + private String prjDataPath; + + @SerializedName("DevType") + @ApiModelProperty("装置型号") + private String devType; + + @SerializedName("DevMac") + @ApiModelProperty("装置mac") + private String devMac; + + @SerializedName("AppVersion") + @ApiModelProperty("设备应用程序版本信息") + private String appVersion; + + @SerializedName("Cldid") + @ApiModelProperty("逻辑子设备ID(0-逻辑设备本身)") + private Integer clDid; + + @SerializedName("StatCycle") + @ApiModelProperty("分钟数据统计时间间隔(1~10分钟)") + private Integer statCycle; + + @SerializedName("VolGrade") + @ApiModelProperty("电压等级(kV)") + private Double volGrade; + + @SerializedName("VolConType") + @ApiModelProperty("电压接线方式 (0-星型, 1-角型, 2-V型)") + private Integer volConType; + + @SerializedName("CurConSel") + @ApiModelProperty("电流接线方式 (0-正常, 1-合成IB, 2-合成IC)") + private Integer curConSel; + + @SerializedName("PtRatio") + @ApiModelProperty("PT变比") + private Integer ptRatio; + + @SerializedName("CtRatio") + @ApiModelProperty("CT变比") + private Integer ctRatio; + + @SerializedName("CapacitySscb") + @ApiModelProperty("基准短路容量(MVA)") + private Double capacitySscb; + + @SerializedName("CapacitySscmin") + @ApiModelProperty("最小短路容量(MVA)") + private Double capacitySscmin; + + @SerializedName("CapacitySt") + @ApiModelProperty("供电设备容量(MVA)") + private Double capacitySt; + + @SerializedName("CapacitySi") + @ApiModelProperty("用户协议容量(MVA)") + private Double capacitySi; + } + } diff --git a/iot-access/access-api/src/main/java/com/njcn/access/pojo/dto/AutoDataDto.java b/iot-access/access-api/src/main/java/com/njcn/access/pojo/dto/AutoDataDto.java index eb8c16d..97adeaa 100644 --- a/iot-access/access-api/src/main/java/com/njcn/access/pojo/dto/AutoDataDto.java +++ b/iot-access/access-api/src/main/java/com/njcn/access/pojo/dto/AutoDataDto.java @@ -72,6 +72,78 @@ public class AutoDataDto { @SerializedName("Data") private String data; + + @SerializedName("PrjName") + @ApiModelProperty("工程名称") + private String prjName; + + @SerializedName("PrjTimeStart") + @ApiModelProperty("装置启动时间") + private Long prjTimeStart; + + @SerializedName("PrjTimeEnd") + @ApiModelProperty("装置结束时间") + private Long prjTimeEnd; + + @SerializedName("PrjDataPath") + @ApiModelProperty("装置数据路径") + private String prjDataPath; + + @SerializedName("DevType") + @ApiModelProperty("装置型号") + private String devType; + + @SerializedName("DevMac") + @ApiModelProperty("装置mac地址") + private String devMac; + + @SerializedName("AppVersion") + @ApiModelProperty("装置程序版本") + private String appVersion; + + @SerializedName("Cldid") + @ApiModelProperty("逻辑子设备id") + private Integer clDid; + + @SerializedName("StatCycle") + @ApiModelProperty("统计间隔") + private Integer statCycle; + + @SerializedName("VolGrade") + @ApiModelProperty("电压等级") + private Float volGrade; + + @SerializedName("VolConType") + @ApiModelProperty("电压接线方式(0-星型, 1-角型, 2-V型)") + private Integer volConType; + + @SerializedName("CurConSel") + @ApiModelProperty("电流接线方式(0-正常, 1-合成IB, 2-合成IC)") + private Integer curConSel; + + @SerializedName("PtRatio") + @ApiModelProperty("PT变比") + private Integer ptRatio; + + @SerializedName("CtRatio") + @ApiModelProperty("ct变比") + private Integer ctRatio; + + @SerializedName("CapacitySscb") + @ApiModelProperty("基准短路容量") + private Float capacitySscb; + + @SerializedName("CapacitySscmin") + @ApiModelProperty("最小短路容量") + private Float capacitySscmin; + + @SerializedName("CapacitySt") + @ApiModelProperty("供电设备容量") + private Float capacitySt; + + @SerializedName("CapacitySi") + @ApiModelProperty("用户协议容量") + private Float capacitySi; } } diff --git a/iot-access/access-api/src/main/java/com/njcn/access/pojo/dto/ControlDto.java b/iot-access/access-api/src/main/java/com/njcn/access/pojo/dto/ControlDto.java new file mode 100644 index 0000000..879fbab --- /dev/null +++ b/iot-access/access-api/src/main/java/com/njcn/access/pojo/dto/ControlDto.java @@ -0,0 +1,22 @@ +package com.njcn.access.pojo.dto; + +import com.alibaba.nacos.shaded.com.google.gson.annotations.SerializedName; +import lombok.Data; + +import java.io.Serializable; + +/** + * @author xy + */ +@Data +public class ControlDto implements Serializable { + + @SerializedName("Cldid") + private Integer clDid; + + @SerializedName("CmdType") + private String cmdType; + + @SerializedName("CmdParm") + private String cmdParm; +} diff --git a/iot-access/access-api/src/main/java/com/njcn/access/pojo/dto/DeviceRedisInfoDto.java b/iot-access/access-api/src/main/java/com/njcn/access/pojo/dto/DeviceRedisInfoDto.java new file mode 100644 index 0000000..ac58700 --- /dev/null +++ b/iot-access/access-api/src/main/java/com/njcn/access/pojo/dto/DeviceRedisInfoDto.java @@ -0,0 +1,52 @@ +package com.njcn.access.pojo.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * @author xy + * 装置缓存信息 + */ +@Data +public class DeviceRedisInfoDto { + + @ApiModelProperty("装置id") + private String deviceId; + + @ApiModelProperty("装置nDid") + private String nDid; + + @ApiModelProperty("装置类型") + private String deviceType; + + @ApiModelProperty("装置模板id") + private String modelId; + + @ApiModelProperty("模板名称") + private String modelName; + + @ApiModelProperty("模板版本") + private String modelVersion; + + @ApiModelProperty("模板类型 0:治理模板 1:电能质量模板") + private Integer modelType; + + @ApiModelProperty("监测点信息") + private List lineList; + + @Data + public static class LineRedisInfo { + + @ApiModelProperty("监测点id") + private String lineId; + + @ApiModelProperty("监测点位置") + private String location; + + @ApiModelProperty("逻辑设备编码") + private Integer clDid; + } + +} diff --git a/iot-access/access-api/src/main/java/com/njcn/access/pojo/dto/ModelRedisInfoDto.java b/iot-access/access-api/src/main/java/com/njcn/access/pojo/dto/ModelRedisInfoDto.java new file mode 100644 index 0000000..ffd9071 --- /dev/null +++ b/iot-access/access-api/src/main/java/com/njcn/access/pojo/dto/ModelRedisInfoDto.java @@ -0,0 +1,63 @@ +package com.njcn.access.pojo.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.time.LocalDate; +import java.util.List; + +/** + * @author xy + * 模板缓存信息 + */ +@Data +public class ModelRedisInfoDto { + + @ApiModelProperty("模板id") + private String modelId; + + @ApiModelProperty("模板名称") + private String modelName; + + @ApiModelProperty("模板时间") + private LocalDate versionDate; + + @ApiModelProperty("模板版本") + private String version; + + @ApiModelProperty("数据集集合") + private List dataSetList; + + @Data + public static class DataSet { + + @ApiModelProperty("数据集id") + private String dataSetId; + + @ApiModelProperty("数据集名称") + private String dataSetName; + + @ApiModelProperty("数据指标集合") + private List dataArrayList; + } + + @Data + public static class DataArray { + + @ApiModelProperty("数据指标id") + private String dataArrayId; + + @ApiModelProperty("数据指标名称") + private String dataArrayName; + + @ApiModelProperty("数据指标别名") + private String anotherName; + + @ApiModelProperty("数据指标统计方式") + private String statMethod; + + @ApiModelProperty("数据指标相别") + private String phase; + } + +} diff --git a/iot-access/access-api/src/main/java/com/njcn/access/pojo/dto/UploadFileDto.java b/iot-access/access-api/src/main/java/com/njcn/access/pojo/dto/UploadFileDto.java index b2a4835..c16ff41 100644 --- a/iot-access/access-api/src/main/java/com/njcn/access/pojo/dto/UploadFileDto.java +++ b/iot-access/access-api/src/main/java/com/njcn/access/pojo/dto/UploadFileDto.java @@ -34,4 +34,8 @@ public class UploadFileDto { @ApiModelProperty("文件校验码") private String fileCheck; + @SerializedName("StepFileCheck") + @ApiModelProperty("当前帧文件校验码") + private String stepFileCheck; + } diff --git a/iot-access/access-api/src/main/java/com/njcn/access/pojo/dto/file/FileDto.java b/iot-access/access-api/src/main/java/com/njcn/access/pojo/dto/file/FileDto.java index 2b0d3ec..2a57019 100644 --- a/iot-access/access-api/src/main/java/com/njcn/access/pojo/dto/file/FileDto.java +++ b/iot-access/access-api/src/main/java/com/njcn/access/pojo/dto/file/FileDto.java @@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.io.Serializable; +import java.util.List; /** * 类的介绍: @@ -42,7 +43,10 @@ public class FileDto implements Serializable { private String type; @SerializedName("FileInfo") - private FileDto.FileInfo fileInfo; + private FileInfo fileInfo; + + @SerializedName("DirInfo") + private List dirInfo; @SerializedName("Data") private String data; @@ -86,4 +90,22 @@ public class FileDto implements Serializable { private String fileChkType; } + @Data + public static class DirInfo{ + + @SerializedName("Name") + private String name; + + @SerializedName("Type") + private String type; + + @SerializedName("Size") + @ApiModelProperty("文件大小,单位KB") + private Integer size; + + @SerializedName("Time") + @ApiModelProperty("时间") + private Long time; + } + } diff --git a/iot-access/access-api/src/main/java/com/njcn/access/pojo/po/CsSoftInfoPO.java b/iot-access/access-api/src/main/java/com/njcn/access/pojo/po/CsSoftInfoPO.java index a6c8204..182c7be 100644 --- a/iot-access/access-api/src/main/java/com/njcn/access/pojo/po/CsSoftInfoPO.java +++ b/iot-access/access-api/src/main/java/com/njcn/access/pojo/po/CsSoftInfoPO.java @@ -1,10 +1,8 @@ package com.njcn.access.pojo.po; import com.baomidou.mybatisplus.annotation.TableName; -import com.njcn.db.bo.BaseEntity; import lombok.Data; -import java.time.LocalDate; import java.time.LocalDateTime; import java.util.Date; @@ -47,7 +45,7 @@ public class CsSoftInfoPO { /** * 应用程序发布日期 */ - private Date appDate; + private LocalDateTime appDate; /** * 应用程序校验码 diff --git a/iot-access/access-boot/src/main/java/com/njcn/access/utils/CRC32Utils.java b/iot-access/access-api/src/main/java/com/njcn/access/utils/CRC32Utils.java similarity index 96% rename from iot-access/access-boot/src/main/java/com/njcn/access/utils/CRC32Utils.java rename to iot-access/access-api/src/main/java/com/njcn/access/utils/CRC32Utils.java index d369109..b23095a 100644 --- a/iot-access/access-boot/src/main/java/com/njcn/access/utils/CRC32Utils.java +++ b/iot-access/access-api/src/main/java/com/njcn/access/utils/CRC32Utils.java @@ -1,8 +1,11 @@ package com.njcn.access.utils; +import org.springframework.stereotype.Component; + /** * @author xy */ +@Component public class CRC32Utils { // CRC-32/MPEG-2 多项式, x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1 diff --git a/iot-access/access-api/src/main/java/com/njcn/access/utils/ChannelObjectUtil.java b/iot-access/access-api/src/main/java/com/njcn/access/utils/ChannelObjectUtil.java new file mode 100644 index 0000000..c17d7dd --- /dev/null +++ b/iot-access/access-api/src/main/java/com/njcn/access/utils/ChannelObjectUtil.java @@ -0,0 +1,45 @@ +package com.njcn.access.utils; + +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author xy + */ +@Component +public class ChannelObjectUtil { + + /** + * 将list转成对应实体 + * @param object + * @param clazz + * @return + * @param + */ + public List objectToList(Object object, Class clazz) { + List resultList = new ArrayList<>(); + if (object instanceof List) { + for (Object o : (List) object) { + resultList.add(clazz.cast(o)); + } + } + return resultList; + } + + /** + * 将object转成对应实体 + * @param object + * @param clazz + * @return + * @param + */ + public T objectToSingleObject(Object object, Class clazz) { + if (clazz.isInstance(object)) { + return clazz.cast(object); + } + // 或者抛出异常,根据您的需求 + return null; + } +} diff --git a/iot-access/access-boot/src/main/java/com/njcn/access/utils/JsonUtil.java b/iot-access/access-api/src/main/java/com/njcn/access/utils/JsonUtil.java similarity index 100% rename from iot-access/access-boot/src/main/java/com/njcn/access/utils/JsonUtil.java rename to iot-access/access-api/src/main/java/com/njcn/access/utils/JsonUtil.java diff --git a/iot-access/access-boot/src/main/java/com/njcn/access/utils/MqttUtil.java b/iot-access/access-api/src/main/java/com/njcn/access/utils/MqttUtil.java similarity index 100% rename from iot-access/access-boot/src/main/java/com/njcn/access/utils/MqttUtil.java rename to iot-access/access-api/src/main/java/com/njcn/access/utils/MqttUtil.java diff --git a/iot-access/access-boot/pom.xml b/iot-access/access-boot/pom.xml index 6345f2e..786f3ab 100644 --- a/iot-access/access-boot/pom.xml +++ b/iot-access/access-boot/pom.xml @@ -63,7 +63,12 @@ common-mq ${project.version} - + + com.njcn + zl-event-api + 1.0.0 + compile + diff --git a/iot-access/access-boot/src/main/java/com/njcn/access/controller/AskDeviceDataController.java b/iot-access/access-boot/src/main/java/com/njcn/access/controller/AskDeviceDataController.java new file mode 100644 index 0000000..ac1c22a --- /dev/null +++ b/iot-access/access-boot/src/main/java/com/njcn/access/controller/AskDeviceDataController.java @@ -0,0 +1,85 @@ +package com.njcn.access.controller; + +import com.njcn.access.service.AskDeviceDataService; +import com.njcn.common.pojo.annotation.OperateInfo; +import com.njcn.common.pojo.enums.common.LogEnum; +import com.njcn.common.pojo.enums.response.CommonResponseEnum; +import com.njcn.common.pojo.response.HttpResult; +import com.njcn.common.utils.HttpResultUtil; +import com.njcn.web.controller.BaseController; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author xy + */ +@Slf4j +@RestController +@RequestMapping("/askDeviceData") +@Api(tags = "平台操作装置报文") +@AllArgsConstructor +//@ApiIgnore +public class AskDeviceDataController extends BaseController { + + private final AskDeviceDataService askDeviceDataService; + + @OperateInfo(info = LogEnum.BUSINESS_COMMON) + @PostMapping("/askDeviceRootPath") + @ApiOperation("设备根目录询问") + @ApiImplicitParam(name = "nDid", value = "nDid", required = true) + public HttpResult askDeviceRootPath(@RequestParam("nDid") String nDid){ + String methodDescribe = getMethodDescribe("askDeviceRootPath"); + askDeviceDataService.askDeviceRootPath(nDid); + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, null, methodDescribe); + } + + @OperateInfo(info = LogEnum.BUSINESS_COMMON) + @PostMapping("/askDeviceFileOrDir") + @ApiOperation("设备文件/目录信息询问") + @ApiImplicitParams({ + @ApiImplicitParam(name = "nDid", value = "nDid", required = true), + @ApiImplicitParam(name = "name", value = "name", required = true) + }) + public HttpResult askDeviceFileOrDir(@RequestParam("nDid") String nDid, @RequestParam("name") String name){ + String methodDescribe = getMethodDescribe("askDeviceFileOrDir"); + askDeviceDataService.askDeviceFileOrDir(nDid,name); + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, null, methodDescribe); + } + + @OperateInfo(info = LogEnum.BUSINESS_COMMON) + @PostMapping("/downloadFile") + @ApiOperation("设备文件下载") + @ApiImplicitParams({ + @ApiImplicitParam(name = "nDid", value = "nDid", required = true), + @ApiImplicitParam(name = "name", value = "文件路径名", required = true), + @ApiImplicitParam(name = "size", value = "文件大小(单位byte)", required = true), + @ApiImplicitParam(name = "fileCheck", value = "文件校验码", required = true) + }) + public HttpResult downloadFile(@RequestParam("nDid") String nDid, @RequestParam("name") String name, @RequestParam("size") Integer size, @RequestParam("fileCheck") String fileCheck){ + String methodDescribe = getMethodDescribe("downloadFile"); + boolean result = askDeviceDataService.downloadFile(nDid,name,size,fileCheck); + if (result) { + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, true, methodDescribe); + } else { + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.FAIL, false, methodDescribe); + } + } + + @OperateInfo(info = LogEnum.BUSINESS_COMMON) + @PostMapping("/rebootDevice") + @ApiOperation("重启设备") + @ApiImplicitParam(name = "nDid", value = "nDid", required = true) + public HttpResult rebootDevice(@RequestParam("nDid") String nDid){ + String methodDescribe = getMethodDescribe("rebootDevice"); + askDeviceDataService.rebootDevice(nDid); + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, null, methodDescribe); + } +} diff --git a/iot-access/access-boot/src/main/java/com/njcn/access/controller/CsDeviceController.java b/iot-access/access-boot/src/main/java/com/njcn/access/controller/CsDeviceController.java index 098d213..e9fffc5 100644 --- a/iot-access/access-boot/src/main/java/com/njcn/access/controller/CsDeviceController.java +++ b/iot-access/access-boot/src/main/java/com/njcn/access/controller/CsDeviceController.java @@ -37,7 +37,7 @@ public class CsDeviceController extends BaseController { @OperateInfo(info = LogEnum.BUSINESS_COMMON) @PostMapping("/register") - @ApiOperation("直连设备状态判断") + @ApiOperation("直连设备注册") @ApiImplicitParams({ @ApiImplicitParam(name = "nDid", value = "设备识别码", required = true), @ApiImplicitParam(name = "type", value = "流程标识(2:功能调试 3:出厂调试 4:设备注册)", required = true) @@ -62,7 +62,7 @@ public class CsDeviceController extends BaseController { @OperateInfo(info = LogEnum.BUSINESS_COMMON) @PostMapping("/access") - @ApiOperation("直连设备注册") + @ApiOperation("直连设备接入") @ApiImplicitParam(name = "devAccessParam", value = "接入参数", required = true) public HttpResult devAccess(@RequestBody @Validated DevAccessParam devAccessParam){ String methodDescribe = getMethodDescribe("devAccess"); diff --git a/iot-access/access-boot/src/main/java/com/njcn/access/controller/CsSoftInfoController.java b/iot-access/access-boot/src/main/java/com/njcn/access/controller/CsSoftInfoController.java index a927f60..77b9d7c 100644 --- a/iot-access/access-boot/src/main/java/com/njcn/access/controller/CsSoftInfoController.java +++ b/iot-access/access-boot/src/main/java/com/njcn/access/controller/CsSoftInfoController.java @@ -1,10 +1,24 @@ package com.njcn.access.controller; -import org.springframework.web.bind.annotation.RequestMapping; - -import org.springframework.web.bind.annotation.RestController; +import com.njcn.access.mapper.CsSoftInfoMapper; +import com.njcn.access.pojo.po.CsSoftInfoPO; +import com.njcn.common.pojo.annotation.OperateInfo; +import com.njcn.common.pojo.enums.common.LogEnum; +import com.njcn.common.pojo.enums.response.CommonResponseEnum; +import com.njcn.common.pojo.response.HttpResult; +import com.njcn.common.utils.HttpResultUtil; import com.njcn.web.controller.BaseController; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; /** *

@@ -14,9 +28,25 @@ import com.njcn.web.controller.BaseController; * @author xuyang * @since 2023-08-09 */ +@Slf4j @RestController @RequestMapping("/csSoftInfo") +@Api(tags = "装置程序信息") +@AllArgsConstructor +@Validated public class CsSoftInfoController extends BaseController { + private final CsSoftInfoMapper csSoftInfoMapper; + + @OperateInfo(info = LogEnum.BUSINESS_COMMON) + @PostMapping("/findSoftInfo") + @ApiOperation("获取程序软件信息") + @ApiImplicitParam(name = "id", value = "id", required = true) + public HttpResult findSoftInfo(@RequestParam String id){ + String methodDescribe = getMethodDescribe("findSoftInfo"); + CsSoftInfoPO po = csSoftInfoMapper.selectById(id); + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, po, methodDescribe); + } + } diff --git a/iot-access/access-boot/src/main/java/com/njcn/access/controller/CsTopicController.java b/iot-access/access-boot/src/main/java/com/njcn/access/controller/CsTopicController.java index 3fc63b8..f44bde9 100644 --- a/iot-access/access-boot/src/main/java/com/njcn/access/controller/CsTopicController.java +++ b/iot-access/access-boot/src/main/java/com/njcn/access/controller/CsTopicController.java @@ -1,6 +1,5 @@ package com.njcn.access.controller; -import com.njcn.access.pojo.po.CsLineModel; import com.njcn.access.service.ICsTopicService; import com.njcn.common.pojo.annotation.OperateInfo; import com.njcn.common.pojo.enums.common.LogEnum; @@ -13,7 +12,10 @@ import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; import springfox.documentation.annotations.ApiIgnore; /** diff --git a/iot-access/access-boot/src/main/java/com/njcn/access/handler/MqttMessageHandler.java b/iot-access/access-boot/src/main/java/com/njcn/access/handler/MqttMessageHandler.java index b2301af..03cd040 100644 --- a/iot-access/access-boot/src/main/java/com/njcn/access/handler/MqttMessageHandler.java +++ b/iot-access/access-boot/src/main/java/com/njcn/access/handler/MqttMessageHandler.java @@ -57,9 +57,14 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.Instant; import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.temporal.ChronoField; import java.util.*; import java.util.stream.Collectors; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + /** * @author hongawen * @version 1.0.0 @@ -350,6 +355,9 @@ public class MqttMessageHandler { onlineLogsService.save(csDeviceOnlineLogs); } } + //修改redis的mid + redisUtil.saveByKey(AppRedisKey.DEVICE_MID + nDid,1); + redisUtil.saveByKeyWithExpire("online" + nDid,"online",10L); //询问设备软件信息 askDevData(nDid,version,1,mid); //更新治理监测点信息和设备容量 @@ -374,23 +382,28 @@ public class MqttMessageHandler { //记录设备软件信息 CsSoftInfoPO csSoftInfoPo = new CsSoftInfoPO(); BeanUtils.copyProperties(softInfo,csSoftInfoPo); - try { - String id = IdUtil.fastSimpleUUID(); - csSoftInfoPo.setId(id); - csSoftInfoPo.setAppDate(new SimpleDateFormat("yyyy-MM-dd").parse(softInfo.getAppDate())); - csSoftInfoService.save(csSoftInfoPo); - //更新设备软件id 先看是否存在软件信息,删除 然后在录入 - CsEquipmentDeliveryPO po = equipmentFeignClient.findDevByNDid(nDid).getData(); - String soft = po.getSoftinfoId(); - if (StringUtil.isNotBlank(soft)){ - csSoftInfoService.removeById(soft); - } - equipmentFeignClient.updateSoftInfo(nDid,csSoftInfoPo.getId()); - //询问设备容量信息 - //askDevData(nDid,version,2,(res.getMid()+1)); - } catch (ParseException e) { - e.printStackTrace(); + String id = IdUtil.fastSimpleUUID(); + csSoftInfoPo.setId(id); + DateTimeFormatter formatter = new DateTimeFormatterBuilder() + .appendPattern("yyyy-MM-dd[[HH][:mm][:ss]]") + .parseDefaulting(ChronoField.HOUR_OF_DAY, 0) + .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0) + .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0) + .parseDefaulting(ChronoField.MILLI_OF_SECOND, 0) + .toFormatter(); + LocalDateTime localDateTime = LocalDateTime.parse(softInfo.getAppDate(), formatter); + assertThat(localDateTime).isNotNull(); + csSoftInfoPo.setAppDate(localDateTime); + csSoftInfoService.save(csSoftInfoPo); + //更新设备软件id 先看是否存在软件信息,删除 然后在录入 + CsEquipmentDeliveryPO po = equipmentFeignClient.findDevByNDid(nDid).getData(); + String soft = po.getSoftinfoId(); + if (StringUtil.isNotBlank(soft)){ + csSoftInfoService.removeById(soft); } + equipmentFeignClient.updateSoftInfo(nDid,csSoftInfoPo.getId()); + //询问设备容量信息 + //askDevData(nDid,version,2,(res.getMid()+1)); break; case 2: List devInfo = JSON.parseArray(JSON.toJSONString(rspDataDto.getDataArray()), RspDataDto.LdevInfo.class); @@ -436,10 +449,24 @@ public class MqttMessageHandler { } } break; + case 48: + log.info("询问装置项目列表"); + logDto.setOperate("监测点:" + (nDid + rspDataDto.getClDid()) + "询问项目列表"); + List projectInfoList = JSON.parseArray(JSON.toJSONString(rspDataDto.getDataArray()), RspDataDto.ProjectInfo.class); + String key = AppRedisKey.PROJECT_INFO + nDid + rspDataDto.getClDid(); + redisUtil.saveByKeyWithExpire(key,projectInfoList,60L); + break; default: break; } break; + case 4663: + log.info("装置操作应答"); + if (Objects.equals(res.getCode(),AccessEnum.SUCCESS.getCode())){ + String key = AppRedisKey.CONTROL + nDid; + redisUtil.saveByKeyWithExpire(key,"success",10L); + } + break; default: break; } @@ -510,7 +537,7 @@ public class MqttMessageHandler { } //判断事件类型 switch (dataDto.getMsg().getDataAttr()) { - //暂态事件、录波处理 + //暂态事件、录波处理、工程信息 case 0: log.info(nDid + "事件报文为:" + new String(message.getPayload(), StandardCharsets.UTF_8)); EventDto eventDto = gson.fromJson(new String(message.getPayload(), StandardCharsets.UTF_8), EventDto.class); @@ -562,12 +589,24 @@ public class MqttMessageHandler { //响应请求 switch (fileDto.getType()){ case 4657: - log.info("获取文件信息"); - log.info("文件信息响应:" + fileDto); - appFileMessageTemplate.sendMember(appFileMessage); + log.info("获取文件信息" + fileDto); + String key = AppRedisKey.PROJECT_INFO + nDid; + if (Objects.isNull(fileDto.getMsg().getType())) { + handleDefaultCase(fileDto, nDid); + } else { + if (Objects.equals("dir", fileDto.getMsg().getType())) { + saveDirectoryInfo(fileDto.getMsg().getDirInfo(), key); + } else if (Objects.equals("file", fileDto.getMsg().getType())){ + saveFileInfo(fileDto.getMsg().getFileInfo(), key); + appFileMessageTemplate.sendMember(appFileMessage); + } + } break; case 4658: log.info("获取文件流信息"); + FileRedisDto dto = new FileRedisDto(); + dto.setCode(fileDto.getCode()); + redisUtil.saveByKeyWithExpire(AppRedisKey.DOWNLOAD + fileDto.getMsg().getName() + fileDto.getMid(),dto,10L); if (Objects.equals(fileDto.getCode(),AccessEnum.SUCCESS.getCode())){ appFileStreamMessageTemplate.sendMember(appFileMessage); } @@ -576,17 +615,42 @@ public class MqttMessageHandler { log.info("需要缓存请求的文件信息"); } break; - case 4659: - log.info("装置收到系统上传的文件"); - FileRedisDto fileRedisDto = new FileRedisDto(); - fileRedisDto.setCode(fileDto.getCode()); - redisUtil.saveByKeyWithExpire("uploadFileStep",fileRedisDto,10L); - break; + case 4659: + log.info("装置收到系统上传的文件"); + FileRedisDto fileRedisDto = new FileRedisDto(); + fileRedisDto.setCode(fileDto.getCode()); + redisUtil.saveByKeyWithExpire(AppRedisKey.UPLOAD,fileRedisDto,10L); + redisUtil.saveByKeyWithExpire("uploading","uploading",20L); + break; + case 4662: + log.info("装置根目录应答"); + redisUtil.saveByKeyWithExpire(AppRedisKey.DEVICE_ROOT_PATH + nDid,fileDto.getMsg().getName(),10L); default: break; } } + private void saveDirectoryInfo(List dirInfo, String key) { + if (!CollectionUtil.isEmpty(dirInfo)) { + redisUtil.saveByKeyWithExpire(key, dirInfo, 10L); + } + } + + private void saveFileInfo(FileDto.FileInfo fileInfo, String key) { + if (!Objects.isNull(fileInfo)) { + redisUtil.saveByKeyWithExpire(key, fileInfo, 10L); + } + } + + private void handleDefaultCase(FileDto fileDto, String nDid) { + List list = fileDto.getMsg().getDirInfo(); + String keyDir = AppRedisKey.PROJECT_INFO + nDid; + saveDirectoryInfo(list, keyDir); + + FileDto.FileInfo fileInfo = fileDto.getMsg().getFileInfo(); + String keyFile = AppRedisKey.FILE_INFO + nDid; + saveFileInfo(fileInfo, keyFile); + } /** * type含义 @@ -635,5 +699,4 @@ public class MqttMessageHandler { publisher.send("/Pfm/DevCmd/"+version+"/"+nDid, new Gson().toJson(reqAndResParam),1,false); } - } diff --git a/iot-access/access-boot/src/main/java/com/njcn/access/listener/RedisKeyExpirationListener.java b/iot-access/access-boot/src/main/java/com/njcn/access/listener/RedisKeyExpirationListener.java index eb41278..e943c26 100644 --- a/iot-access/access-boot/src/main/java/com/njcn/access/listener/RedisKeyExpirationListener.java +++ b/iot-access/access-boot/src/main/java/com/njcn/access/listener/RedisKeyExpirationListener.java @@ -1,12 +1,24 @@ package com.njcn.access.listener; +import com.alibaba.nacos.shaded.com.google.gson.Gson; import com.njcn.access.enums.AccessEnum; import com.njcn.access.service.ICsDeviceOnlineLogsService; import com.njcn.access.service.ICsEquipmentDeliveryService; import com.njcn.access.service.ICsTopicService; import com.njcn.access.service.impl.CsDeviceServiceImpl; +import com.njcn.access.utils.MqttUtil; import com.njcn.common.pojo.dto.DeviceLogDTO; +import com.njcn.csdevice.api.CsDeviceUserFeignClient; +import com.njcn.csdevice.api.CsLedgerFeignClient; import com.njcn.csdevice.api.CsLogsFeignClient; +import com.njcn.csdevice.api.EquipmentFeignClient; +import com.njcn.csdevice.pojo.dto.DevDetailDTO; +import com.njcn.csdevice.pojo.po.CsEquipmentDeliveryPO; +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.zlevent.pojo.dto.NoticeUserDto; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.data.redis.connection.Message; @@ -15,11 +27,22 @@ import org.springframework.data.redis.listener.RedisMessageListenerContainer; import org.springframework.stereotype.Component; import javax.annotation.Resource; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; import java.util.Objects; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; /** * @author xy @@ -32,27 +55,39 @@ public class RedisKeyExpirationListener extends KeyExpirationEventMessageListene @Resource private ICsTopicService csTopicService; - @Resource private ICsEquipmentDeliveryService csEquipmentDeliveryService; - @Resource private CsDeviceServiceImpl csDeviceService; - @Resource private CsLogsFeignClient csLogsFeignClient; - @Resource private ICsDeviceOnlineLogsService onlineLogsService; + @Resource + private MqttUtil mqttUtil; + @Resource + private CsLedgerFeignClient csLedgerFeignclient; + @Resource + private EquipmentFeignClient equipmentFeignClient; + @Resource + private AppUserFeignClient appUserFeignClient; + @Resource + private CsDeviceUserFeignClient csDeviceUserFeignClient; + @Resource + private UserFeignClient userFeignClient; + @Resource + private RedisUtil redisUtil; + + private final Object lock = new Object(); public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) { super(listenerContainer); } - // 最大尝试次数 - private static final int MAX_ATTEMPTS = 4; // 当前尝试次数 private static int attemptCount = 1; + //最大告警次数 + private static int MAX_WARNING_TIMES = 0; /** * 针对redis数据失效事件,进行数据处理 @@ -74,66 +109,176 @@ public class RedisKeyExpirationListener extends KeyExpirationEventMessageListene } //主任务 + //1.装置心跳断连 + //2.MQTT客户端不在线 private void executeMainTask(ScheduledExecutorService scheduler, String nDid, String version) { System.out.println("正在执行主任务..."); DeviceLogDTO logDto = new DeviceLogDTO(); logDto.setUserName("装置失去心跳触发"); - logDto.setOperate(nDid + "重连"); - //装置下线 - csEquipmentDeliveryService.updateRunStatusBynDid(nDid, AccessEnum.OFFLINE.getCode()); - //装置没有心跳,则立马发起接入请求 - csDeviceService.devAccessAskTemplate(nDid,version,1); - Integer status = csEquipmentDeliveryService.queryEquipmentBynDid(nDid).getRunStatus(); - if (Objects.equals(status,AccessEnum.ONLINE.getCode())){ - logDto.setResult(1); - scheduler.shutdown(); - } else { - logDto.setResult(0); + //判断mqtt + String clientName = "NJCN-" + nDid.substring(nDid.length() - 6); + boolean mqttClient = mqttUtil.judgeClientOnline(clientName); + //心跳异常,但是客户端在线,则发送接入请求 + //这边可能存在装置已经掉线,但是客户端仍然在线的情况 + if (mqttClient) { + csDeviceService.devAccessAskTemplate(nDid,version,1); + try { + Thread.sleep(2000); + Object object = redisUtil.getObjectByKey("online" + nDid); + if (Objects.nonNull(object)) { + scheduler.shutdown(); + logDto.setOperate("客户端在线重连成功"); + } else { + //装置下线 + csEquipmentDeliveryService.updateRunStatusBynDid(nDid, AccessEnum.OFFLINE.getCode()); + startScheduledTask(scheduler,nDid,version); + logDto.setOperate("客户端离线进入定时任务"); + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + //客户端不在线则修改装置状态,进入定时任务 + else { + //装置下线 + csEquipmentDeliveryService.updateRunStatusBynDid(nDid, AccessEnum.OFFLINE.getCode()); startScheduledTask(scheduler,nDid,version); } csLogsFeignClient.addUserLog(logDto); } - //启动第一次定时任务 private void startScheduledTask(ScheduledExecutorService scheduler, String nDid, String version) { - ScheduledFuture future = scheduler.scheduleAtFixedRate(() -> { - DeviceLogDTO logDto = new DeviceLogDTO(); - logDto.setOperate(nDid + "第一阶段重连定时任务"); - if (attemptCount < MAX_ATTEMPTS) { - System.out.println(nDid + "执行第一阶段重连定时任务,第 " + attemptCount + " 次尝试..."); - attemptCount++; - csDeviceService.devAccessAskTemplate(nDid,version,attemptCount); - int status = csEquipmentDeliveryService.queryEquipmentBynDid(nDid).getRunStatus(); - if (Objects.equals(status,AccessEnum.ONLINE.getCode())){ - logDto.setResult(1); - scheduler.shutdown(); + synchronized (lock) { + NoticeUserDto dto = sendOffLine(nDid); + sendEventToUser(dto); + String clientName = "NJCN-" + nDid.substring(nDid.length() - 6); + ScheduledFuture future = scheduler.scheduleAtFixedRate(() -> { + System.out.println(nDid + "执行重连定时任务..."); + DeviceLogDTO logDto = new DeviceLogDTO(); + logDto.setOperate(nDid + "重连定时任务"); + //判断客户端 + boolean mqttClient = mqttUtil.judgeClientOnline(clientName); + if (mqttClient) { + csDeviceService.devAccessAskTemplate(nDid,version,attemptCount++); + Integer status = csEquipmentDeliveryService.queryEquipmentBynDid(nDid).getRunStatus(); + if (Objects.equals(status,AccessEnum.ONLINE.getCode())){ + logDto.setResult(1); + scheduler.shutdown(); + return; + } else { + logDto.setResult(0); + //重连三次仍未成功,则推送告警消息 + MAX_WARNING_TIMES++; + if (MAX_WARNING_TIMES == 3) { + NoticeUserDto dto2 = sendConnectFail(nDid); + sendEventToUser(dto2); + } + } + } else { + //重连三次仍未成功,则推送告警消息 + MAX_WARNING_TIMES++; + if (MAX_WARNING_TIMES == 3) { + NoticeUserDto dto2 = sendConnectFail(nDid); + sendEventToUser(dto2); + } + logDto.setResult(0); } - } else { - scheduler.shutdown(); - attemptCount++; - logDto.setResult(0); - startSecondScheduledTask(nDid,version); - } - csLogsFeignClient.addUserLog(logDto); - }, 0, 1, TimeUnit.MINUTES); + csLogsFeignClient.addUserLog(logDto); + }, 0, 5, TimeUnit.SECONDS); + } } - //启动第二个定时任务 - private void startSecondScheduledTask(String nDid, String version) { - ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); - ScheduledFuture future = scheduler.scheduleAtFixedRate(() -> { - System.out.println(nDid + "执行第二阶段重连定时任务..."); - DeviceLogDTO logDto = new DeviceLogDTO(); - logDto.setOperate(nDid + "第二阶段重连定时任务"); - csDeviceService.devAccessAskTemplate(nDid,version,attemptCount++); - int status = csEquipmentDeliveryService.queryEquipmentBynDid(nDid).getRunStatus(); - if (Objects.equals(status,AccessEnum.ONLINE.getCode())) { - logDto.setResult(1); - scheduler.shutdown(); - } else { - logDto.setResult(0); - } - csLogsFeignClient.addUserLog(logDto); - }, 0, 10, TimeUnit.MINUTES); + //掉线通知 + private NoticeUserDto sendOffLine(String nDid) { + NoticeUserDto dto = new NoticeUserDto(); + NoticeUserDto.Payload payload = new NoticeUserDto.Payload(); + dto.setTitle("设备离线"); + CsEquipmentDeliveryPO po = equipmentFeignClient.findDevByNDid(nDid).getData(); + DevDetailDTO devDetailDto = csLedgerFeignclient.queryDevDetail(po.getId()).getData(); + DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + LocalDateTime localDateTime = LocalDateTime.now(); + String dateStr = localDateTime.format(fmt); + String content = String.format(devDetailDto.getEngineeringName() + "-" + devDetailDto.getProjectName() + "-" + devDetailDto.getEquipmentName() + "于" + dateStr + "离线"); + dto.setContent(content); + dto.setPushClientId(getEventUser(po.getId(),true)); + payload.setType(3); + payload.setPath("/pages/message/message?type="+payload.getType()); + dto.setPayload(payload); + return dto; } + + //重连失败通知 + private NoticeUserDto sendConnectFail(String nDid) { + NoticeUserDto dto = new NoticeUserDto(); + NoticeUserDto.Payload payload = new NoticeUserDto.Payload(); + dto.setTitle("设备接入失败"); + CsEquipmentDeliveryPO po = equipmentFeignClient.findDevByNDid(nDid).getData(); + DevDetailDTO devDetailDto = csLedgerFeignclient.queryDevDetail(po.getId()).getData(); + DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + LocalDateTime localDateTime = LocalDateTime.now(); + String dateStr = localDateTime.format(fmt); + String content = String.format(devDetailDto.getEngineeringName() + "-" + devDetailDto.getProjectName() + "-" + devDetailDto.getEquipmentName() + "于" + dateStr + "多次接入失败"); + dto.setContent(content); + dto.setPushClientId(getEventUser(po.getId(),true)); + payload.setType(3); + payload.setPath("/pages/message/message?type="+payload.getType()); + dto.setPayload(payload); + + return dto; + } + + + /** + * 获取所有需要推送的用户id + */ + public List getEventUser(String devId, boolean isAdmin) { + List adminUser = appUserFeignClient.getAdminInfo().getData(); + List adminList = adminUser.stream().map(User::getId).collect(Collectors.toList()); + if (isAdmin) { + List list = csDeviceUserFeignClient.findUserById(devId).getData(); + adminList.addAll(list); + } + List users = userFeignClient.appuserByIdList(adminList).getData(); + return users.stream().map(User::getDevCode).filter(Objects::nonNull).filter(StringUtils::isNotBlank).distinct().collect(Collectors.toList()); + } + + public void sendEventToUser(NoticeUserDto noticeUserDto) { + try { + // 创建一个URL对象,指定目标HTTPS接口地址 + URL url = new URL("https://fc-mp-ff7b310f-94c9-4468-8260-109111c0a6b2.next.bspapp.com/push"); + // 打开HTTPS连接 + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + // 设置请求方法为POST + connection.setRequestMethod("POST"); + // 设置请求头,指定Content-Type为application/json + connection.setRequestProperty("Content-Type", "application/json"); + // 启用输出流以发送JSON数据 + connection.setDoOutput(true); + // 将JSON数据写入输出流 + OutputStream outputStream = connection.getOutputStream(); + log.info(new Gson().toJson(noticeUserDto).replace("pushClientId", "push_clientid")); + outputStream.write(new Gson().toJson(noticeUserDto).replace("pushClientId", "push_clientid").getBytes(StandardCharsets.UTF_8)); + outputStream.flush(); + outputStream.close(); + // 获取响应代码 + int responseCode = connection.getResponseCode(); + log.info("Response Code: " + responseCode); + // 读取响应数据 + BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + String inputLine; + StringBuilder response = new StringBuilder(); + while ((inputLine = reader.readLine()) != null) { + response.append(inputLine); + } + reader.close(); + // 打印响应内容 + log.info("Response Content: " + response.toString()); + // 关闭连接 + connection.disconnect(); + } catch (IOException e) { + e.getMessage(); + } + } + + } diff --git a/iot-access/access-boot/src/main/java/com/njcn/access/runner/AccessApplicationRunner.java b/iot-access/access-boot/src/main/java/com/njcn/access/runner/AccessApplicationRunner.java index 260546c..fd2a1f9 100644 --- a/iot-access/access-boot/src/main/java/com/njcn/access/runner/AccessApplicationRunner.java +++ b/iot-access/access-boot/src/main/java/com/njcn/access/runner/AccessApplicationRunner.java @@ -1,47 +1,45 @@ -//package com.njcn.access.runner; -// -//import com.njcn.access.service.ICsEquipmentDeliveryService; -//import com.njcn.access.service.ICsTopicService; -//import com.njcn.access.service.impl.CsDeviceServiceImpl; -//import com.njcn.csdevice.pojo.po.CsEquipmentDeliveryPO; -//import lombok.extern.slf4j.Slf4j; -//import org.springframework.boot.ApplicationArguments; -//import org.springframework.boot.ApplicationRunner; -//import org.springframework.stereotype.Component; -// -//import javax.annotation.Resource; -//import java.util.List; -//import java.util.Objects; -// -///** -// * 类的介绍:用来重新发起设备的接入,存在程序意外停止了,缓存失效导致无法更新装置的状态,所以需要在程序启动时发起设备的接入 -// * -// * @author xuyang -// * @version 1.0.0 -// * @createTime 2023/8/28 13:57 -// */ -//@Component -//@Slf4j -//public class AccessApplicationRunner implements ApplicationRunner { -// -// @Resource -// private CsDeviceServiceImpl csDeviceService; -// -// @Resource -// private ICsTopicService csTopicService; -// -// @Resource -// private ICsEquipmentDeliveryService csEquipmentDeliveryService; -// -// @Override -// public void run(ApplicationArguments args){ -// List list = csEquipmentDeliveryService.getAll(); -// list.forEach(item->{ -// String version = csTopicService.getVersion(item.getNdid()); -// if (!Objects.isNull(version)){ -// csDeviceService.devAccess(item.getNdid(),version,1); -// } -// }); -// } -// -//} +package com.njcn.access.runner; + +import com.njcn.access.service.ICsEquipmentDeliveryService; +import com.njcn.access.service.ICsTopicService; +import com.njcn.access.service.impl.CsDeviceServiceImpl; +import com.njcn.csdevice.pojo.po.CsEquipmentDeliveryPO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Objects; + +/** + * 类的介绍:用来重新发起设备的接入,存在程序意外停止了,缓存失效导致无法更新装置的状态,所以需要在程序启动时发起设备的接入 + * + * @author xuyang + * @version 1.0.0 + * @createTime 2023/8/28 13:57 + */ +@Component +@Slf4j +public class AccessApplicationRunner implements ApplicationRunner { + + @Resource + private CsDeviceServiceImpl csDeviceService; + @Resource + private ICsTopicService csTopicService; + @Resource + private ICsEquipmentDeliveryService csEquipmentDeliveryService; + + @Override + public void run(ApplicationArguments args){ + List list = csEquipmentDeliveryService.getAll(); + list.forEach(item->{ + String version = csTopicService.getVersion(item.getNdid()); + if (!Objects.isNull(version)){ + csDeviceService.devAccessAskTemplate(item.getNdid(),version,1); + } + }); + } + +} diff --git a/iot-access/access-boot/src/main/java/com/njcn/access/service/AskDeviceDataService.java b/iot-access/access-boot/src/main/java/com/njcn/access/service/AskDeviceDataService.java new file mode 100644 index 0000000..cd59008 --- /dev/null +++ b/iot-access/access-boot/src/main/java/com/njcn/access/service/AskDeviceDataService.java @@ -0,0 +1,15 @@ +package com.njcn.access.service; + +/** + * @author xy + */ +public interface AskDeviceDataService { + + void askDeviceRootPath(String nDid); + + void askDeviceFileOrDir(String nDid, String name); + + boolean downloadFile(String nDid, String name, Integer size, String fileCheck); + + void rebootDevice(String nDid); +} diff --git a/iot-access/access-boot/src/main/java/com/njcn/access/service/ICsDevModelService.java b/iot-access/access-boot/src/main/java/com/njcn/access/service/ICsDevModelService.java index c44bb11..71c958a 100644 --- a/iot-access/access-boot/src/main/java/com/njcn/access/service/ICsDevModelService.java +++ b/iot-access/access-boot/src/main/java/com/njcn/access/service/ICsDevModelService.java @@ -14,6 +14,11 @@ import java.util.List; public interface ICsDevModelService { + /** + * 初始化缓存模板信息 + */ + void refreshDevModelCache(); + /** * 解析模板文件->入库 * @param file diff --git a/iot-access/access-boot/src/main/java/com/njcn/access/service/ICsDeviceService.java b/iot-access/access-boot/src/main/java/com/njcn/access/service/ICsDeviceService.java index af79019..94088f6 100644 --- a/iot-access/access-boot/src/main/java/com/njcn/access/service/ICsDeviceService.java +++ b/iot-access/access-boot/src/main/java/com/njcn/access/service/ICsDeviceService.java @@ -26,7 +26,7 @@ public interface ICsDeviceService { Object getModel(String nDid); /** - * MQTT连接成功,获取装置所用的模板信息 + * 直连设备接入 * @param devAccessParam */ void devAccess(DevAccessParam devAccessParam); diff --git a/iot-access/access-boot/src/main/java/com/njcn/access/service/impl/AskDeviceDataServiceImpl.java b/iot-access/access-boot/src/main/java/com/njcn/access/service/impl/AskDeviceDataServiceImpl.java new file mode 100644 index 0000000..0941094 --- /dev/null +++ b/iot-access/access-boot/src/main/java/com/njcn/access/service/impl/AskDeviceDataServiceImpl.java @@ -0,0 +1,204 @@ +package com.njcn.access.service.impl; + +import com.alibaba.nacos.shaded.com.google.gson.Gson; +import com.github.tocrhz.mqtt.publisher.MqttPublisher; +import com.njcn.access.api.CsTopicFeignClient; +import com.njcn.access.enums.AccessEnum; +import com.njcn.access.enums.TypeEnum; +import com.njcn.access.pojo.dto.ControlDto; +import com.njcn.access.pojo.dto.ReqAndResDto; +import com.njcn.access.pojo.dto.file.FileRedisDto; +import com.njcn.access.service.AskDeviceDataService; +import com.njcn.common.pojo.exception.BusinessException; +import com.njcn.csdevice.enums.AlgorithmResponseEnum; +import com.njcn.redis.pojo.enums.AppRedisKey; +import com.njcn.redis.utils.RedisUtil; +import lombok.RequiredArgsConstructor; +import net.sf.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import java.util.Objects; + +/** + * @author xy + */ +@Service +@RequiredArgsConstructor +public class AskDeviceDataServiceImpl implements AskDeviceDataService { + + private static final Logger log = LoggerFactory.getLogger(AskDeviceDataServiceImpl.class); + private final MqttPublisher publisher; + private final CsTopicFeignClient csTopicFeignClient; + private final RedisUtil redisUtil; + private static Integer mid = 1; + private static Integer range = 51200; + + @Override + public void askDeviceRootPath(String nDid) { + Object object = getDeviceMid(nDid); + if (!Objects.isNull(object)) { + mid = (Integer) object; + } + ReqAndResDto.Req reqAndResParam = new ReqAndResDto.Req(); + reqAndResParam.setMid(mid); + reqAndResParam.setDid(1); + reqAndResParam.setPri(AccessEnum.FIRST_CHANNEL.getCode()); + reqAndResParam.setExpire(-1); + reqAndResParam.setType(Integer.parseInt(TypeEnum.TYPE_13.getCode())); + String version = getVersion(nDid); + publisher.send("/Pfm/DevFileCmd/" + version + "/" + nDid, new Gson().toJson(reqAndResParam), 1, false); + mid = mid + 1; + if (mid > 10000) { + mid = 1; + } + redisUtil.saveByKey(AppRedisKey.DEVICE_MID + nDid,mid); + } + + @Override + public void askDeviceFileOrDir(String nDid, String name) { + Object object = getDeviceMid(nDid); + if (!Objects.isNull(object)) { + mid = (Integer) object; + } + ReqAndResDto.Req reqAndResParam = new ReqAndResDto.Req(); + reqAndResParam.setMid(mid); + reqAndResParam.setDid(1); + reqAndResParam.setPri(AccessEnum.FIRST_CHANNEL.getCode()); + reqAndResParam.setExpire(-1); + reqAndResParam.setType(Integer.parseInt(TypeEnum.TYPE_8.getCode())); + String json = String.format("{\"Name\":\"%s\"}", name); + JSONObject jsonObject = JSONObject.fromObject(json); + reqAndResParam.setMsg(jsonObject); + String version = getVersion(nDid); + publisher.send("/Pfm/DevFileCmd/" + version + "/" + nDid, new Gson().toJson(reqAndResParam), 1, false); + mid = mid + 1; + if (mid > 10000) { + mid = 1; + } + redisUtil.saveByKey(AppRedisKey.DEVICE_MID + nDid,mid); + } + + + @Override + public boolean downloadFile(String nDid, String name, Integer size, String fileCheck) { + boolean result = true; + redisUtil.saveByKeyWithExpire("fileDowning","fileDowning",300L); + redisUtil.saveByKeyWithExpire("fileCheck"+name,fileCheck,300L); + int length = size/51200 + 1; + try { + for (int i = 0; i < length; i++) { + Object object = getDeviceMid(nDid); + if (!Objects.isNull(object)) { + mid = (Integer) object; + } + ReqAndResDto.Req reqAndResParam = getPojo(mid,name,i); + publisher.send("/Pfm/DevFileCmd/V1/"+nDid,new Gson().toJson(reqAndResParam),1,false); + //判断是否重发 + sendNextStep(name,nDid,mid,i); + FileRedisDto fileRedisDto = (FileRedisDto) redisUtil.getObjectByKey(AppRedisKey.DOWNLOAD + name + mid); + //重发之后判断继续循环还是跳出循环 + if (!Objects.isNull(fileRedisDto) && !Objects.equals(fileRedisDto.getCode(),200)) { + result = false; + break; + } + mid = mid + 1; + if (mid > 10000) { + mid = 1; + } + redisUtil.saveByKey(AppRedisKey.DEVICE_MID + nDid,mid); + } + } catch (Exception e) { + redisUtil.delete("fileDowning"); + redisUtil.delete("fileCheck"+name); + throw new BusinessException(AlgorithmResponseEnum.FILE_DOWNLOAD_ERROR); + } + return result; + } + + @Override + public void rebootDevice(String nDid) { + Object object = getDeviceMid(nDid); + if (!Objects.isNull(object)) { + mid = (Integer) object; + } + ReqAndResDto.Req reqAndResParam = new ReqAndResDto.Req(); + reqAndResParam.setMid(mid); + reqAndResParam.setDid(0); + reqAndResParam.setPri(AccessEnum.FIRST_CHANNEL.getCode()); + reqAndResParam.setExpire(-1); + reqAndResParam.setType(Integer.parseInt(TypeEnum.TYPE_31.getCode())); + ControlDto controlDto = new ControlDto(); + controlDto.setClDid(-1); + controlDto.setCmdType("reboot"); + controlDto.setCmdParm("on"); + reqAndResParam.setMsg(controlDto); + publisher.send("/Pfm/DevCmd/V1/" + nDid, new Gson().toJson(reqAndResParam), 1, false); + mid = mid + 1; + if (mid > 10000) { + mid = 1; + } + redisUtil.saveByKey(AppRedisKey.DEVICE_MID + nDid,mid); + } + + public Object getDeviceMid(String nDid) { + return redisUtil.getObjectByKey(AppRedisKey.DEVICE_MID + nDid); + } + + public String getVersion(String nDid) { + return csTopicFeignClient.find(nDid).getData(); + } + + /** + * 文件下载请求报文 + */ + public ReqAndResDto.Req getPojo(Integer mid, String fileName, Integer step) { + String json; + ReqAndResDto.Req reqAndResParam = new ReqAndResDto.Req(); + reqAndResParam.setMid(mid); + reqAndResParam.setDid(0); + reqAndResParam.setPri(AccessEnum.FIRST_CHANNEL.getCode()); + reqAndResParam.setType(Integer.parseInt(TypeEnum.TYPE_9.getCode())); + reqAndResParam.setExpire(-1); + json = "{Name:\""+fileName+"\",TransferMode:"+1+",Offset:"+(step*range)+",Len:"+range+"}"; + JSONObject jsonObject = JSONObject.fromObject(json); + reqAndResParam.setMsg(jsonObject); + return reqAndResParam; + } + + /** + * 根据装置响应来判断是否询问下一帧数据 + */ + public void sendNextStep(String fileName, String id, int mid,int step) { + try { + for (int i = 1; i < 4; i++) { + if (step == 0 ){ + Thread.sleep(5000); + } else { + Thread.sleep(2000); + } + FileRedisDto fileRedisDto = (FileRedisDto) redisUtil.getObjectByKey(AppRedisKey.DOWNLOAD + fileName + mid); + if (Objects.isNull(fileRedisDto)) { + FileRedisDto failDto = new FileRedisDto(); + failDto.setCode(400); + redisUtil.saveByKeyWithExpire(AppRedisKey.DOWNLOAD + fileName + mid,failDto,10L); + } else { + if (Objects.equals(fileRedisDto.getCode(),200)) { + break; + } else { + log.info("第" +i+"次尝试"); + //尝试失败则设置code为400,如果装置响应了,则会将code置为200 + FileRedisDto failDto = new FileRedisDto(); + failDto.setCode(400); + redisUtil.saveByKeyWithExpire(AppRedisKey.DOWNLOAD + fileName + mid,failDto,10L); + ReqAndResDto.Req req = getPojo(mid,fileName,step); + publisher.send("/Pfm/DevFileCmd/V1" + id, new Gson().toJson(req), 1, false); + } + } + } + } catch (Exception e) { + throw new BusinessException(AlgorithmResponseEnum.ASK_DEVICE_DIR_ERROR); + } + } +} diff --git a/iot-access/access-boot/src/main/java/com/njcn/access/service/impl/CsDevModelServiceImpl.java b/iot-access/access-boot/src/main/java/com/njcn/access/service/impl/CsDevModelServiceImpl.java index 010371b..cd5bcf8 100644 --- a/iot-access/access-boot/src/main/java/com/njcn/access/service/impl/CsDevModelServiceImpl.java +++ b/iot-access/access-boot/src/main/java/com/njcn/access/service/impl/CsDevModelServiceImpl.java @@ -2,6 +2,7 @@ package com.njcn.access.service.impl; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjectUtil; import com.alibaba.nacos.shaded.com.google.gson.Gson; import com.github.tocrhz.mqtt.publisher.MqttPublisher; import com.njcn.access.enums.AccessEnum; @@ -20,13 +21,16 @@ import com.njcn.access.service.*; import com.njcn.access.utils.CRC32Utils; import com.njcn.access.utils.JsonUtil; import com.njcn.common.pojo.dto.DeviceLogDTO; +import com.njcn.common.pojo.enums.response.CommonResponseEnum; import com.njcn.common.pojo.exception.BusinessException; import com.njcn.csdevice.api.CsLogsFeignClient; import com.njcn.csdevice.api.DevModelFeignClient; +import com.njcn.csdevice.enums.AlgorithmResponseEnum; import com.njcn.csdevice.pojo.po.*; import com.njcn.csdevice.pojo.vo.CsEquipmentDeliveryVO; import com.njcn.oss.constant.OssPath; import com.njcn.oss.utils.FileStorageUtil; +import com.njcn.redis.pojo.enums.AppRedisKey; import com.njcn.redis.utils.RedisUtil; import com.njcn.system.api.*; import com.njcn.system.enums.DicDataEnum; @@ -38,12 +42,10 @@ import com.njcn.system.pojo.vo.DictTreeVO; import com.njcn.web.utils.RequestUtil; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.bouncycastle.util.encoders.Hex; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; -import java.io.IOException; import java.sql.Date; import java.util.*; import java.util.concurrent.atomic.AtomicReference; @@ -99,6 +101,14 @@ public class CsDevModelServiceImpl implements ICsDevModelService { private final MqttMessageHandler mqttMessageHandler; + @Override + public void refreshDevModelCache() { + + + + + } + @Override @Transactional(rollbackFor = {Exception.class}) public void addModel(MultipartFile file) { @@ -154,30 +164,22 @@ public class CsDevModelServiceImpl implements ICsDevModelService { } } - - public static void main(String[] args) { - - } @Override public void uploadDevFile(MultipartFile file,String id,String path) { - DeviceLogDTO logDto = null; + Object object = redisUtil.getObjectByKey("uploading"); + if (Objects.nonNull(object)) { + throw new BusinessException(AlgorithmResponseEnum.FILE_UPLOADING); + } + Object object2 = redisUtil.getObjectByKey("fileDowning"); + if (Objects.nonNull(object2)) { + throw new BusinessException(AlgorithmResponseEnum.FILE_BUSY); + } try { byte[] bytes = file.getBytes(); int length = bytes.length; //生成文件校验码 int crc = CRC32Utils.calculateCRC32(bytes,length,0xffffffff); String hexString = String.format("%08X", crc); - //判断nDid是否存在 - CsEquipmentDeliveryVO csEquipmentDeliveryVO = csEquipmentDeliveryService.queryEquipmentBynDid(id); - logDto = new DeviceLogDTO(); - logDto.setUserName(RequestUtil.getUserNickname()); - logDto.setLoginName(RequestUtil.getUsername()); - if (Objects.isNull(csEquipmentDeliveryVO.getNdid())) { - logDto.setResult(0); - logDto.setFailReason(AccessResponseEnum.NDID_NO_FIND.getMessage()); - csLogsFeignClient.addUserLog(logDto); - throw new BusinessException(AccessResponseEnum.NDID_NO_FIND); - } //存储文件至文件服务器 fileStorageUtil.uploadMultipart(file, OssPath.SYSTEM_TO_DEV + file.getOriginalFilename() + "_"); //获取版本 @@ -188,6 +190,7 @@ public class CsDevModelServiceImpl implements ICsDevModelService { //需要循环的次数 int times = bytes.length / cap + 1; for (int i = 1; i <= times; i++) { + DeviceLogDTO logDto = new DeviceLogDTO(); byte[] lsBytes; if (length > 50*1024) { lsBytes = Arrays.copyOfRange(bytes, (i - 1) * cap, i * cap); @@ -197,10 +200,11 @@ public class CsDevModelServiceImpl implements ICsDevModelService { logDto.setResult(1); length = length - cap; //判断是否重发 - sendNextStep(logDto,path,file,bytes.length,lsBytes,(i-1)*cap,version,id,i,hexString); - FileRedisDto fileRedisDto = (FileRedisDto) redisUtil.getObjectByKey("uploadFileStep"); + sendNextStep(logDto,path,file,bytes.length,lsBytes,(i-1)*cap,version,id,i,hexString,false); + FileRedisDto fileRedisDto = (FileRedisDto) redisUtil.getObjectByKey(AppRedisKey.UPLOAD); //重发之后判断继续循环还是跳出循环 - if (!Objects.equals(fileRedisDto.getCode(),200)) { + if (!Objects.isNull(fileRedisDto) && !Objects.equals(fileRedisDto.getCode(),200)) { + redisUtil.delete("uploading"); break; } } else { @@ -210,21 +214,22 @@ public class CsDevModelServiceImpl implements ICsDevModelService { logDto.setOperate(id + "设备上送文件,这是最后一帧,为第" + i + "帧"); logDto.setResult(1); //判断是否重发 - sendNextStep(logDto,path,file,bytes.length,lsBytes,(i-1)*cap,version,id,i,hexString); + sendNextStep(logDto,path,file,bytes.length,lsBytes,(i-1)*cap,version,id,i,hexString,true); } csLogsFeignClient.addUserLog(logDto); } } else { ReqAndResDto.Req req = getPojo(1,path,file,length,bytes,0,hexString); publisher.send("/Pfm/DevFileCmd/" + version + "/" + id, new Gson().toJson(req), 1, false); + DeviceLogDTO logDto = new DeviceLogDTO(); logDto.setOperate(id + "系统上送文件,当前文件只有1帧"); logDto.setResult(1); csLogsFeignClient.addUserLog(logDto); //判断是否重发 - sendNextStep(logDto,path,file,length,bytes,0,version,id,1,hexString); + sendNextStep(logDto,path,file,length,bytes,0,version,id,1,hexString,false); } } catch (Exception e) { - assert logDto != null; + DeviceLogDTO logDto = new DeviceLogDTO(); logDto.setResult(0); logDto.setFailReason(AccessResponseEnum.UPLOAD_ERROR.getMessage()); csLogsFeignClient.addUserLog(logDto); @@ -250,6 +255,10 @@ public class CsDevModelServiceImpl implements ICsDevModelService { uploadFileDto.setLen(bytes.length); uploadFileDto.setData(Base64.getEncoder().encodeToString(bytes)); uploadFileDto.setFileCheck(fileCheck); + //生成当前帧文件校验码 + int crc = CRC32Utils.calculateCRC32(bytes,bytes.length,0xffffffff); + String hexString = String.format("%08X", crc); + uploadFileDto.setStepFileCheck(hexString); reqAndResParam.setMsg(uploadFileDto); return reqAndResParam; } @@ -257,24 +266,33 @@ 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) { + 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) { try { for (int i = 0; i < 3; i++) { - Thread.sleep(300); - FileRedisDto fileRedisDto = (FileRedisDto) redisUtil.getObjectByKey("uploadFileStep"); - FileRedisDto fileRedis = new FileRedisDto(); - if (Objects.nonNull(fileRedisDto.getCode()) && fileRedisDto.getCode().equals(200)) { - fileRedis.setCode(200); - break; + if (result) { + Thread.sleep(5000); } else { - ReqAndResDto.Req req = getPojo(mid,path,file,length,bytes,offset,fileCheck); - publisher.send("/Pfm/DevFileCmd/" + version + "/" + id, new Gson().toJson(req), 1, false); - logDto.setOperate(id + "系统上送文件,装置响应失败,重新发送,这是第" + (i+1) + "次"); - logDto.setResult(1); - csLogsFeignClient.addUserLog(logDto); - fileRedis.setCode(fileRedisDto.getCode()); + Thread.sleep(2000); + } + FileRedisDto fileRedisDto = (FileRedisDto) redisUtil.getObjectByKey(AppRedisKey.UPLOAD); + if (Objects.isNull(fileRedisDto)) { + FileRedisDto fileRedis = new FileRedisDto(); + fileRedis.setCode(400); + redisUtil.saveByKeyWithExpire(AppRedisKey.UPLOAD,fileRedis,10L); + } else { + if (Objects.equals(fileRedisDto.getCode(),200)) { + break; + } else { + FileRedisDto fileRedis = new FileRedisDto(); + fileRedis.setCode(400); + redisUtil.saveByKeyWithExpire(AppRedisKey.UPLOAD,fileRedis,10L); + ReqAndResDto.Req req = getPojo(mid,path,file,length,bytes,offset,fileCheck); + publisher.send("/Pfm/DevFileCmd/" + version + "/" + id, new Gson().toJson(req), 1, false); + logDto.setOperate(id + "系统上送文件,装置响应失败,重新发送,这是第" + (i+1) + "次"); + logDto.setResult(1); + csLogsFeignClient.addUserLog(logDto); + } } - redisUtil.saveByKeyWithExpire("uploadFileStep",fileRedis,10L); } } catch (InterruptedException e) { assert logDto != null; diff --git a/iot-access/access-boot/src/main/java/com/njcn/access/service/impl/CsDeviceServiceImpl.java b/iot-access/access-boot/src/main/java/com/njcn/access/service/impl/CsDeviceServiceImpl.java index f874b76..3615f3d 100644 --- a/iot-access/access-boot/src/main/java/com/njcn/access/service/impl/CsDeviceServiceImpl.java +++ b/iot-access/access-boot/src/main/java/com/njcn/access/service/impl/CsDeviceServiceImpl.java @@ -102,7 +102,7 @@ public class CsDeviceServiceImpl implements ICsDeviceService { DeviceLogDTO logDto = new DeviceLogDTO(); logDto.setUserName(RequestUtil.getUserNickname()); logDto.setLoginName(RequestUtil.getUsername()); - logDto.setOperate("当前设备"+nDid+"状态判断"); + logDto.setOperate("直连设备"+nDid+"注册"); logDto.setResult(1); //1.判断nDid是否存在 CsEquipmentDeliveryVO csEquipmentDeliveryVO = csEquipmentDeliveryService.queryEquipmentBynDid(nDid); @@ -112,13 +112,6 @@ public class CsDeviceServiceImpl implements ICsDeviceService { csLogsFeignClient.addUserLog(logDto); throw new BusinessException(AccessResponseEnum.NDID_NO_FIND); } - //判断是否已经注册过 - if (!Objects.isNull(csEquipmentDeliveryVO.getNdid()) && Objects.equals(type,csEquipmentDeliveryVO.getProcess()) && Objects.equals(AccessEnum.ACCESS.getCode(),csEquipmentDeliveryVO.getStatus())){ - logDto.setResult(0); - logDto.setFailReason(AccessResponseEnum.NDID_SAME_STEP.getMessage()); - csLogsFeignClient.addUserLog(logDto); - throw new BusinessException(AccessResponseEnum.NDID_SAME_STEP); - } //2.判断设备是否是直连设备 SysDicTreePO sysDicTreePo = dictTreeFeignClient.queryById(csEquipmentDeliveryVO.getDevType()).getData(); if (Objects.isNull(sysDicTreePo)){ @@ -134,7 +127,14 @@ public class CsDeviceServiceImpl implements ICsDeviceService { csLogsFeignClient.addUserLog(logDto); throw new BusinessException(AccessResponseEnum.DEV_IS_NOT_ZL); } - //3.判断客户端是否在线 + //3.判断是否已经注册过 + if (!Objects.isNull(csEquipmentDeliveryVO.getNdid()) && Objects.equals(type,csEquipmentDeliveryVO.getProcess()) && Objects.equals(AccessEnum.ACCESS.getCode(),csEquipmentDeliveryVO.getStatus())){ + logDto.setResult(0); + logDto.setFailReason(AccessResponseEnum.NDID_SAME_STEP.getMessage()); + csLogsFeignClient.addUserLog(logDto); + throw new BusinessException(AccessResponseEnum.NDID_SAME_STEP); + } + //4.判断客户端是否在线 String clientName = "NJCN-" + nDid.substring(nDid.length() - 6); boolean mqttClient = mqttUtil.judgeClientOnline(clientName); if (!mqttClient){ @@ -143,7 +143,7 @@ public class CsDeviceServiceImpl implements ICsDeviceService { csLogsFeignClient.addUserLog(logDto); throw new BusinessException(AccessResponseEnum.MISSING_CLIENT); } - //4.判断当前流程是否是合法的 + //5.判断当前流程是否是合法的 if (csEquipmentDeliveryVO.getProcess() > type){ logDto.setResult(0); logDto.setFailReason(AccessResponseEnum.PROCESS_SAME_ERROR.getMessage()); @@ -153,10 +153,10 @@ public class CsDeviceServiceImpl implements ICsDeviceService { logDto.setFailReason(AccessResponseEnum.PROCESS_MISSING_ERROR.getMessage()); throw new BusinessException(AccessResponseEnum.PROCESS_MISSING_ERROR); } - //5.询问设备支持的主题信息 + //6.询问设备支持的主题信息 //将支持的主题入库 askTopic(nDid); - //6.MQTT询问装置用的模板,并判断库中是否存在模板 + //7.MQTT询问装置用的模板,并判断库中是否存在模板 //存在则建立关系;不存在则告警出来 SysDicTreePO dictData = dictTreeFeignClient.queryById(csEquipmentDeliveryVO.getDevModel()).getData(); if (Objects.isNull(dictData)){ @@ -203,7 +203,7 @@ public class CsDeviceServiceImpl implements ICsDeviceService { DeviceLogDTO logDto = new DeviceLogDTO(); logDto.setUserName(RequestUtil.getUserNickname()); logDto.setLoginName(RequestUtil.getUsername()); - logDto.setOperate("设备"+devAccessParam.getNDid()+"注册"); + logDto.setOperate("设备"+devAccessParam.getNDid()+"接入"); logDto.setResult(1); try { //获取版本 @@ -288,7 +288,6 @@ public class CsDeviceServiceImpl implements ICsDeviceService { csEquipmentDeliveryService.updateStatusBynDid(devAccessParam.getNDid(), AccessEnum.REGISTERED.getCode()); //7.发起自动接入请求 devAccessAskTemplate(devAccessParam.getNDid(),version,1); - //8.删除redis监测点模板信息 redisUtil.delete(AppRedisKey.MODEL + devAccessParam.getNDid()); redisUtil.delete(AppRedisKey.LINE + devAccessParam.getNDid()); @@ -599,16 +598,4 @@ public class CsDeviceServiceImpl implements ICsDeviceService { } return urlList; } - - public List objectToList2(Object object) { - List urlList = new ArrayList<>(); - if (object != null) { - if (object instanceof ArrayList) { - for (Object o : (List) object) { - urlList.add((RspDataDto.LdevInfo) o); - } - } - } - return urlList; - } } diff --git a/iot-analysis/analysis-stat/stat-api/src/main/java/com/njcn/stat/api/WlRecordFeignClient.java b/iot-analysis/analysis-stat/stat-api/src/main/java/com/njcn/stat/api/WlRecordFeignClient.java new file mode 100644 index 0000000..5fff977 --- /dev/null +++ b/iot-analysis/analysis-stat/stat-api/src/main/java/com/njcn/stat/api/WlRecordFeignClient.java @@ -0,0 +1,21 @@ +package com.njcn.stat.api; + +import com.njcn.common.pojo.constant.ServerInfo; +import com.njcn.common.pojo.response.HttpResult; +import com.njcn.mq.message.AppAutoDataMessage; +import com.njcn.stat.api.fallback.WlRecordClientFallbackFactory; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +/** + * @author xy + */ +@FeignClient(value = ServerInfo.CS_STAT_BOOT, path = "/record", fallbackFactory = WlRecordClientFallbackFactory.class,contextId = "record") +public interface WlRecordFeignClient { + + @PostMapping("/addOrUpdateBaseData") + HttpResult addOrUpdateBaseData(@RequestBody @Validated AppAutoDataMessage appAutoDataMessage); + +} diff --git a/iot-analysis/analysis-stat/stat-api/src/main/java/com/njcn/stat/api/fallback/WlRecordClientFallbackFactory.java b/iot-analysis/analysis-stat/stat-api/src/main/java/com/njcn/stat/api/fallback/WlRecordClientFallbackFactory.java new file mode 100644 index 0000000..c910b8f --- /dev/null +++ b/iot-analysis/analysis-stat/stat-api/src/main/java/com/njcn/stat/api/fallback/WlRecordClientFallbackFactory.java @@ -0,0 +1,35 @@ +package com.njcn.stat.api.fallback; + +import com.njcn.common.pojo.enums.response.CommonResponseEnum; +import com.njcn.common.pojo.exception.BusinessException; +import com.njcn.common.pojo.response.HttpResult; +import com.njcn.mq.message.AppAutoDataMessage; +import com.njcn.stat.api.WlRecordFeignClient; +import feign.hystrix.FallbackFactory; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * @author xy + */ +@Slf4j +@Component +public class WlRecordClientFallbackFactory implements FallbackFactory { + @Override + public WlRecordFeignClient create(Throwable cause) { + //判断抛出异常是否为解码器抛出的业务异常 + Enum exceptionEnum = CommonResponseEnum.SERVICE_FALLBACK; + if (cause.getCause() instanceof BusinessException) { + BusinessException businessException = (BusinessException) cause.getCause(); + } + Enum finalExceptionEnum = exceptionEnum; + return new WlRecordFeignClient() { + + @Override + public HttpResult addOrUpdateBaseData(AppAutoDataMessage appAutoDataMessage) { + log.error("{}异常,降级处理,异常为:{}","新增或更新装置基础数据",cause.toString()); + throw new BusinessException(finalExceptionEnum); + } + }; + } +} diff --git a/iot-analysis/analysis-stat/stat-boot/src/main/java/com/njcn/stat/controller/WlRecordController.java b/iot-analysis/analysis-stat/stat-boot/src/main/java/com/njcn/stat/controller/WlRecordController.java new file mode 100644 index 0000000..662f8ce --- /dev/null +++ b/iot-analysis/analysis-stat/stat-boot/src/main/java/com/njcn/stat/controller/WlRecordController.java @@ -0,0 +1,48 @@ +package com.njcn.stat.controller; + +import com.njcn.common.pojo.annotation.OperateInfo; +import com.njcn.common.pojo.enums.common.LogEnum; +import com.njcn.common.pojo.enums.response.CommonResponseEnum; +import com.njcn.common.pojo.response.HttpResult; +import com.njcn.common.utils.HttpResultUtil; +import com.njcn.mq.message.AppAutoDataMessage; +import com.njcn.stat.service.IWlRecordService; +import com.njcn.web.controller.BaseController; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 类的介绍: + * + * @author xuyang + * @version 1.0.0 + * @createTime 2024/9/10 9:23 + */ +@Slf4j +@RestController +@RequestMapping("/record") +@Api(tags = "便携式基础数据录入") +@AllArgsConstructor +public class WlRecordController extends BaseController { + + private final IWlRecordService wlRecordService; + + @OperateInfo(info = LogEnum.BUSINESS_COMMON) + @PostMapping("/addOrUpdateBaseData") + @ApiOperation("新增或更新装置基础数据") + @ApiImplicitParam(name = "appAutoDataMessage", value = "数据实体", required = true) + public HttpResult addOrUpdateBaseData(@RequestBody @Validated AppAutoDataMessage appAutoDataMessage){ + String methodDescribe = getMethodDescribe("addOrUpdateBaseData"); + wlRecordService.addOrUpdateBaseData(appAutoDataMessage); + return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, null, methodDescribe); + } + +} diff --git a/iot-analysis/analysis-stat/stat-boot/src/main/java/com/njcn/stat/listener/RedisKeyExpirationListener.java b/iot-analysis/analysis-stat/stat-boot/src/main/java/com/njcn/stat/listener/RedisKeyExpirationListener.java index ce447c1..6ae17be 100644 --- a/iot-analysis/analysis-stat/stat-boot/src/main/java/com/njcn/stat/listener/RedisKeyExpirationListener.java +++ b/iot-analysis/analysis-stat/stat-boot/src/main/java/com/njcn/stat/listener/RedisKeyExpirationListener.java @@ -1,67 +1,67 @@ -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 map = new HashMap<>(); - List 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); - } - } -} +//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 map = new HashMap<>(); +// List 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); +// } +// } +//} diff --git a/iot-analysis/analysis-stat/stat-boot/src/main/java/com/njcn/stat/service/IWlRecordService.java b/iot-analysis/analysis-stat/stat-boot/src/main/java/com/njcn/stat/service/IWlRecordService.java new file mode 100644 index 0000000..7963840 --- /dev/null +++ b/iot-analysis/analysis-stat/stat-boot/src/main/java/com/njcn/stat/service/IWlRecordService.java @@ -0,0 +1,12 @@ +package com.njcn.stat.service; + +import com.njcn.mq.message.AppAutoDataMessage; + +/** + * @author xy + */ +public interface IWlRecordService { + + void addOrUpdateBaseData(AppAutoDataMessage appAutoDataMessage); + +} diff --git a/iot-analysis/analysis-stat/stat-boot/src/main/java/com/njcn/stat/service/impl/StatServiceImpl.java b/iot-analysis/analysis-stat/stat-boot/src/main/java/com/njcn/stat/service/impl/StatServiceImpl.java index 22ce765..fafab29 100644 --- a/iot-analysis/analysis-stat/stat-boot/src/main/java/com/njcn/stat/service/impl/StatServiceImpl.java +++ b/iot-analysis/analysis-stat/stat-boot/src/main/java/com/njcn/stat/service/impl/StatServiceImpl.java @@ -99,36 +99,36 @@ public class StatServiceImpl implements IStatService { lineId = new Gson().fromJson(String.valueOf(redisUtil.getObjectByKey(AppRedisKey.LINE_POSITION+appAutoDataMessage.getId())), Map.class).get(appAutoDataMessage.getMsg().getClDid().toString()).toString(); } } - //缓存指标和influxDB表关系 - Object object2 = redisUtil.getObjectByKey(AppRedisKey.ELE_EPD_PQD); - if(Objects.isNull(object2)) { - saveData(); - } +// //缓存指标和influxDB表关系 +// Object object2 = redisUtil.getObjectByKey(AppRedisKey.ELE_EPD_PQD); +// if(Objects.isNull(object2)) { +// saveData(); +// } //获取当前设备信息 if (CollectionUtil.isNotEmpty(list)){ List recordList = new ArrayList<>(); for (AppAutoDataMessage.DataArray item : list) { switch (item.getDataAttr()) { case 1: - log.info("{}-->处理最大值", po.getNdid()); + log.info("{}-->处理最大值", po.getNdid() + appAutoDataMessage.getDid() + appAutoDataMessage.getMsg().getClDid()); dataArrayParam.setStatMethod("max"); break; case 2: - log.info("{}-->处理最小值", po.getNdid()); + log.info("{}-->处理最小值", po.getNdid() + appAutoDataMessage.getDid() + appAutoDataMessage.getMsg().getClDid()); dataArrayParam.setStatMethod("min"); break; case 3: - log.info("{}-->处理avg", po.getNdid()); + log.info("{}-->处理avg", po.getNdid() + appAutoDataMessage.getDid() + appAutoDataMessage.getMsg().getClDid()); dataArrayParam.setStatMethod("avg"); break; case 4: - log.info("{}-->处理cp95", po.getNdid()); + log.info("{}-->处理cp95", po.getNdid() + appAutoDataMessage.getDid() + appAutoDataMessage.getMsg().getClDid()); dataArrayParam.setStatMethod("cp95"); break; default: break; } - Object object = redisUtil.getObjectByKey(appAutoDataMessage.getId() + appAutoDataMessage.getDid() + appAutoDataMessage.getMsg().getClDid()); + Object object = redisUtil.getObjectByKey(appAutoDataMessage.getId() + appAutoDataMessage.getDid() + appAutoDataMessage.getMsg().getClDid() + dataArrayParam.getStatMethod()); List dataArrayList; if (Objects.isNull(object)){ dataArrayList = saveModelData(dataArrayParam); @@ -168,29 +168,29 @@ public class StatServiceImpl implements IStatService { } } } - redisUtil.saveByKeyWithExpire(AppRedisKey.LINE_POSITION+id,map,600L); + redisUtil.saveByKey(AppRedisKey.LINE_POSITION+id,map); } - /** - * 缓存字典和influxDB表关系 - */ - public void saveData() { - Map map = new HashMap<>(); - List 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); - } +// /** +// * 缓存字典和influxDB表关系 +// */ +// public void saveData() { +// Map map = new HashMap<>(); +// List 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); +// } /** * 缓存设备模板信息 */ public List saveModelData(DataArrayParam dataArrayParam) { - String key = dataArrayParam.getId() + dataArrayParam.getDid() + dataArrayParam.getCldId(); + String key = dataArrayParam.getId() + dataArrayParam.getDid() + dataArrayParam.getCldId() + dataArrayParam.getStatMethod(); List dataArrayList = dataArrayFeignClient.findListByParam(dataArrayParam).getData(); if (CollectionUtil.isEmpty(dataArrayList)){ throw new BusinessException(StatResponseEnum.DATA_ARRAY_NULL); @@ -214,10 +214,10 @@ public class StatServiceImpl implements IStatService { if (!Objects.equals(dataArrayList.size(),floats.size())){ throw new BusinessException(StatResponseEnum.ARRAY_DATA_NOT_MATCH); } - //判断字典数据是否存在 - if (Objects.isNull(redisUtil.getObjectByKey(AppRedisKey.ELE_EPD_PQD))){ - saveData(); - } +// //判断字典数据是否存在 +// if (Objects.isNull(redisUtil.getObjectByKey(AppRedisKey.ELE_EPD_PQD))){ +// saveData(); +// } Map map = new Gson().fromJson(String.valueOf(redisUtil.getObjectByKey(AppRedisKey.ELE_EPD_PQD)), Map.class); for (int i = 0; i < dataArrayList.size(); i++) { String tableName = map.get(dataArrayList.get(i).getName()); diff --git a/iot-analysis/analysis-stat/stat-boot/src/main/java/com/njcn/stat/service/impl/WlRecordServiceImpl.java b/iot-analysis/analysis-stat/stat-boot/src/main/java/com/njcn/stat/service/impl/WlRecordServiceImpl.java new file mode 100644 index 0000000..7c5492c --- /dev/null +++ b/iot-analysis/analysis-stat/stat-boot/src/main/java/com/njcn/stat/service/impl/WlRecordServiceImpl.java @@ -0,0 +1,44 @@ +package com.njcn.stat.service.impl; + +import com.njcn.csdevice.api.EquipmentFeignClient; +import com.njcn.csdevice.api.WlRecordFeignClient; +import com.njcn.csdevice.pojo.po.CsEquipmentDeliveryPO; +import com.njcn.csdevice.pojo.po.WlRecord; +import com.njcn.mq.message.AppAutoDataMessage; +import com.njcn.stat.service.IWlRecordService; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; + +/** + * 类的介绍: + * + * @author xuyang + * @version 1.0.0 + * @createTime 2023/8/14 9:32 + */ +@Service +@Slf4j +@AllArgsConstructor +public class WlRecordServiceImpl implements IWlRecordService{ + + private final EquipmentFeignClient equipmentFeignClient; + + private final WlRecordFeignClient wlRecordFeignClient; + + @Override + public void addOrUpdateBaseData(AppAutoDataMessage appAutoDataMessage) { + WlRecord wlRecord = new WlRecord(); + CsEquipmentDeliveryPO po = equipmentFeignClient.findDevByNDid(appAutoDataMessage.getId()).getData(); + AppAutoDataMessage.DataArray dataArray = appAutoDataMessage.getMsg().getDataArray().get(0); + BeanUtils.copyProperties(dataArray, wlRecord); + wlRecord.setDevId(po.getId()); + wlRecord.setLineId(po.getNdid() + appAutoDataMessage.getMsg().getClDid()); + wlRecord.setGcDataPath(dataArray.getPrjDataPath()); + if (dataArray.getPrjTimeEnd() == -1) { + wlRecord.setEndTime(null); + } + wlRecordFeignClient.addBaseData(wlRecord); + } +} diff --git a/iot-analysis/analysis-zl-event/zl-event-boot/src/main/java/com/njcn/zlevent/listener/RedisKeyExpirationListener.java b/iot-analysis/analysis-zl-event/zl-event-boot/src/main/java/com/njcn/zlevent/listener/RedisKeyExpirationListener.java index 714623e..34c564c 100644 --- a/iot-analysis/analysis-zl-event/zl-event-boot/src/main/java/com/njcn/zlevent/listener/RedisKeyExpirationListener.java +++ b/iot-analysis/analysis-zl-event/zl-event-boot/src/main/java/com/njcn/zlevent/listener/RedisKeyExpirationListener.java @@ -43,21 +43,16 @@ public class RedisKeyExpirationListener extends KeyExpirationEventMessageListene @Resource private EpdFeignClient epdFeignClient; - @Resource private RedisUtil redisUtil; - @Resource private CsTopicFeignClient csTopicFeignClient; - @Resource private MqttPublisher publisher; - public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) { super(listenerContainer); } - /** * 针对redis数据失效事件,进行数据处理 * 注意message.toString()可以获取失效的key diff --git a/iot-analysis/analysis-zl-event/zl-event-boot/src/main/java/com/njcn/zlevent/service/impl/EventServiceImpl.java b/iot-analysis/analysis-zl-event/zl-event-boot/src/main/java/com/njcn/zlevent/service/impl/EventServiceImpl.java index 2c8de7e..5288be3 100644 --- a/iot-analysis/analysis-zl-event/zl-event-boot/src/main/java/com/njcn/zlevent/service/impl/EventServiceImpl.java +++ b/iot-analysis/analysis-zl-event/zl-event-boot/src/main/java/com/njcn/zlevent/service/impl/EventServiceImpl.java @@ -137,6 +137,10 @@ public class EventServiceImpl implements IEventService { if (Objects.equals(param.getName(),ZlConstant.EVT_PARAM_TM)){ csEvent.setPersistTime(Double.parseDouble(param.getData().toString())); } + lineId = appEventMessage.getId() + appEventMessage.getMsg().getClDid(); + fields.put(param.getName(),appEventMessage.getMsg().getClDid()==1?"电网侧":"负载侧"); + csEvent.setLocation(appEventMessage.getMsg().getClDid()==1?ZlConstant.GRID:ZlConstant.LOAD); + csEvent.setClDid(appEventMessage.getMsg().getClDid()); fields.put(param.getName(),param.getData()); } //fixme 这边前置传递的应该是UTC时间,但是前置说是传递的北京时间,讨论了一下没太理解。这边暂时先这样处理,influx入库处理成北京时间,减去8小时。 diff --git a/iot-analysis/analysis-zl-event/zl-event-boot/src/main/java/com/njcn/zlevent/service/impl/FileServiceImpl.java b/iot-analysis/analysis-zl-event/zl-event-boot/src/main/java/com/njcn/zlevent/service/impl/FileServiceImpl.java index 9ad5380..9f29cb5 100644 --- a/iot-analysis/analysis-zl-event/zl-event-boot/src/main/java/com/njcn/zlevent/service/impl/FileServiceImpl.java +++ b/iot-analysis/analysis-zl-event/zl-event-boot/src/main/java/com/njcn/zlevent/service/impl/FileServiceImpl.java @@ -4,15 +4,14 @@ import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.text.StrPool; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; -import com.alibaba.nacos.common.utils.ConcurrentHashSet; import com.alibaba.nacos.shaded.com.google.gson.Gson; -import com.alibaba.nacos.shaded.com.google.gson.GsonBuilder; import com.github.tocrhz.mqtt.publisher.MqttPublisher; import com.njcn.access.api.CsTopicFeignClient; import com.njcn.access.enums.AccessEnum; import com.njcn.access.enums.AccessResponseEnum; import com.njcn.access.enums.TypeEnum; import com.njcn.access.pojo.dto.ReqAndResDto; +import com.njcn.access.utils.CRC32Utils; import com.njcn.common.config.GeneralInfo; import com.njcn.common.pojo.exception.BusinessException; import com.njcn.csharmonic.api.WavePicFeignClient; @@ -41,7 +40,6 @@ import java.io.*; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; -import java.util.concurrent.TimeUnit; /** * 类的介绍: @@ -112,7 +110,7 @@ public class FileServiceImpl implements IFileService { csWave.setStatus(0); csWaveService.save(csWave); //请求当前文件的数据 - askFileStream(appFileMessage.getId(),mid,fileName,-1,range); + askFileStream(appFileMessage.getId(),mid,fileName,0,range); redisUtil.saveByKey(AppRedisKey.RMQ_FILE_CONSUME_KEY.concat(fileInfoDto.getName()), fileInfoDto); redisUtil.delete(AppRedisKey.TIME+fileName); } else { @@ -123,7 +121,7 @@ public class FileServiceImpl implements IFileService { @Override public void analysisFileStream(AppFileMessage appFileMessage) { DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSS"); - String filePath; + String filePath = null; List list = new ArrayList<>(); FileStreamDto fileStreamDto = new FileStreamDto(); //波形文件上传成功后,将文件信息存储一下,方便后期查看 @@ -138,18 +136,53 @@ public class FileServiceImpl implements IFileService { try { //todo 目前文件先只处理波形事件的,后续有其他文件再做处理 String fileName = appFileMessage.getMsg().getName(); - //String lsFileName =fileName.split(StrUtil.SLASH)[fileName.split(StrUtil.SLASH).length - 1]; String lsFileName = generalInfo.getBusinessTempPath() + File.separator + fileName.split(StrUtil.SLASH)[fileName.split(StrUtil.SLASH).length - 1]; + File lsFile =new File(generalInfo.getBusinessTempPath()); + //如果文件夹不存在则创建 + if (!lsFile.exists() && !lsFile.isDirectory()){ + lsFile .mkdirs(); + } //获取缓存的文件信息 Object fileInfo = redisUtil.getObjectByKey(AppRedisKey.RMQ_FILE_CONSUME_KEY.concat(fileName)); FileInfoDto fileInfoDto = JSON.parseObject(JSON.toJSONString(fileInfo), FileInfoDto.class); - //1.判断当前文件是否之前缓存过,没缓存,则先缓存(这边缓存两条记录,一条是用来判断超时的,还有一条记录文件数据,文件数据目前没有过期时间,文件数据收完才会删除) - //2.缓存了判断收到的报文个数是否和总个数一致,一致则解析文件;不一致则更新缓存 - //3.超时判断: 30s分钟未收到相关文件信息,核查文件个数,看丢失哪些帧,重新请求 - if(fileName.contains(".cfg") || fileName.contains(".dat")) { + if (Objects.isNull(fileInfoDto)) { + String fileCheck = redisUtil.getObjectByKey("fileCheck"+fileName).toString(); if (appFileMessage.getMsg().getFrameTotal() == 1){ //解析文件入库 - filePath = fileStream(1,null,appFileMessage.getMsg().getData(),fileName,appFileMessage.getId()); + filePath = fileStream(1,null,appFileMessage.getMsg().getData(),fileName,appFileMessage.getId(),fileCheck,"download"); + } else { + //最后一帧 + if (Objects.equals(appFileMessage.getMsg().getFrameTotal(), appFileMessage.getMsg().getFrameCurr())) { + Map filePartMap = readFile(lsFileName); + filePartMap.put(appFileMessage.getMsg().getFrameCurr(), appFileMessage.getMsg().getData()); + //解析文件 + filePath = fileStream(appFileMessage.getMsg().getFrameTotal(), filePartMap, null, fileName, appFileMessage.getId(),fileCheck,"download"); + //删除临时文件 + File file = new File(lsFileName); + if (file.exists()) { + file.delete(); + } + } + //中间帧 + else { + Map filePartMap = readFile(lsFileName); + if (Objects.isNull(filePartMap.get(appFileMessage.getMsg().getFrameCurr()))) { + appendFile(lsFileName,appFileMessage.getMsg().getFrameCurr(),appFileMessage.getMsg().getData()); + } + } + } + if (!Objects.isNull(filePath)){ + redisUtil.saveByKey("downloadFilePath:"+appFileMessage.getMsg().getName(),filePath); + } + } + //录波文件下载 + //1.判断当前文件是否之前缓存过,没缓存,则先缓存(这边缓存两条记录,一条是用来判断超时的,还有一条记录文件数据,文件数据目前没有过期时间,文件数据收完才会删除) + //2.缓存了判断收到的报文个数是否和总个数一致,一致则解析文件;不一致则更新缓存 + //3.超时判断: 30s未收到相关文件信息,核查文件个数,看丢失哪些帧,重新请求 + else { + if (appFileMessage.getMsg().getFrameTotal() == 1){ + //解析文件入库 + filePath = fileStream(1,null,appFileMessage.getMsg().getData(),fileName,appFileMessage.getId(),fileInfoDto.getFileCheck(),"event"); csEventLogs.setStatus(1); csEventLogs.setRemark("当前文件1帧,全部收到,解析成功!"); csEventLogs.setNowStep(1); @@ -178,7 +211,7 @@ public class FileServiceImpl implements IFileService { csEventLogs.setNowStep(appFileMessage.getMsg().getFrameCurr()); csEventLogs.setAllStep(appFileMessage.getMsg().getFrameTotal()); csEventLogs.setIsAll(0); - redisUtil.saveByKeyWithExpire(AppRedisKey.FILE_PART_TIME.concat(appFileMessage.getMsg().getName()), null, 30L); + redisUtil.saveByKeyWithExpire(AppRedisKey.FILE_PART_TIME.concat(appFileMessage.getMsg().getName()), null, 5L); redisUtil.saveByKey(AppRedisKey.FILE_PART.concat(appFileMessage.getMsg().getName()), fileStreamDto); //将数据写入临时文件 appendFile(lsFileName,appFileMessage.getMsg().getFrameCurr(),appFileMessage.getMsg().getData()); @@ -192,7 +225,7 @@ public class FileServiceImpl implements IFileService { Map filePartMap = readFile(lsFileName); filePartMap.put(appFileMessage.getMsg().getFrameCurr(), appFileMessage.getMsg().getData()); //解析文件 - filePath = fileStream(appFileMessage.getMsg().getFrameTotal(), filePartMap, null, fileName, appFileMessage.getId()); + filePath = fileStream(appFileMessage.getMsg().getFrameTotal(), filePartMap, null, fileName, appFileMessage.getId(),fileInfoDto.getFileCheck(),"event"); csEventLogs.setStatus(1); csEventLogs.setRemark("当前文件" + appFileMessage.getMsg().getFrameTotal() + "帧,这是第" + appFileMessage.getMsg().getFrameCurr() + "帧,全部收到,解析成功!"); csEventLogs.setNowStep(appFileMessage.getMsg().getFrameCurr()); @@ -224,17 +257,21 @@ public class FileServiceImpl implements IFileService { csEventLogs.setNowStep(appFileMessage.getMsg().getFrameCurr()); csEventLogs.setAllStep(appFileMessage.getMsg().getFrameTotal()); csEventLogs.setIsAll(0); + redisUtil.saveByKey(AppRedisKey.FILE_PART.concat(appFileMessage.getMsg().getName()), dto); + long time1 = System.currentTimeMillis(); + //将数据写入临时文件 + appendFile(lsFileName, appFileMessage.getMsg().getFrameCurr(), appFileMessage.getMsg().getData()); + long time2 = System.currentTimeMillis(); + System.out.println("time==:" + (time2 - time1)); + log.info("当前文件 {} 帧,这是第 {} 帧报文,记录成功", appFileMessage.getMsg().getFrameTotal(), appFileMessage.getMsg().getFrameCurr()); if (Objects.isNull(object2)) { - redisUtil.saveByKeyWithExpire(AppRedisKey.FILE_PART_TIME.concat(appFileMessage.getMsg().getName()), null, 30L); + redisUtil.saveByKeyWithExpire(AppRedisKey.FILE_PART_TIME.concat(appFileMessage.getMsg().getName()), null, 10L); } else { redisUtil.saveByKeyWithExpire(AppRedisKey.FILE_PART_TIME.concat(appFileMessage.getMsg().getName()), null, 1L); } - redisUtil.saveByKey(AppRedisKey.FILE_PART.concat(appFileMessage.getMsg().getName()), dto); - //将数据写入临时文件 - appendFile(lsFileName, appFileMessage.getMsg().getFrameCurr(), appFileMessage.getMsg().getData()); - log.info("当前文件 {} 帧,这是第 {} 帧报文,记录成功", appFileMessage.getMsg().getFrameTotal(), appFileMessage.getMsg().getFrameCurr()); } } else { + redisUtil.saveByKeyWithExpire(AppRedisKey.FILE_PART_TIME.concat(appFileMessage.getMsg().getName()), null, 1L); csEventLogs.setStatus(1); csEventLogs.setRemark("当前文件为重复帧,这是第" + appFileMessage.getMsg().getFrameCurr() + "帧,不做记录!"); csEventLogs.setNowStep(appFileMessage.getMsg().getFrameCurr()); @@ -249,9 +286,6 @@ public class FileServiceImpl implements IFileService { csEventLogs.setLocation(fileInfoDto.getLocation()); //记录日志 csEventLogsService.save(csEventLogs); - } else { - //todo 处理其他文件 - log.info("暂未做其他文件处理"); } } catch (Exception e){ csEventLogs.setStatus(0); @@ -283,10 +317,10 @@ public class FileServiceImpl implements IFileService { /** * 组装文件 */ - public String fileStream(Integer number, Map map, String data, String fileName, String nDid) { + public String fileStream(Integer number, Map map, String data, String fileName, String nDid, String fileCheck,String type) { String filePath; if (number == 1){ - filePath = stream(true,data,nDid,fileName,null); + filePath = stream(true,data,nDid,fileName,null,fileCheck,type); } else { int lengthByte = 0; for (int i = 1; i <= number; i++) { @@ -300,7 +334,7 @@ public class FileServiceImpl implements IFileService { System.arraycopy(byteArray, 0, allByte, countLength, byteArray.length); countLength += byteArray.length; } - filePath = stream(false,null,nDid,fileName,allByte); + filePath = stream(false,null,nDid,fileName,allByte,fileCheck,type); } return filePath; } @@ -308,7 +342,8 @@ public class FileServiceImpl implements IFileService { /** * 解析存储文件信息 */ - public String stream(boolean bool, String stream, String folder, String fileName, byte[] bytes) { + public String stream(boolean bool, String stream, String folder, String fileName, byte[] bytes, String fileCheck, String type) { + String path; byte[] byteArray = null; //将文件后缀替换成大写 String[] parts = fileName.split(StrUtil.SLASH); @@ -321,9 +356,18 @@ public class FileServiceImpl implements IFileService { } else { byteArray = bytes; } - //todo 此处需要做文件crc校验或者md5校验,目前不知道怎么处理,先放一下 + //文件校验 + int crc = CRC32Utils.calculateCRC32(byteArray,byteArray.length,0xffffffff); + String hexString = String.format("%08X", crc); + if (!Objects.equals(hexString,fileCheck)) { + throw new BusinessException(AccessResponseEnum.FILE_CHECK_ERROR); + } InputStream inputStream = new ByteArrayInputStream(byteArray); - String path = fileStorageUtil.uploadStreamSpecifyName(inputStream, OssPath.WAVE_DIR + folder + StrUtil.SLASH,fileName); + if (Objects.equals(type,"download")) { + path = fileStorageUtil.uploadStreamSpecifyName(inputStream, OssPath.DOWNLOAD_DIR + folder + StrUtil.SLASH,fileName); + } else { + path = fileStorageUtil.uploadStreamSpecifyName(inputStream, OssPath.WAVE_DIR + folder + StrUtil.SLASH,fileName); + } try { inputStream.close(); } catch (IOException e) { diff --git a/iot-analysis/analysis-zl-event/zl-event-boot/src/main/java/com/njcn/zlevent/utils/FileCheckUtils.java b/iot-analysis/analysis-zl-event/zl-event-boot/src/main/java/com/njcn/zlevent/utils/FileCheckUtils.java deleted file mode 100644 index 29fc592..0000000 --- a/iot-analysis/analysis-zl-event/zl-event-boot/src/main/java/com/njcn/zlevent/utils/FileCheckUtils.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.njcn.zlevent.utils; - -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.zip.CRC32; - -/** - * 类的介绍:用于文件校验 - * - * @author xuyang - * @version 1.0.0 - * @createTime 2023/9/8 13:32 - */ - -public class FileCheckUtils { - - /** - * 32位CRC检验 - * @param inputStream 文件流 - * @return - * @throws IOException - */ - public static long calculateCRC32Checksum(InputStream inputStream) throws IOException { - CRC32 crc32 = new CRC32(); - // 用于读取文件内容的缓冲区 - byte[] buffer = new byte[1024]; - int bytesRead; - while ((bytesRead = inputStream.read(buffer)) != -1) { - crc32.update(buffer, 0, bytesRead); - } - return crc32.getValue(); - } - - /** - * MD5检验 - * @param inputStream 文件流 - * @return - * @throws IOException - */ - public static String calculateMD5Checksum(InputStream inputStream) throws IOException, NoSuchAlgorithmException { - MessageDigest md5 = MessageDigest.getInstance("MD5"); - // 用于读取文件内容的缓冲区 - byte[] buffer = new byte[8192]; - int bytesRead; - while ((bytesRead = inputStream.read(buffer)) != -1) { - md5.update(buffer, 0, bytesRead); - } - byte[] digest = md5.digest(); - // 将MD5摘要转换为十六进制字符串 - StringBuilder md5Checksum = new StringBuilder(); - for (byte b : digest) { - md5Checksum.append(String.format("%02x", b)); - } - return md5Checksum.toString(); - } -} diff --git a/iot-analysis/analysis-zl-event/zl-event-boot/src/main/java/com/njcn/zlevent/utils/SendEventUtils.java b/iot-analysis/analysis-zl-event/zl-event-boot/src/main/java/com/njcn/zlevent/utils/SendEventUtils.java index c292b80..b022dcb 100644 --- a/iot-analysis/analysis-zl-event/zl-event-boot/src/main/java/com/njcn/zlevent/utils/SendEventUtils.java +++ b/iot-analysis/analysis-zl-event/zl-event-boot/src/main/java/com/njcn/zlevent/utils/SendEventUtils.java @@ -18,7 +18,6 @@ import com.njcn.user.pojo.po.app.AppInfoSet; import com.njcn.zlevent.pojo.dto.NoticeUserDto; import com.njcn.zlevent.service.ICsEventUserService; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -32,7 +31,6 @@ import java.net.URL; import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; diff --git a/iot-message/message-boot/src/main/java/com/njcn/message/consumer/AppAutoDataConsumer.java b/iot-message/message-boot/src/main/java/com/njcn/message/consumer/AppAutoDataConsumer.java index 8afc7fd..521c3e2 100644 --- a/iot-message/message-boot/src/main/java/com/njcn/message/consumer/AppAutoDataConsumer.java +++ b/iot-message/message-boot/src/main/java/com/njcn/message/consumer/AppAutoDataConsumer.java @@ -9,6 +9,7 @@ import com.njcn.redis.pojo.enums.AppRedisKey; import com.njcn.redis.pojo.enums.RedisKeyEnum; import com.njcn.redis.utils.RedisUtil; import com.njcn.stat.api.StatFeignClient; +import com.njcn.stat.api.WlRecordFeignClient; import com.njcn.system.api.RocketMqLogFeignClient; import com.njcn.system.pojo.po.RocketmqMsgErrorLog; import lombok.extern.slf4j.Slf4j; @@ -45,6 +46,8 @@ public class AppAutoDataConsumer extends EnhanceConsumerMessageHandler