From 8ff09fea018acc63b107430fe4a5c7ca1ffbed5c Mon Sep 17 00:00:00 2001 From: alwayssuper <191763414@qq.com> Date: Fri, 20 Dec 2024 14:44:46 +0800 Subject: [PATCH 1/4] =?UTF-8?q?[=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96]?= =?UTF-8?q?=EF=BC=9A=E7=89=A9=E6=A8=A1=E5=9E=8B=E6=97=A5=E5=BF=97=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 1 + .../product/IotProductDeviceTypeEnum.java | 2 +- ...er.java => TdThingModelMessageMapper.java} | 2 +- .../simulatesend/SimulateSendConsumer.java | 8 ++++ .../IotThingModelMessageServiceImpl.java | 43 ++++++++++--------- .../module/iot/util/IotTdDatabaseUtils.java | 36 ++++++++++------ .../tdengine/TdThinkModelMessageMapper.xml | 6 +-- 7 files changed, 59 insertions(+), 39 deletions(-) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/{TdThinkModelMessageMapper.java => TdThingModelMessageMapper.java} (93%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/simulatesend/SimulateSendConsumer.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 4539f12591..a763924b57 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -14,6 +14,7 @@ public interface ErrorCodeConstants { ErrorCode PRODUCT_KEY_EXISTS = new ErrorCode(1_050_001_001, "产品标识已经存在"); ErrorCode PRODUCT_STATUS_NOT_DELETE = new ErrorCode(1_050_001_002, "产品状是发布状态,不允许删除"); ErrorCode PRODUCT_STATUS_NOT_ALLOW_THING_MODEL = new ErrorCode(1_050_001_003, "产品状是发布状态,不允许操作物模型"); + ErrorCode PRODUCT_DEVICE_NOT_EXISTS = new ErrorCode(1_050_001_004, "产品设备类型不存在"); // ========== 产品物模型 1-050-002-000 ============ ErrorCode THING_MODEL_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在"); diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java index ef1432804a..8a5aaf74bf 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java @@ -16,7 +16,7 @@ import java.util.Arrays; public enum IotProductDeviceTypeEnum implements IntArrayValuable { DIRECT(0, "直连设备"), - GATEWAY_CHILD(1, "网关子设备"), + GATEWAY_SUB(1, "网关子设备"), GATEWAY(2, "网关设备"); /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThinkModelMessageMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThingModelMessageMapper.java similarity index 93% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThinkModelMessageMapper.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThingModelMessageMapper.java index da9730e74b..0a735be03a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThinkModelMessageMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThingModelMessageMapper.java @@ -10,7 +10,7 @@ import org.apache.ibatis.annotations.Mapper; */ @Mapper @DS("tdengine") -public interface TdThinkModelMessageMapper { +public interface TdThingModelMessageMapper { /** * 创建物模型消息日志超级表超级表 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/simulatesend/SimulateSendConsumer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/simulatesend/SimulateSendConsumer.java new file mode 100644 index 0000000000..dfc911df52 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/simulatesend/SimulateSendConsumer.java @@ -0,0 +1,8 @@ +package cn.iocoder.yudao.module.iot.mq.consumer.simulatesend; + +/** + * @author alwayssuper + * @date 2024/12/20 8:04 + */ +public class SimulateSendConsumer { +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java index 454a2e072d..87bf01d26b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java @@ -13,11 +13,9 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.*; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; -import cn.iocoder.yudao.module.iot.dal.tdengine.TdThinkModelMessageMapper; import cn.iocoder.yudao.module.iot.enums.IotConstants; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; @@ -68,11 +66,6 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ @Resource private DeviceDataRedisDAO deviceDataRedisDAO; - @Resource - private IotTdDatabaseUtils iotTdDatabaseUtils; - - @Resource - private TdThinkModelMessageMapper tdThinkModelMessageMapper; // TODO @haohao:这个方法,可以考虑加下 1. 2. 3. 更有层次感 @Override @@ -85,7 +78,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ iotDeviceService.updateDeviceStatus(new IotDeviceStatusUpdateReqVO() .setId(device.getId()).setStatus(IotDeviceStatusEnum.ONLINE.getStatus())); // 1.2 创建物模型日志设备表 - createThinkModelMessageDeviceTable(device.getProductKey(), device.getDeviceName(), device.getDeviceKey()); + createThingModelMessageDeviceTable(device.getProductKey(), device.getDeviceName(), device.getDeviceKey()); } // 2. 获取设备属性并进行物模型校验,过滤非物模型属性 @@ -122,13 +115,23 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ // 2. 获取超级表的名称和数据库名称 // TODO @alwayssuper:最好 databaseName、superTableName 的处理,放到 tdThinkModelMessageMapper 里。可以考虑,弄个 default 方法 - String databaseName = iotTdDatabaseUtils.getDatabaseName(); + String databaseName = IotTdDatabaseUtils.getDatabaseName(url); String superTableName = IotTdDatabaseUtils.getThingModelMessageSuperTableName(product.getProductKey()); + // 解析物模型,获取字段列表 + List schemaFields = List.of( + TdFieldDO.builder().fieldName("time").dataType("TIMESTAMP").build(), + TdFieldDO.builder().fieldName("id").dataType("NCHAR").dataLength(64).build(), + TdFieldDO.builder().fieldName("sys").dataType("NCHAR").dataLength(2048).build(), + TdFieldDO.builder().fieldName("method").dataType("NCHAR").dataLength(256).build(), + TdFieldDO.builder().fieldName("params").dataType("NCHAR").dataLength(2048).build() + ); + // 设置超级表的标签 + List tagsFields = List.of( + TdFieldDO.builder().fieldName("device_key").dataType("NCHAR").dataLength(64).build() + ); // 3. 创建超级表 - tdThinkModelMessageMapper.createSuperTable(ThingModelMessageDO.builder().build() - .setDataBaseName(databaseName) - .setSuperTableName(superTableName)); + tdEngineDDLMapper.createSuperTable(new TdTableDO(databaseName, superTableName, schemaFields, tagsFields)); } private List getValidFunctionList(String productKey) { @@ -237,20 +240,20 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ * @param deviceKey 设备 Key * */ - private void createThinkModelMessageDeviceTable(String productKey, String deviceName, String deviceKey){ + private void createThingModelMessageDeviceTable(String productKey, String deviceName, String deviceKey){ // 1. 获取超级表的名称、数据库名称、设备日志表名称 - String databaseName = iotTdDatabaseUtils.getDatabaseName(); + String databaseName = IotTdDatabaseUtils.getDatabaseName(url); String superTableName = IotTdDatabaseUtils.getThingModelMessageSuperTableName(productKey); // TODO @alwayssuper:最好 databaseName、superTableName、thinkModelMessageDeviceTableName 的处理,放到 tdThinkModelMessageMapper 里。可以考虑,弄个 default 方法 - String thinkModelMessageDeviceTableName = IotTdDatabaseUtils.getThinkModelMessageDeviceTableName(productKey, deviceName); + String thinkModelMessageDeviceTableName = IotTdDatabaseUtils.getThingModelMessageDeviceTableName(productKey, deviceName); // 2. 创建物模型日志设备数据表 - tdThinkModelMessageMapper.createTableWithTag(ThingModelMessageDO.builder().build() - .setDataBaseName(databaseName) - .setSuperTableName(superTableName) - .setTableName(thinkModelMessageDeviceTableName) - .setDeviceKey(deviceKey)); +// tdThingModelMessageMapper.createTableWithTag(ThingModelMessageDO.builder().build() +// .setDataBaseName(databaseName) +// .setSuperTableName(superTableName) +// .setTableName(thinkModelMessageDeviceTableName) +// .setDeviceKey(deviceKey)); } /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java index 8feef7bf60..e4ecf74657 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java @@ -1,9 +1,14 @@ package cn.iocoder.yudao.module.iot.util; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.module.iot.enums.IotConstants; +import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_DEVICE_NOT_EXISTS; + // TODO @芋艿:可能要思索下,有没更好的处理方式 // TODO @芋艿:怎么改成无状态 /** @@ -11,19 +16,14 @@ import org.springframework.stereotype.Component; * * @author AlwaysSuper */ -@Component public class IotTdDatabaseUtils { - @Value("${spring.datasource.dynamic.datasource.tdengine.url}") - private String url; - /** * 获取数据库名称 */ - public String getDatabaseName() { + public static String getDatabaseName(String url) { // TODO @alwayssuper:StrUtil.subAfter("/") - int index = url.lastIndexOf("/"); - return index != -1 ? url.substring(index + 1) : url; + return StrUtil.subAfter(url, "/", true); } /** @@ -35,11 +35,19 @@ public class IotTdDatabaseUtils { */ public static String getProductSuperTableName(Integer deviceType, String productKey) { // TODO @alwayssuper:枚举字段,不要 1、2、3;不符合预期,抛出异常 - return switch (deviceType) { - case 1 -> String.format(IotConstants.GATEWAY_SUB_STABLE_NAME_FORMAT, productKey).toLowerCase(); - case 2 -> String.format(IotConstants.GATEWAY_STABLE_NAME_FORMAT, productKey).toLowerCase(); - default -> String.format(IotConstants.DEVICE_STABLE_NAME_FORMAT, productKey).toLowerCase(); - }; + if (deviceType == null) { + throw exception(PRODUCT_DEVICE_NOT_EXISTS); + } + if (IotProductDeviceTypeEnum.GATEWAY_SUB.getType().equals(deviceType)) { + return String.format(IotConstants.GATEWAY_SUB_STABLE_NAME_FORMAT, productKey).toLowerCase(); + } else if (IotProductDeviceTypeEnum.GATEWAY.getType().equals(deviceType)) { + return String.format(IotConstants.GATEWAY_STABLE_NAME_FORMAT, productKey).toLowerCase(); + } else if (IotProductDeviceTypeEnum.DIRECT.getType().equals(deviceType)){ + return String.format(IotConstants.DEVICE_STABLE_NAME_FORMAT, productKey).toLowerCase(); + } + else{ + throw exception(PRODUCT_DEVICE_NOT_EXISTS); + } } /** @@ -51,7 +59,7 @@ public class IotTdDatabaseUtils { */ public static String getThingModelMessageSuperTableName(String productKey) { // TODO @alwayssuper:是不是应该 + 拼接就好,不用 format - return String.format("thing_model_message_", productKey).toLowerCase(); + return "thing_model_message_" + productKey.toLowerCase(); } /** @@ -61,7 +69,7 @@ public class IotTdDatabaseUtils { * @param deviceName 设备名称 * @return 物模型日志设备表名 */ - public static String getThinkModelMessageDeviceTableName(String productKey, String deviceName) { + public static String getThingModelMessageDeviceTableName(String productKey, String deviceName) { return String.format(IotConstants.THING_MODEL_MESSAGE_TABLE_NAME_FORMAT, productKey.toLowerCase(), deviceName.toLowerCase()); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml index aeecd5dc1e..074ae98842 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml @@ -2,7 +2,7 @@ - + @@ -14,7 +14,7 @@ method VARCHAR(255), params VARCHAR(2048) )TAGS ( - deviceKey VARCHAR(255) + device_key VARCHAR(255) ) @@ -28,7 +28,7 @@ method , params )TAGS( - #{deviceKey} + #{device_key} ) \ No newline at end of file From a2532013ec1ade71362a4361cb37aedb3b5f0519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Fri, 20 Dec 2024 18:57:40 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E3=80=90=E6=96=B0=E5=A2=9E=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E3=80=91IoT=EF=BC=9A=20HTTP=20=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/disabled.txt | 0 plugins/enabled.txt | 0 ...-module-iot-http-plugin-2.2.0-snapshot.jar | Bin 0 -> 9347 bytes yudao-module-iot/pom.xml | 1 - yudao-module-iot/yudao-module-iot-api/pom.xml | 11 ++ .../yudao/module/iot/api/DeviceDataApi.java | 17 ++ .../yudao/module/iot/api/ServiceRegistry.java | 34 ++++ yudao-module-iot/yudao-module-iot-biz/pom.xml | 6 + .../iot/api/device/DeviceDataApiImpl.java | 25 +++ .../yudao/module/iot/api/package-info.java | 1 + .../admin/plugininfo/Greetings.java | 41 ----- .../admin/plugininfo/PluginController.java | 20 +-- .../admin/plugininfo/WhazzupGreeting.java | 34 ---- .../vo/PluginInstanceRespVO.java | 2 - .../vo/PluginInstanceSaveReqVO.java | 1 - .../plugin/ServiceRegistryConfiguration.java | 34 ++++ .../framework/plugin/SpringConfiguration.java | 8 +- .../service/device/IotDeviceDataService.java | 3 +- .../plugininfo/PluginInfoServiceImpl.java | 40 +++-- .../product/IotProductServiceImpl.java | 2 +- .../yudao-module-iot-plugin-api/pom.xml | 30 ---- .../yudao/module/iot/api/Greeting.java | 27 --- .../yudao/module/iot/api/package-info.java | 6 - .../yudao-module-iot-plugin/pom.xml | 24 ++- .../plugin.properties | 6 + .../yudao-module-iot-demo-plugin/pom.xml | 148 ++++++++++++++++ .../src/main/assembly/assembly.xml | 31 ++++ .../yudao/module/iot/plugin/DemoPlugin.java | 77 +++++++++ .../plugin.properties | 1 + .../yudao-module-iot-http-plugin/pom.xml | 96 +++++------ .../src/main/assembly/assembly.xml | 6 - .../yudao/module/iot/plugin/HttpHandler.java | 160 ++++++++++++++++++ .../yudao/module/iot/plugin/HttpPlugin.java | 102 +++++------ 33 files changed, 690 insertions(+), 304 deletions(-) create mode 100644 plugins/disabled.txt create mode 100644 plugins/enabled.txt create mode 100644 plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/DeviceDataApi.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/Greetings.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/WhazzupGreeting.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugin-api/pom.xml delete mode 100644 yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/Greeting.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/plugin.properties create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/pom.xml create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/src/main/assembly/assembly.xml create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/DemoPlugin.java create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java diff --git a/plugins/disabled.txt b/plugins/disabled.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugins/enabled.txt b/plugins/enabled.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar b/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar new file mode 100644 index 0000000000000000000000000000000000000000..0300a632ae6d0bd042e974113a7193dc0e578232 GIT binary patch literal 9347 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 yudao-module-iot-api yudao-module-iot-biz - yudao-module-iot-plugin-api yudao-module-iot-plugin 4.0.0 diff --git a/yudao-module-iot/yudao-module-iot-api/pom.xml b/yudao-module-iot/yudao-module-iot-api/pom.xml index 8a75b09bf9..a370944457 100644 --- a/yudao-module-iot/yudao-module-iot-api/pom.xml +++ b/yudao-module-iot/yudao-module-iot-api/pom.xml @@ -21,6 +21,17 @@ cn.iocoder.boot yudao-common + + + org.pf4j + pf4j-spring + + + org.slf4j + slf4j-log4j12 + + + diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/DeviceDataApi.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/DeviceDataApi.java new file mode 100644 index 0000000000..2f3ef60477 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/DeviceDataApi.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.iot.api; + +/** + * 设备数据 API + */ +public interface DeviceDataApi { + + /** + * 保存设备数据 + * + * @param productKey 产品 key + * @param deviceName 设备名称 + * @param message 消息 + */ + void saveDeviceData(String productKey, String deviceName, String message); + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java new file mode 100644 index 0000000000..5c55bd89cb --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.iot.api; + +import java.util.HashMap; +import java.util.Map; + +/** + * 服务注册表 - 插架模块使用,无法使用 Spring 注入 + */ +public class ServiceRegistry { + private static final Map, Object> services = new HashMap<>(); + + /** + * 注册服务 + * + * @param serviceClass 服务类 + * @param serviceImpl 服务实现 + * @param 服务类 + */ + public static void registerService(Class serviceClass, T serviceImpl) { + services.put(serviceClass, serviceImpl); + } + + /** + * 获得服务 + * + * @param serviceClass 服务类 + * @param 服务类 + * @return 服务实现 + */ + @SuppressWarnings("unchecked") + public static T getService(Class serviceClass) { + return (T) services.get(serviceClass); + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index 774d353809..c0810a183d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -81,6 +81,12 @@ org.pf4j pf4j-spring + + + org.slf4j + slf4j-log4j12 + + diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java new file mode 100644 index 0000000000..59ae850a1e --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.iot.api.device; + +import cn.iocoder.yudao.module.iot.api.DeviceDataApi; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceDataService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 设备数据 API 实现类 + */ +@Service +@Validated +public class DeviceDataApiImpl implements DeviceDataApi { + + @Resource + private IotDeviceDataService iotDeviceDataService; + + @Override + public void saveDeviceData(String productKey, String deviceName, String message) { + iotDeviceDataService.saveDeviceData(productKey, deviceName, message); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java new file mode 100644 index 0000000000..c0f3d748a1 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.iot.api; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/Greetings.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/Greetings.java deleted file mode 100644 index 1b29a34475..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/Greetings.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2012-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package cn.iocoder.yudao.module.iot.controller.admin.plugininfo; - -import cn.iocoder.yudao.module.iot.api.Greeting; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.util.List; - -/** - * 打招呼 测试用例 - */ -@Component -public class Greetings { - - @Autowired - private List greetings; - - public Integer printGreetings() { - System.out.printf("找到扩展点的 %d 个扩展 '%s'%n", greetings.size(), Greeting.class.getName()); - for (Greeting greeting : greetings) { - System.out.println(">>> " + greeting.getGreeting()); - } - return greetings.size(); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginController.java index 4cd22bccaf..321eef9b6f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginController.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.plugininfo; import jakarta.annotation.Resource; import org.pf4j.spring.SpringPluginManager; import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.ApplicationContext; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -25,12 +24,8 @@ import java.util.stream.Collectors; @RequestMapping("/iot/plugins") public class PluginController { - @Resource - private ApplicationContext applicationContext; @Resource private SpringPluginManager springPluginManager; - @Resource - private Greetings greetings; @Value("${pf4j.pluginsDir}") private String pluginsDir; @@ -73,10 +68,8 @@ public class PluginController { return ResponseEntity.ok("插件上传并加载成功"); } catch (IOException e) { - e.printStackTrace(); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("上传插件时发生错误: " + e.getMessage()); } catch (Exception e) { - e.printStackTrace(); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("加载插件时发生错误: " + e.getMessage()); } } @@ -120,15 +113,4 @@ public class PluginController { return ResponseEntity.ok(plugins); } - /** - * 打印问候语 - * - * @return 问候语数量 - */ - @PermitAll - @GetMapping("/printGreetings") - public ResponseEntity printGreetings() { - Integer count = greetings.printGreetings(); - return ResponseEntity.ok(count); - } -} +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/WhazzupGreeting.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/WhazzupGreeting.java deleted file mode 100644 index b6ca7f322b..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/WhazzupGreeting.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2012-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package cn.iocoder.yudao.module.iot.controller.admin.plugininfo; - -import cn.iocoder.yudao.module.iot.api.Greeting; -import org.pf4j.Extension; -import org.springframework.stereotype.Component; - -/** - * 打招呼 测试用例 - */ -@Extension -@Component -public class WhazzupGreeting implements Greeting { - - @Override - public String getGreeting() { - return "Whazzup"; - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceRespVO.java index e71ff29045..92edca821d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceRespVO.java @@ -2,8 +2,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; -import java.util.*; -import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDateTime; import com.alibaba.excel.annotation.*; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceSaveReqVO.java index 8d927045d5..95db299d19 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceSaveReqVO.java @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; -import java.util.*; import jakarta.validation.constraints.*; @Schema(description = "管理后台 - IoT 插件实例新增/修改 Request VO") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java new file mode 100644 index 0000000000..385c8aee56 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.iot.framework.plugin; + +import cn.iocoder.yudao.module.iot.api.DeviceDataApi; +import cn.iocoder.yudao.module.iot.api.ServiceRegistry; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; + +@Slf4j +@Configuration +public class ServiceRegistryConfiguration { + + @Resource + private DeviceDataApi deviceDataApi; + + @PostConstruct + public void init() { + // 将主程序中的 DeviceDataApi 实例注册到 ServiceRegistry + ServiceRegistry.registerService(DeviceDataApi.class, deviceDataApi); + log.info("[init][将 DeviceDataApi 实例注册到 ServiceRegistry 中]"); + } + + /** + * 定义一个标记用的 Bean,用于表示 ServiceRegistry 已初始化完成 + */ + @Bean("serviceRegistryInitializedMarker") + public Object serviceRegistryInitializedMarker() { + // 返回任意对象即可,这里返回null都可以,但最好返回个实际对象 + return new Object(); + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java index db03332d90..d87a94f318 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.iot.framework.plugin; -import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.Greetings; import org.pf4j.spring.SpringPluginManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -10,14 +9,9 @@ import org.springframework.context.annotation.DependsOn; public class SpringConfiguration { @Bean + @DependsOn("serviceRegistryInitializedMarker") public SpringPluginManager pluginManager() { return new SpringPluginManager(); } - @Bean - @DependsOn("pluginManager") - public Greetings greetings() { - return new Greetings(); - } - } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java index 70fd23014e..1dd4ad666e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java @@ -20,7 +20,8 @@ public interface IotDeviceDataService { * * @param productKey 产品 key * @param deviceName 设备名称 - * @param message 消息 + * @param message 消息 + *

JSON 格式,参见 ... */ void saveDeviceData(String productKey, String deviceName, String message); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java index daa76acc63..bd7efa8d0c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java @@ -22,9 +22,7 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import org.springframework.web.multipart.MultipartFile; -import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.jar.JarEntry; @@ -220,24 +218,24 @@ public class PluginInfoServiceImpl implements PluginInfoService { pluginInfoMapper.updateById(pluginInfoDo); } - @PostConstruct - public void init() { - Executors.newSingleThreadScheduledExecutor().schedule(this::startPlugins, 3, TimeUnit.SECONDS); - } - - @SneakyThrows - private void startPlugins() { - for (PluginInfoDO pluginInfoDO : pluginInfoMapper.selectList()) { - if (!IotPluginStatusEnum.RUNNING.getStatus().equals(pluginInfoDO.getStatus())) { - continue; - } - log.info("start plugin:{}", pluginInfoDO.getPluginId()); - try { - pluginManager.startPlugin(pluginInfoDO.getPluginId()); - } catch (Exception e) { - log.error("start plugin error", e); - } - } - } +// @PostConstruct +// public void init() { +// Executors.newSingleThreadScheduledExecutor().schedule(this::startPlugins, 3, TimeUnit.SECONDS); +// } +// +// @SneakyThrows +// private void startPlugins() { +// for (PluginInfoDO pluginInfoDO : pluginInfoMapper.selectList()) { +// if (!IotPluginStatusEnum.RUNNING.getStatus().equals(pluginInfoDO.getStatus())) { +// continue; +// } +// log.info("start plugin:{}", pluginInfoDO.getPluginId()); +// try { +// pluginManager.startPlugin(pluginInfoDO.getPluginId()); +// } catch (Exception e) { +// log.error("start plugin error", e); +// } +// } +// } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index 628805a97e..a53aee55d2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -122,7 +122,7 @@ public class IotProductServiceImpl implements IotProductService { thingModelFunctionService.createSuperTableDataModel(id); // 3.2 创建物模型日志超级表数据模型 thingModelMessageService.createSuperTable(id); - }x + } productMapper.updateById(updateObj); } diff --git a/yudao-module-iot/yudao-module-iot-plugin-api/pom.xml b/yudao-module-iot/yudao-module-iot-plugin-api/pom.xml deleted file mode 100644 index 6d5eb765b1..0000000000 --- a/yudao-module-iot/yudao-module-iot-plugin-api/pom.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - 4.0.0 - cn.iocoder.boot - yudao-module-iot-plugin-api - 0.0.1 - jar - - ${project.artifactId} - - 物联网 模块插件 API,暴露给其它模块调用 - - - - 0.9.0 - - - - - - org.pf4j - pf4j-spring - ${pf4j-spring.version} - provided - - - - diff --git a/yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/Greeting.java b/yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/Greeting.java deleted file mode 100644 index b284549373..0000000000 --- a/yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/Greeting.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2012-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package cn.iocoder.yudao.module.iot.api; - -import org.pf4j.ExtensionPoint; - -/** - * @author Decebal Suiu - */ -public interface Greeting extends ExtensionPoint { - - String getGreeting(); - -} diff --git a/yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java b/yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java deleted file mode 100644 index 7da0c665ba..0000000000 --- a/yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -/** - * 占位 - * - * TODO 芋艿:后续删除 - */ -package cn.iocoder.yudao.module.iot.api; diff --git a/yudao-module-iot/yudao-module-iot-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/pom.xml index 8ec68638f3..c8f0ff0fe8 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/pom.xml @@ -2,19 +2,29 @@ - 4.0.0 - cn.iocoder.boot - yudao-module-iot-plugin - 0.0.1 - pom - + + + + + + + yudao-module-iot + cn.iocoder.boot + ${revision} + + yudao-module-iot-demo-plugin yudao-module-iot-http-plugin + 4.0.0 + + yudao-module-iot-plugin + pom + ${project.artifactId} - 物联网模块 - 插件模块 + 物联网 插件 模块 \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/plugin.properties b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/plugin.properties new file mode 100644 index 0000000000..5a67270bb0 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/plugin.properties @@ -0,0 +1,6 @@ +plugin.id=demo-plugin +plugin.class=cn.iocoder.yudao.module.iot.plugin.DemoPlugin +plugin.version=0.0.1 +plugin.provider=ahh +plugin.dependencies= +plugin.description=demo-plugin diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/pom.xml new file mode 100644 index 0000000000..3d58a1a75e --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/pom.xml @@ -0,0 +1,148 @@ + + + + yudao-module-iot-plugin + cn.iocoder.boot + ${revision} + + 4.0.0 + jar + + yudao-module-iot-demo-plugin + + ${project.artifactId} + + 物联网 插件模块 - demo 插件 + + + + + demo-plugin + cn.iocoder.yudao.module.iot.plugin.DemoPlugin + 0.0.1 + ahh + + + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 1.6 + + + unzip jar file + package + + + + + + + run + + + + + + + maven-assembly-plugin + 2.3 + + + + src/main/assembly/assembly.xml + + + false + + + + make-assembly + package + + attached + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + + ${plugin.id} + ${plugin.class} + ${plugin.version} + ${plugin.provider} + ${plugin.dependencies} + + + + + + + maven-deploy-plugin + + true + + + + + + + + + org.springframework.boot + spring-boot-starter-web + ${spring.boot.version} + provided + + + + org.pf4j + pf4j-spring + provided + + + + cn.iocoder.boot + yudao-module-iot-api + ${revision} + + + org.projectlombok + lombok + ${lombok.version} + provided + + + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/src/main/assembly/assembly.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/src/main/assembly/assembly.xml new file mode 100644 index 0000000000..daec9e4315 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/src/main/assembly/assembly.xml @@ -0,0 +1,31 @@ + + plugin + + zip + + false + + + false + runtime + lib + + *:jar:* + + + + + + + target/plugin-classes + classes + + + diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/DemoPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/DemoPlugin.java new file mode 100644 index 0000000000..c97a5b9b5e --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/DemoPlugin.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.iot.plugin; + +import com.sun.net.httpserver.HttpServer; +import lombok.extern.slf4j.Slf4j; +import org.pf4j.Plugin; +import org.pf4j.PluginWrapper; +import org.pf4j.RuntimeMode; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.InetSocketAddress; + +/** + * 一个启动 HTTP 服务器的简单插件。 + */ +@Slf4j +public class DemoPlugin extends Plugin { + + private HttpServer server; + + public DemoPlugin(PluginWrapper wrapper) { + super(wrapper); + } + + @Override + public void start() { + log.info("Demo 插件启动"); + // for testing the development mode + if (RuntimeMode.DEVELOPMENT.equals(wrapper.getRuntimeMode())) { + log.info("DemoPlugin in DEVELOPMENT mode"); + } + startDemoServer(); + } + + @Override + public void stop() { + log.info("Demo 插件停止"); + stopDemoServer(); + } + + private void startDemoServer() { + try { + server = HttpServer.create(new InetSocketAddress(9081), 0); + server.createContext("/", exchange -> { + String response = "Hello from DemoPlugin"; + exchange.sendResponseHeaders(200, response.getBytes().length); + OutputStream os = exchange.getResponseBody(); + os.write(response.getBytes()); + os.close(); + }); + server.setExecutor(null); + server.start(); + log.info("HTTP 服务器启动成功,端口为 9081"); + log.info("访问地址为 http://127.0.0.1:9081/"); + } catch (IOException e) { + log.error("HTTP 服务器启动失败", e); + } + } + + private void stopDemoServer() { + if (server != null) { + server.stop(0); + log.info("HTTP 服务器停止成功"); + } + } + +// @Extension +// public static class WelcomeGreeting implements Greeting { +// +// @Override +// public String getGreeting() { +// return "Welcome to DemoPlugin"; +// } +// +// } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/plugin.properties b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/plugin.properties index 694c97ba5f..4e1199acfc 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/plugin.properties +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/plugin.properties @@ -3,3 +3,4 @@ plugin.class=cn.iocoder.yudao.module.iot.plugin.HttpPlugin plugin.version=0.0.1 plugin.provider=ahh plugin.dependencies= +plugin.description=http-plugin-0.0.1 diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml index eccf47febd..200a451b62 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml @@ -3,14 +3,20 @@ xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation=" http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + yudao-module-iot-plugin + cn.iocoder.boot + ${revision} + 4.0.0 - cn.iocoder.boot - yudao-module-iot-http-plugin - 0.0.1 jar + yudao-module-iot-http-plugin + ${project.artifactId} - 物联网 模块 - http 插件 + + 物联网 插件模块 - http 插件 + @@ -19,50 +25,8 @@ 0.0.1 ahh - - - 17 - ${java.version} - ${java.version} - 1.6 - 2.3 - 2.4 - 0.9.0 - - 1.18.34 - 3.3.1 - UTF-8 - - - - org.springframework.boot - spring-boot-starter-web - ${spring.boot.version} - provided - - - - org.pf4j - pf4j-spring - ${pf4j-spring.version} - provided - - - - cn.iocoder.boot - yudao-module-iot-plugin-api - ${project.version} - - - org.projectlombok - lombok - ${lombok.version} - provided - - - + + org.springframework.boot + spring-boot-starter-web + + + + org.pf4j + pf4j-spring + provided + + + + cn.iocoder.boot + yudao-module-iot-api + ${revision} + + + org.projectlombok + lombok + ${lombok.version} + provided + + + io.netty + netty-all + 4.1.63.Final + + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/assembly/assembly.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/assembly/assembly.xml index ce2e92cf95..daec9e4315 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/assembly/assembly.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/assembly/assembly.xml @@ -1,9 +1,3 @@ - plugin diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java new file mode 100644 index 0000000000..c145182eda --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java @@ -0,0 +1,160 @@ +package cn.iocoder.yudao.module.iot.plugin; + +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import cn.iocoder.yudao.module.iot.api.DeviceDataApi; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.http.*; +import io.netty.util.CharsetUtil; + +/** + * 基于 Netty 的 HTTP 处理器,用于接收设备上报的数据并调用主程序的 DeviceDataApi 接口进行处理。 + *

+ * 请求格式: + * POST /sys/{productKey}/{deviceName}/thing/event/property/post + * 请求体为 JSON 格式数据。 + *

+ * 返回结果为 JSON 格式,包含统一的 code、data、id、message、method、version 字段。 + */ +public class HttpHandler extends SimpleChannelInboundHandler { + + private final DeviceDataApi deviceDataApi; + + public HttpHandler(DeviceDataApi deviceDataApi) { + this.deviceDataApi = deviceDataApi; + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) { + String uri = request.uri(); + + // 期望的路径格式: /sys/{productKey}/{deviceName}/thing/event/property/post + // 使用 "/" 拆分路径 + String[] parts = uri.split("/"); + + /* + 拆分结果示例: + parts[0] = "" + parts[1] = "sys" + parts[2] = productKey + parts[3] = deviceName + parts[4] = "thing" + parts[5] = "event" + parts[6] = "property" + parts[7] = "post" + */ + boolean isCorrectPath = parts.length == 8 + && "sys".equals(parts[1]) + && "thing".equals(parts[4]) + && "event".equals(parts[5]) + && "property".equals(parts[6]) + && "post".equals(parts[7]); + + if (!isCorrectPath) { + // 如果路径不匹配,返回 404 错误 + writeResponse(ctx, HttpResponseStatus.NOT_FOUND, "Not Found"); + return; + } + + String productKey = parts[2]; + String deviceName = parts[3]; + + // 从请求中获取原始数据 + String requestBody = request.content().toString(CharsetUtil.UTF_8); + + // 尝试解析请求数据为 JSON 对象 + JSONObject jsonData; + try { + jsonData = JSONUtil.parseObj(requestBody); + } catch (Exception e) { + // 数据不是合法的 JSON 格式,返回 400 错误 + JSONObject res = createResponseJson( + 400, + new JSONObject(), + null, + "请求数据不是合法的 JSON 格式: " + e.getMessage(), + "thing.event.property.post", + "1.0" + ); + writeResponse(ctx, HttpResponseStatus.BAD_REQUEST, res.toString()); + return; + } + + // 获取请求中的 id 字段,若不存在则为 null + String id = jsonData.getStr("id", null); + + try { + // 调用主程序的接口保存数据 + deviceDataApi.saveDeviceData(productKey, deviceName, jsonData.toString()); + + // 构造成功响应内容 + JSONObject successRes = createResponseJson( + 200, + new JSONObject(), + id, + "success", + "thing.event.property.post", + "1.0" + ); + writeResponse(ctx, HttpResponseStatus.OK, successRes.toString()); + } catch (Exception e) { + // 保存数据过程中出现异常,返回 500 错误 + JSONObject errorRes = createResponseJson( + 500, + new JSONObject(), + id, + "The format of result is error!", + "thing.event.property.post", + "1.0" + ); + writeResponse(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR, errorRes.toString()); + } + } + + /** + * 创建标准化的响应 JSON 对象 + * + * @param code 响应状态码(业务层面的) + * @param data 返回的数据对象(JSON) + * @param id 请求的 id(可选) + * @param message 返回的提示信息 + * @param method 返回的 method 标识 + * @param version 返回的版本号 + * @return 构造好的 JSON 对象 + */ + private JSONObject createResponseJson(int code, JSONObject data, String id, String message, String method, String version) { + JSONObject res = new JSONObject(); + res.set("code", code); + res.set("data", data != null ? data : new JSONObject()); // 确保 data 不为 null + res.set("id", id); + res.set("message", message); + res.set("method", method); + res.set("version", version); + return res; + } + + /** + * 向客户端返回 HTTP 响应的辅助方法。 + * + * @param ctx 通道上下文 + * @param status HTTP 响应状态码(网络层面的) + * @param content 响应内容(JSON 字符串或其他文本) + */ + private void writeResponse(ChannelHandlerContext ctx, HttpResponseStatus status, String content) { + FullHttpResponse response = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, + status, + Unpooled.copiedBuffer(content, CharsetUtil.UTF_8) + ); + + // 设置响应头为 JSON 类型和正确的编码 + response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=UTF-8"); + response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); + + // 发送响应并在发送完成后关闭连接 + ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java index 32926be452..68311300e7 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java @@ -1,79 +1,81 @@ package cn.iocoder.yudao.module.iot.plugin; -import cn.iocoder.yudao.module.iot.api.Greeting; -import com.sun.net.httpserver.HttpServer; +import cn.iocoder.yudao.module.iot.api.DeviceDataApi; +import cn.iocoder.yudao.module.iot.api.ServiceRegistry; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.codec.http.*; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang.StringUtils; -import org.pf4j.Extension; -import org.pf4j.Plugin; import org.pf4j.PluginWrapper; -import org.pf4j.RuntimeMode; +import org.pf4j.Plugin; -import java.io.IOException; -import java.io.OutputStream; -import java.net.InetSocketAddress; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; -/** - * 一个启动 HTTP 服务器的简单插件。 - */ @Slf4j public class HttpPlugin extends Plugin { - private HttpServer server; + private static final int PORT = 8092; + private final ExecutorService executorService; + private DeviceDataApi deviceDataApi; // 用于保存设备数据的 API public HttpPlugin(PluginWrapper wrapper) { super(wrapper); + this.executorService = Executors.newSingleThreadExecutor(); // 创建单线程池 } @Override public void start() { log.info("HttpPlugin.start()"); - // for testing the development mode - if (RuntimeMode.DEVELOPMENT.equals(wrapper.getRuntimeMode())) { - log.info("HttpPlugin in DEVELOPMENT mode"); + + // 从 ServiceRegistry 中获取主程序暴露的 DeviceDataApi 接口实例 + deviceDataApi = ServiceRegistry.getService(DeviceDataApi.class); + if (deviceDataApi == null) { + log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!"); + return; } - startHttpServer(); + + // 异步启动 Netty 服务器 + executorService.submit(this::startHttpServer); } @Override public void stop() { log.info("HttpPlugin.stop()"); - stopHttpServer(); + executorService.shutdownNow(); // 停止线程池 } + // 启动 HTTP 服务 private void startHttpServer() { + EventLoopGroup bossGroup = new NioEventLoopGroup(1); + EventLoopGroup workerGroup = new NioEventLoopGroup(); + try { - server = HttpServer.create(new InetSocketAddress(9081), 0); - server.createContext("/", exchange -> { - String response = "Welcome to PF4J HTTP Server"; - exchange.sendResponseHeaders(200, response.getBytes().length); - OutputStream os = exchange.getResponseBody(); - os.write(response.getBytes()); - os.close(); - }); - server.setExecutor(null); - server.start(); - log.info("HTTP server started on port 9081"); - } catch (IOException e) { - log.error("Error starting HTTP server", e); + ServerBootstrap bootstrap = new ServerBootstrap(); + bootstrap.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .childHandler(new ChannelInitializer() { + @Override + protected void initChannel(Channel channel) { + channel.pipeline().addLast(new HttpServerCodec()); + channel.pipeline().addLast(new HttpObjectAggregator(65536)); + // 将从 ServiceRegistry 获取的 deviceDataApi 传入处理器 + channel.pipeline().addLast(new HttpHandler(deviceDataApi)); + } + }); + + // 绑定端口并启动服务器 + ChannelFuture future = bootstrap.bind(PORT).sync(); + log.info("HTTP 服务器启动成功,端口为: {}", PORT); + future.channel().closeFuture().sync(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + log.error("HTTP 服务启动中断", e); + } finally { + bossGroup.shutdownGracefully(); + workerGroup.shutdownGracefully(); } } - - private void stopHttpServer() { - if (server != null) { - server.stop(0); - log.info("HTTP server stopped"); - } - } - - @Extension - public static class WelcomeGreeting implements Greeting { - - @Override - public String getGreeting() { - return "Welcome to PF4J"; - } - - } - -} \ No newline at end of file +} From e998b0c7ebe0123972f9a3aaaf43aacdba0ff75d Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 21 Dec 2024 16:28:25 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E8=AF=84=E5=AE=A1=20plugin=20?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-module-iot/yudao-module-iot-api/pom.xml | 1 + .../yudao/module/iot/api/ServiceRegistry.java | 2 ++ .../iot/api/{ => device}/DeviceDataApi.java | 2 +- yudao-module-iot/yudao-module-iot-biz/pom.xml | 1 + .../iot/api/device/DeviceDataApiImpl.java | 5 ++- .../yudao/module/iot/api/package-info.java | 5 +++ .../plugin/ServiceRegistryConfiguration.java | 7 ++-- .../service/device/IotDeviceDataService.java | 2 +- .../PluginInstanceServiceImpl.java | 1 + .../yudao/module/iot/plugin/HttpHandler.java | 33 ++++++------------- .../yudao/module/iot/plugin/HttpPlugin.java | 20 +++++++---- 11 files changed, 42 insertions(+), 37 deletions(-) rename yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/{ => device}/DeviceDataApi.java (85%) diff --git a/yudao-module-iot/yudao-module-iot-api/pom.xml b/yudao-module-iot/yudao-module-iot-api/pom.xml index a370944457..d2f83b785e 100644 --- a/yudao-module-iot/yudao-module-iot-api/pom.xml +++ b/yudao-module-iot/yudao-module-iot-api/pom.xml @@ -22,6 +22,7 @@ yudao-common + org.pf4j pf4j-spring diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java index 5c55bd89cb..5603ad8d72 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java @@ -7,6 +7,7 @@ import java.util.Map; * 服务注册表 - 插架模块使用,无法使用 Spring 注入 */ public class ServiceRegistry { + private static final Map, Object> services = new HashMap<>(); /** @@ -31,4 +32,5 @@ public class ServiceRegistry { public static T getService(Class serviceClass) { return (T) services.get(serviceClass); } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/DeviceDataApi.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java similarity index 85% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/DeviceDataApi.java rename to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java index 2f3ef60477..cb747f5053 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/DeviceDataApi.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.api; +package cn.iocoder.yudao.module.iot.api.device; /** * 设备数据 API diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index c0810a183d..19b50ec215 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -81,6 +81,7 @@ org.pf4j pf4j-spring + org.slf4j diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java index 59ae850a1e..d62c20cb54 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.iot.api.device; -import cn.iocoder.yudao.module.iot.api.DeviceDataApi; import cn.iocoder.yudao.module.iot.service.device.IotDeviceDataService; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -15,11 +14,11 @@ import javax.annotation.Resource; public class DeviceDataApiImpl implements DeviceDataApi { @Resource - private IotDeviceDataService iotDeviceDataService; + private IotDeviceDataService deviceDataService; @Override public void saveDeviceData(String productKey, String deviceName, String message) { - iotDeviceDataService.saveDeviceData(productKey, deviceName, message); + deviceDataService.saveDeviceData(productKey, deviceName, message); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java index c0f3d748a1..07852180d4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java @@ -1 +1,6 @@ +/** + * 占位 + * + * TODO 芋艿:后续删除 + */ package cn.iocoder.yudao.module.iot.api; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java index 385c8aee56..3450b67fb9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.framework.plugin; -import cn.iocoder.yudao.module.iot.api.DeviceDataApi; +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import cn.iocoder.yudao.module.iot.api.ServiceRegistry; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; @@ -26,9 +26,10 @@ public class ServiceRegistryConfiguration { /** * 定义一个标记用的 Bean,用于表示 ServiceRegistry 已初始化完成 */ - @Bean("serviceRegistryInitializedMarker") + @Bean("serviceRegistryInitializedMarker") // TODO @haohao:1)这个名字,可以搞个 public static final 常量;2)是不是 conditionBefore 啥 public Object serviceRegistryInitializedMarker() { - // 返回任意对象即可,这里返回null都可以,但最好返回个实际对象 + // 返回任意对象即可,这里返回 null 都可以,但最好返回个实际对象 return new Object(); } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java index 1dd4ad666e..1c246e2c70 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java @@ -21,7 +21,7 @@ public interface IotDeviceDataService { * @param productKey 产品 key * @param deviceName 设备名称 * @param message 消息 - *

JSON 格式,参见 ... + *

参见 JSON 格式 */ void saveDeviceData(String productKey, String deviceName, String message); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImpl.java index 405efe1636..afb05ef2f8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImpl.java @@ -13,6 +13,7 @@ import org.springframework.validation.annotation.Validated; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PLUGIN_INSTANCE_NOT_EXISTS; +// TODO @haohao:可以搞个 plugin 包,然后把 plugininfo、plugininstance /** * IoT 插件实例 Service 实现类 * diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java index c145182eda..6d0908683b 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.plugin; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; -import cn.iocoder.yudao.module.iot.api.DeviceDataApi; +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; @@ -12,12 +12,9 @@ import io.netty.util.CharsetUtil; /** * 基于 Netty 的 HTTP 处理器,用于接收设备上报的数据并调用主程序的 DeviceDataApi 接口进行处理。 - *

- * 请求格式: - * POST /sys/{productKey}/{deviceName}/thing/event/property/post - * 请求体为 JSON 格式数据。 - *

- * 返回结果为 JSON 格式,包含统一的 code、data、id、message、method、version 字段。 + * + * 1. 请求格式:JSON 格式,地址为 POST /sys/{productKey}/{deviceName}/thing/event/property/post + * 2. 返回结果:JSON 格式,包含统一的 code、data、id、message、method、version 字段 */ public class HttpHandler extends SimpleChannelInboundHandler { @@ -29,10 +26,9 @@ public class HttpHandler extends SimpleChannelInboundHandler { @Override protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) { - String uri = request.uri(); - // 期望的路径格式: /sys/{productKey}/{deviceName}/thing/event/property/post // 使用 "/" 拆分路径 + String uri = request.uri(); String[] parts = uri.split("/"); /* @@ -52,25 +48,19 @@ public class HttpHandler extends SimpleChannelInboundHandler { && "event".equals(parts[5]) && "property".equals(parts[6]) && "post".equals(parts[7]); - if (!isCorrectPath) { - // 如果路径不匹配,返回 404 错误 writeResponse(ctx, HttpResponseStatus.NOT_FOUND, "Not Found"); return; } - String productKey = parts[2]; String deviceName = parts[3]; - // 从请求中获取原始数据 + // 从请求中获取原始数据,尝试解析请求数据为 JSON 对象 String requestBody = request.content().toString(CharsetUtil.UTF_8); - - // 尝试解析请求数据为 JSON 对象 JSONObject jsonData; try { jsonData = JSONUtil.parseObj(requestBody); } catch (Exception e) { - // 数据不是合法的 JSON 格式,返回 400 错误 JSONObject res = createResponseJson( 400, new JSONObject(), @@ -82,8 +72,6 @@ public class HttpHandler extends SimpleChannelInboundHandler { writeResponse(ctx, HttpResponseStatus.BAD_REQUEST, res.toString()); return; } - - // 获取请求中的 id 字段,若不存在则为 null String id = jsonData.getStr("id", null); try { @@ -101,7 +89,6 @@ public class HttpHandler extends SimpleChannelInboundHandler { ); writeResponse(ctx, HttpResponseStatus.OK, successRes.toString()); } catch (Exception e) { - // 保存数据过程中出现异常,返回 500 错误 JSONObject errorRes = createResponseJson( 500, new JSONObject(), @@ -128,7 +115,7 @@ public class HttpHandler extends SimpleChannelInboundHandler { private JSONObject createResponseJson(int code, JSONObject data, String id, String message, String method, String version) { JSONObject res = new JSONObject(); res.set("code", code); - res.set("data", data != null ? data : new JSONObject()); // 确保 data 不为 null + res.set("data", data != null ? data : new JSONObject()); res.set("id", id); res.set("message", message); res.set("method", method); @@ -137,24 +124,24 @@ public class HttpHandler extends SimpleChannelInboundHandler { } /** - * 向客户端返回 HTTP 响应的辅助方法。 + * 向客户端返回 HTTP 响应的辅助方法 * * @param ctx 通道上下文 * @param status HTTP 响应状态码(网络层面的) * @param content 响应内容(JSON 字符串或其他文本) */ private void writeResponse(ChannelHandlerContext ctx, HttpResponseStatus status, String content) { + // 设置响应头为 JSON 类型和正确的编码 FullHttpResponse response = new DefaultFullHttpResponse( HttpVersion.HTTP_1_1, status, Unpooled.copiedBuffer(content, CharsetUtil.UTF_8) ); - - // 设置响应头为 JSON 类型和正确的编码 response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=UTF-8"); response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); // 发送响应并在发送完成后关闭连接 ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java index 68311300e7..70da0131ce 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.plugin; -import cn.iocoder.yudao.module.iot.api.DeviceDataApi; +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import cn.iocoder.yudao.module.iot.api.ServiceRegistry; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; @@ -18,12 +18,14 @@ import java.util.concurrent.Executors; public class HttpPlugin extends Plugin { private static final int PORT = 8092; + private final ExecutorService executorService; - private DeviceDataApi deviceDataApi; // 用于保存设备数据的 API + private DeviceDataApi deviceDataApi; public HttpPlugin(PluginWrapper wrapper) { super(wrapper); - this.executorService = Executors.newSingleThreadExecutor(); // 创建单线程池 + // 创建单线程池 + this.executorService = Executors.newSingleThreadExecutor(); } @Override @@ -44,10 +46,13 @@ public class HttpPlugin extends Plugin { @Override public void stop() { log.info("HttpPlugin.stop()"); - executorService.shutdownNow(); // 停止线程池 + // 停止线程池 + executorService.shutdownNow(); } - // 启动 HTTP 服务 + /** + * 启动 HTTP 服务 + */ private void startHttpServer() { EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); @@ -56,7 +61,8 @@ public class HttpPlugin extends Plugin { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) - .childHandler(new ChannelInitializer() { + .childHandler(new ChannelInitializer<>() { + @Override protected void initChannel(Channel channel) { channel.pipeline().addLast(new HttpServerCodec()); @@ -64,6 +70,7 @@ public class HttpPlugin extends Plugin { // 将从 ServiceRegistry 获取的 deviceDataApi 传入处理器 channel.pipeline().addLast(new HttpHandler(deviceDataApi)); } + }); // 绑定端口并启动服务器 @@ -78,4 +85,5 @@ public class HttpPlugin extends Plugin { workerGroup.shutdownGracefully(); } } + } From e01d03eefb3fbe5d50fb67c44384bb7f6c88162c Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 21 Dec 2024 16:33:50 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E7=89=A9=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 1 - .../simulatesend/SimulateSendConsumer.java | 4 ++- .../module/iot/util/IotTdDatabaseUtils.java | 25 +++++++------------ .../tdengine/TdThinkModelMessageMapper.xml | 1 - 4 files changed, 12 insertions(+), 19 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index a763924b57..4539f12591 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -14,7 +14,6 @@ public interface ErrorCodeConstants { ErrorCode PRODUCT_KEY_EXISTS = new ErrorCode(1_050_001_001, "产品标识已经存在"); ErrorCode PRODUCT_STATUS_NOT_DELETE = new ErrorCode(1_050_001_002, "产品状是发布状态,不允许删除"); ErrorCode PRODUCT_STATUS_NOT_ALLOW_THING_MODEL = new ErrorCode(1_050_001_003, "产品状是发布状态,不允许操作物模型"); - ErrorCode PRODUCT_DEVICE_NOT_EXISTS = new ErrorCode(1_050_001_004, "产品设备类型不存在"); // ========== 产品物模型 1-050-002-000 ============ ErrorCode THING_MODEL_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在"); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/simulatesend/SimulateSendConsumer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/simulatesend/SimulateSendConsumer.java index dfc911df52..111cf50073 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/simulatesend/SimulateSendConsumer.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/simulatesend/SimulateSendConsumer.java @@ -1,8 +1,10 @@ package cn.iocoder.yudao.module.iot.mq.consumer.simulatesend; /** + * TODO @alwayssuper:记得实现,还有类注释哈 + * * @author alwayssuper - * @date 2024/12/20 8:04 + * @since 2024/12/20 8:04 */ public class SimulateSendConsumer { } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java index e4ecf74657..a409c80692 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java @@ -1,13 +1,9 @@ package cn.iocoder.yudao.module.iot.util; +import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.module.iot.enums.IotConstants; import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_DEVICE_NOT_EXISTS; // TODO @芋艿:可能要思索下,有没更好的处理方式 // TODO @芋艿:怎么改成无状态 @@ -34,20 +30,17 @@ public class IotTdDatabaseUtils { * @return 产品超级表表名 */ public static String getProductSuperTableName(Integer deviceType, String productKey) { - // TODO @alwayssuper:枚举字段,不要 1、2、3;不符合预期,抛出异常 - if (deviceType == null) { - throw exception(PRODUCT_DEVICE_NOT_EXISTS); - } + Assert.notNull(deviceType, "deviceType 不能为空"); if (IotProductDeviceTypeEnum.GATEWAY_SUB.getType().equals(deviceType)) { return String.format(IotConstants.GATEWAY_SUB_STABLE_NAME_FORMAT, productKey).toLowerCase(); - } else if (IotProductDeviceTypeEnum.GATEWAY.getType().equals(deviceType)) { + } + if (IotProductDeviceTypeEnum.GATEWAY.getType().equals(deviceType)) { return String.format(IotConstants.GATEWAY_STABLE_NAME_FORMAT, productKey).toLowerCase(); - } else if (IotProductDeviceTypeEnum.DIRECT.getType().equals(deviceType)){ + } + if (IotProductDeviceTypeEnum.DIRECT.getType().equals(deviceType)){ return String.format(IotConstants.DEVICE_STABLE_NAME_FORMAT, productKey).toLowerCase(); } - else{ - throw exception(PRODUCT_DEVICE_NOT_EXISTS); - } + throw new IllegalArgumentException("deviceType 不正确"); } /** @@ -58,7 +51,6 @@ public class IotTdDatabaseUtils { * */ public static String getThingModelMessageSuperTableName(String productKey) { - // TODO @alwayssuper:是不是应该 + 拼接就好,不用 format return "thing_model_message_" + productKey.toLowerCase(); } @@ -70,7 +62,8 @@ public class IotTdDatabaseUtils { * @return 物模型日志设备表名 */ public static String getThingModelMessageDeviceTableName(String productKey, String deviceName) { - return String.format(IotConstants.THING_MODEL_MESSAGE_TABLE_NAME_FORMAT, productKey.toLowerCase(), deviceName.toLowerCase()); + return String.format(IotConstants.THING_MODEL_MESSAGE_TABLE_NAME_FORMAT, + productKey.toLowerCase(), deviceName.toLowerCase()); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml index 074ae98842..a0cc12712f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml @@ -5,7 +5,6 @@ - CREATE STABLE ${dataBaseName}.${superTableName}( ts TIMESTAMP,