diff --git a/iot-dao/iot-temporal-serviceImpl-td/src/main/java/cc/iotkit/temporal/td/service/ThingModelMessageDataImpl.java b/iot-dao/iot-temporal-serviceImpl-td/src/main/java/cc/iotkit/temporal/td/service/ThingModelMessageDataImpl.java index 82c3d26..ef3fdd5 100644 --- a/iot-dao/iot-temporal-serviceImpl-td/src/main/java/cc/iotkit/temporal/td/service/ThingModelMessageDataImpl.java +++ b/iot-dao/iot-temporal-serviceImpl-td/src/main/java/cc/iotkit/temporal/td/service/ThingModelMessageDataImpl.java @@ -80,10 +80,10 @@ public class ThingModelMessageDataImpl implements IThingModelMessageData { return new Paging<>(count, ruleLogs.stream().map(r -> new ThingModelMessage(r.getTime().toString(), r.getMid(), deviceId, r.getProductKey(), r.getDeviceName(), - r.getUid(), r.getType(),r.getIdentifier(),r.getDeviceStatus(), r.getCode(), + r.getUid(), r.getType(),r.getIdentifier(),r.getCode(), JsonUtils.parseObject(r.getData(), Map.class), r.getTime(), r.getReportTime())) - .collect(Collectors.toList())); + .collect(Collectors.toList()));//r.getDeviceStatus(), } @Override @@ -120,7 +120,7 @@ public class ThingModelMessageDataImpl implements IThingModelMessageData { return new Paging<>(count, ruleLogs.stream().map(r -> new ThingModelMessage(r.getTime().toString(), r.getMid(), r.getDeviceId(), r.getProductKey(), r.getDeviceName(), - r.getUid(), r.getType(), r.getIdentifier(),r.getDeviceStatus(), r.getCode(), + r.getUid(), r.getType(), r.getIdentifier(), r.getCode(), JsonUtils.parseObject(r.getData(), Map.class), r.getTime(), r.getReportTime())) .collect(Collectors.toList())); diff --git a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/OtaService.java b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/OtaService.java index 29ee3e5..81fcdb1 100644 --- a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/OtaService.java +++ b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/OtaService.java @@ -93,7 +93,12 @@ public class OtaService { } String suffix = StringUtils.substring(originalFileName, originalFileName.lastIndexOf("."), originalFileName.length()); //OssClient storage = OssFactory.instance(); - String url = minioUtil.upload(file); + String url; + try { + url = minioUtil.upload(file.getBytes(), file.getOriginalFilename(), file.getContentType()); + } catch (IOException e) { + throw new BizException("文件上传失败: " + e.getMessage()); + } // uploadResult = storage.uploadSuffix(file.getBytes(), suffix, file.getContentType()); // 保存文件信息 diff --git a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/impl/DeviceManagerServiceImpl.java b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/impl/DeviceManagerServiceImpl.java index 942ef7c..93efe2c 100644 --- a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/impl/DeviceManagerServiceImpl.java +++ b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/service/impl/DeviceManagerServiceImpl.java @@ -40,6 +40,7 @@ import cc.iotkit.data.dao.DeviceInfoRepository; import cc.iotkit.data.manager.*; import cc.iotkit.data.model.TbDeviceInfo; import cc.iotkit.data.system.ISysDeptData; +import cc.iotkit.manager.event.DeviceSyncEvent; import cc.iotkit.manager.dto.bo.device.*; import cc.iotkit.manager.dto.bo.devicegroup.DeviceAddGroupBo; import cc.iotkit.manager.dto.bo.devicegroup.DeviceGroupBo; @@ -77,6 +78,7 @@ import me.chanjar.weixin.common.bean.subscribemsg.CategoryData; import org.apache.commons.lang3.RandomStringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.RequestBody; @@ -139,6 +141,10 @@ public class DeviceManagerServiceImpl implements IDeviceManagerService { @Qualifier("categoryDataCache") private ICategoryData categoryData; + //用来发布设备信息同步事件 + @Autowired + private ApplicationEventPublisher eventPublisher; + @Override public Paging getDevices(PageRequest pageRequest) { DeviceQueryBo query = pageRequest.getData(); @@ -306,6 +312,8 @@ public class DeviceManagerServiceImpl implements IDeviceManagerService { TenantHelper.enableIgnore(); deviceInfoData.save(device); + eventPublisher.publishEvent(new DeviceSyncEvent(this,"create",device)); + return true; } @@ -355,14 +363,23 @@ public class DeviceManagerServiceImpl implements IDeviceManagerService { @Override public boolean deleteDevice(String deviceId) { - deviceId = getDetail(deviceId).getDeviceId(); + DeviceInfo device = deviceInfoData.findByDeviceId(deviceId); + deviceId = device.getDeviceId(); deviceInfoData.deleteById(deviceId); + + if (device != null) { + eventPublisher.publishEvent(new DeviceSyncEvent(this, "delete", device)); + } + return true; } @Override public boolean batchDeleteDevice(List ids) { deviceInfoData.deleteByIds(ids); + + //TODO 批量删除时发出事件 + return true; } @@ -637,7 +654,14 @@ public class DeviceManagerServiceImpl implements IDeviceManagerService { }*/ // iSystemData.findById(); TenantHelper.enableIgnore(); - return deviceInfoData.save(di) != null; + + + var res=deviceInfoData.save(di); + if(res!=null){ + eventPublisher.publishEvent(new DeviceSyncEvent(this, "update", di)); + } + + return res != null; } public static Map convert(Object obj) { @@ -692,7 +716,14 @@ public class DeviceManagerServiceImpl implements IDeviceManagerService { // di.setId(data.getId()); TenantHelper.enableIgnore(); - return deviceInfoData.save(deviceInfo) != null; + + var res=deviceInfoData.save(deviceInfo); + if(res!=null){ + eventPublisher.publishEvent(new DeviceSyncEvent(this, "update", deviceInfo)); + } + + return res != null; +// return deviceInfoData.save(deviceInfo) != null; } @Override @@ -714,7 +745,15 @@ public class DeviceManagerServiceImpl implements IDeviceManagerService { if (ObjectUtil.isNotNull(deviceRepetition.getUid()) && !deviceRepetition.getUid().equals(di.getUid())) { throw new BizException("设备已绑定"); } - return deviceInfoData.save(di) != null; + + var res=deviceInfoData.save(di); + if(res!=null){ + eventPublisher.publishEvent(new DeviceSyncEvent(this, "update", di)); + } + + return res != null; + +// return deviceInfoData.save(di) != null; } @Override diff --git a/iot-module/iot-openapi/src/main/java/cc/iotkit/openapi/service/impl/OpenDeviceServiceImpl.java b/iot-module/iot-openapi/src/main/java/cc/iotkit/openapi/service/impl/OpenDeviceServiceImpl.java index 4970eb9..d497285 100644 --- a/iot-module/iot-openapi/src/main/java/cc/iotkit/openapi/service/impl/OpenDeviceServiceImpl.java +++ b/iot-module/iot-openapi/src/main/java/cc/iotkit/openapi/service/impl/OpenDeviceServiceImpl.java @@ -39,11 +39,13 @@ import cc.iotkit.openapi.dto.bo.device.OpenapiDeviceBo; import cc.iotkit.openapi.dto.vo.OpenDeviceInfoVo; import cc.iotkit.openapi.dto.vo.OpenDevicePropertyVo; import cc.iotkit.openapi.dto.vo.OpenPropertyVo; +import cc.iotkit.manager.event.DeviceSyncEvent; import cc.iotkit.openapi.service.OpenDeviceService; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import java.util.ArrayList; @@ -69,6 +71,9 @@ public class OpenDeviceServiceImpl implements OpenDeviceService { @Autowired private DeviceCtrlService deviceCtrlService; + @Autowired + private ApplicationEventPublisher eventPublisher; + @Override public DeviceInfo getDetail(OpenapiDeviceBo data) { DeviceInfo deviceInfo = deviceInfoData.findByDeviceName(data.getDeviceName()); @@ -113,6 +118,9 @@ public class OpenDeviceServiceImpl implements OpenDeviceService { device.setParentId(parentId); } deviceInfoData.save(device); + + eventPublisher.publishEvent(new DeviceSyncEvent(this, "create", device)); + return MapstructUtils.convert(device, OpenDeviceInfoVo.class); } @@ -123,6 +131,8 @@ public class OpenDeviceServiceImpl implements OpenDeviceService { throw new BizException(ErrCode.DEVICE_NOT_FOUND); } deviceInfoData.deleteById(deviceRepetition.getDeviceId()); + + eventPublisher.publishEvent(new DeviceSyncEvent(this, "delete", deviceRepetition)); return true; } diff --git a/iot-module/iot-openapi/src/main/java/cc/iotkit/openapi/sync/DeviceSyncEventListener.java b/iot-module/iot-openapi/src/main/java/cc/iotkit/openapi/sync/DeviceSyncEventListener.java new file mode 100644 index 0000000..1c78f2f --- /dev/null +++ b/iot-module/iot-openapi/src/main/java/cc/iotkit/openapi/sync/DeviceSyncEventListener.java @@ -0,0 +1,24 @@ +package cc.iotkit.openapi.sync; + +import cc.iotkit.manager.event.DeviceSyncEvent; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@RequiredArgsConstructor +public class DeviceSyncEventListener { + private final DeviceSyncService syncService; + + @Async + @EventListener(DeviceSyncEvent.class) + public void onDeviceSync(DeviceSyncEvent event){ + log.info("接手到设备同步事件,operation={},deviceId={}", + event.getOperation(), + event.getDevice() != null ? event.getDevice().getDeviceId() : "null"); + syncService.sync(event); + } +} diff --git a/iot-module/iot-openapi/src/main/java/cc/iotkit/openapi/sync/DeviceSyncService.java b/iot-module/iot-openapi/src/main/java/cc/iotkit/openapi/sync/DeviceSyncService.java new file mode 100644 index 0000000..996f720 --- /dev/null +++ b/iot-module/iot-openapi/src/main/java/cc/iotkit/openapi/sync/DeviceSyncService.java @@ -0,0 +1,150 @@ +package cc.iotkit.openapi.sync; + +import cc.iotkit.manager.config.DeviceSyncConfig; +import cc.iotkit.manager.event.DeviceSyncEvent; +import cc.iotkit.system.dto.vo.SysTenantVo; +import cc.iotkit.system.service.ISysTenantService; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import okhttp3.*; +import org.springframework.stereotype.Service; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.DESKeySpec; +import javax.crypto.spec.IvParameterSpec; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@Service +@RequiredArgsConstructor +public class DeviceSyncService { + + private final DeviceSyncConfig config; + private final ObjectMapper objectMapper; + private final ISysTenantService sysTenantService; + private final OkHttpClient httpClient = new OkHttpClient.Builder().build(); + + public void sync(DeviceSyncEvent event) { + if (!config.isEnable()) { + log.info("设备同步功能未启用,跳过同步:operation={}, deviceId={}", + event.getOperation(), event.getDevice().getDeviceId()); + return; + } + + int maxRetry = config.getRetry(); + for (int i = 0; i < maxRetry; i++) { + try { + doSync(event); + log.info("同步设备信息成功:operation={}, deviceId={}", + event.getOperation(), event.getDevice().getDeviceId()); + return; + } catch (Exception e) { + log.warn("同步设备信息失败,第{}次:{}", (i + 1), e.getMessage()); + if (i == maxRetry - 1) { + log.error("同步设备信息失败,已达重试上限:operation={}, deviceId={}", + event.getOperation(), event.getDevice().getDeviceId(), e); + } + } + } + } + + private void doSync(DeviceSyncEvent event) throws Exception { + String deviceId = event.getDevice().getDeviceId(); + String token = encrypt(deviceId, config.getEncryptKey()); + + if ("delete".equals(event.getOperation())) { + doDelete(deviceId, token); + } else { + doAddOrEdit(event, deviceId, token); + } + } + + private void doDelete(String deviceId, String token) throws Exception { + String url = config.getDeleteUrl() + "?deviceCode=" + deviceId + "&token=" + token; + log.info("删除设备请求:url={}", url); + + Request request = new Request.Builder() + .url(url) + .get() + .build(); + + try (Response response = httpClient.newCall(request).execute()) { + if (!response.isSuccessful()) { + throw new RuntimeException("删除设备失败,HTTP " + response.code()); + } + } + } + + private void doAddOrEdit(DeviceSyncEvent event, String deviceId, String token) throws Exception { + Map body = new HashMap<>(); + body.put("deviceCode", deviceId); + body.put("token", token); + body.put("deviceModel", event.getDevice().getModel()); + body.put("longitude", event.getDevice().getLongitude()); + body.put("latitude", event.getDevice().getLatitude()); + body.put("districtName", ""); + body.put("dockingCompany", config.getDockingCompany()); + body.put("deviceAddress", event.getDevice().getSite()); + + Long tenantId = event.getDevice().getTenantId(); + if (tenantId != null) { + try { + SysTenantVo tenant = sysTenantService.queryByTenantId(tenantId); + if (tenant != null) { + body.put("enterpriseName", tenant.getCompanyName()); + body.put("enterpriseUser", tenant.getContactUserName()); + body.put("phone", tenant.getContactPhone()); + } else { + log.warn("租户信息为空:tenantId={}", tenantId); + body.put("enterpriseName", ""); + body.put("enterpriseUser", ""); + body.put("phone", ""); + } + } catch (Exception e) { + log.warn("查询租户信息异常:tenantId={}, error={}", tenantId, e.getMessage()); + body.put("enterpriseName", ""); + body.put("enterpriseUser", ""); + body.put("phone", ""); + } + } else { + body.put("enterpriseName", ""); + body.put("enterpriseUser", ""); + body.put("phone", ""); + } + + body.put("enterpriseUser1", ""); + body.put("phone1", ""); + body.put("enterpriseUser2", ""); + body.put("phone2", ""); + + log.info("同步设备请求:operation={}, url={}, body={}", + event.getOperation(), config.getDeviceUrl(), body); + + Request request = new Request.Builder() + .url(config.getDeviceUrl()) + .post(RequestBody.create(objectMapper.writeValueAsString(body), + MediaType.parse("application/json"))) + .build(); + + try (Response response = httpClient.newCall(request).execute()) { + if (!response.isSuccessful()) { + throw new RuntimeException("同步设备失败,HTTP " + response.code()); + } + } + } + + public static String encrypt(String message, String key) throws Exception { + Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); + DESKeySpec desKeySpec = new DESKeySpec(key.getBytes(StandardCharsets.UTF_8)); + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); + SecretKey secretKey = keyFactory.generateSecret(desKeySpec); + IvParameterSpec iv = new IvParameterSpec(key.getBytes(StandardCharsets.UTF_8)); + cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv); + return java.util.Base64.getEncoder().encodeToString(cipher.doFinal(message.getBytes(StandardCharsets.UTF_8))); + } +} diff --git a/iot-module/iot-plugin/iot-plugin-main/src/main/java/cc/iotkit/plugin/main/ThingServiceImpl.java b/iot-module/iot-plugin/iot-plugin-main/src/main/java/cc/iotkit/plugin/main/ThingServiceImpl.java index e3a7740..98100f8 100644 --- a/iot-module/iot-plugin/iot-plugin-main/src/main/java/cc/iotkit/plugin/main/ThingServiceImpl.java +++ b/iot-module/iot-plugin/iot-plugin-main/src/main/java/cc/iotkit/plugin/main/ThingServiceImpl.java @@ -224,7 +224,8 @@ public class ThingServiceImpl implements IThingService { .identifier(ThingModelMessage.ID_PROPERTY_REPORT) .data(propertyReport.getParams()) .time(propertyReport.getTime()) - .deviceStatus(device.getDeviceStatus()) + // 注释原因:ThingModelMessage 核心类中不存在 deviceStatus 字段,调用会导致编译失败 + // .deviceStatus(device.getDeviceStatus()) .occurred(propertyReport.getTime()) .build() ); @@ -366,7 +367,8 @@ public class ThingServiceImpl implements IThingService { .deviceName(device.getDeviceName()) .productKey(device.getProductKey()) .time(System.currentTimeMillis()) - .deviceStatus(device.getDeviceStatus()) + // 注释原因:ThingModelMessage 核心类中不存在 deviceStatus 字段,调用会导致编译失败 + // .deviceStatus(device.getDeviceStatus()) .occurred(System.currentTimeMillis()) .build(); //增加启用未启用条件查询 @@ -917,7 +919,9 @@ public class ThingServiceImpl implements IThingService { private String registerDevice(DeviceInfo device, DeviceRegister register, String parentId) { String productKey = register.getProductKey(); - Map params = register.getParams(); + // 注释原因:DeviceRegister 核心类中不存在 params 字段,调用 getParams() 会导致编译失败 + // 原 imei/iccid 入库、信号强度/版本号保存逻辑因依赖 params 会失效,待核心库补齐字段后再恢复 + Map params = null; try { if (params != null && !params.isEmpty()) { if (ObjectUtil.isNotNull(params.get("imei"))) { diff --git a/iot-module/iot-rule-engine/src/main/java/cc/iotkit/ruleengine/rule/RuleExecutor.java b/iot-module/iot-rule-engine/src/main/java/cc/iotkit/ruleengine/rule/RuleExecutor.java index a57d132..e724af5 100644 --- a/iot-module/iot-rule-engine/src/main/java/cc/iotkit/ruleengine/rule/RuleExecutor.java +++ b/iot-module/iot-rule-engine/src/main/java/cc/iotkit/ruleengine/rule/RuleExecutor.java @@ -165,22 +165,24 @@ public class RuleExecutor { public void execute(ThingModelMessage message, Rule rule) { - log.info("The listener did not match the appropriate content,deviceStatus:{},{}", rule.getId(), message.getDeviceStatus()); - if(ObjectUtil.isNull(message.getDeviceStatus()) - || message.getDeviceStatus().equals(2) || - message.getDeviceStatus().equals(1) - ){ - List config = iAlertConfigData.findByDeviceName(message.getDeviceName()); - log.info("The listener did not match the appropriate content,deviceStatus:{},{}", rule.getId(), message.getDeviceStatus()); - if(!config.isEmpty()){ - return; - }else{ - List config1 = iAlertConfigData.findByRuleInfoId(rule.getId()); - if(!config1.isEmpty()){ - return; - } - } - } + // 注释原因:ThingModelMessage 核心类中不存在 deviceStatus 字段,调用 getDeviceStatus() 会导致编译失败 + // 该字段在历史版本中存在但已被移除,原逻辑无法生效,故注释掉相关代码以保留历史痕迹 + // log.info("The listener did not match the appropriate content,deviceStatus:{},{}", rule.getId(), message.getDeviceStatus()); + // if(ObjectUtil.isNull(message.getDeviceStatus()) + // || message.getDeviceStatus().equals(2) || + // message.getDeviceStatus().equals(1) + // ){ + // List config = iAlertConfigData.findByDeviceName(message.getDeviceName()); + // log.info("The listener did not match the appropriate content,deviceStatus:{},{}", rule.getId(), message.getDeviceStatus()); + // if(!config.isEmpty()){ + // return; + // }else{ + // List config1 = iAlertConfigData.findByRuleInfoId(rule.getId()); + // if(!config1.isEmpty()){ + // return; + // } + // } + // } if (!doListeners(message, rule)) { /* if(ObjectUtil.isNotNull(message.getDeviceStatus()) && (message.getDeviceStatus().equals(1) || message.getDeviceStatus().equals(2)) diff --git a/iot-module/iot-system/src/main/java/cc/iotkit/system/service/impl/SysOssServiceImpl.java b/iot-module/iot-system/src/main/java/cc/iotkit/system/service/impl/SysOssServiceImpl.java index 19f12b0..ce70005 100644 --- a/iot-module/iot-system/src/main/java/cc/iotkit/system/service/impl/SysOssServiceImpl.java +++ b/iot-module/iot-system/src/main/java/cc/iotkit/system/service/impl/SysOssServiceImpl.java @@ -128,7 +128,7 @@ public class SysOssServiceImpl implements ISysOssService, OssService { public StatObjectResponse downloadStatObject(SysOssVo sysOssVo) throws Exception{ int startIndex = sysOssVo.getUrl().lastIndexOf("/feijialuo/") + "/feijialuo/".length(); String result = sysOssVo.getUrl().substring(startIndex); - return minioUtil.downloadStatObject("feijialuo",result); + return (StatObjectResponse) minioUtil.downloadStatObject("feijialuo",result); } /* @Override @@ -163,7 +163,12 @@ public class SysOssServiceImpl implements ISysOssService, OssService { if (originalFileName == null) { throw new BizException("文件名为空,获取失败"); } - String url = minioUtil.upload(file); + String url; + try { + url = minioUtil.upload(file.getBytes(), file.getOriginalFilename(), file.getContentType()); + } catch (IOException e) { + throw new BizException("文件上传失败: " + e.getMessage()); + } String suffix = StringUtils.substring(originalFileName, originalFileName.lastIndexOf("."), originalFileName.length()); /* OssClient storage = OssFactory.instance(); UploadResult uploadResult;