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/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/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..3450b67fb9
--- /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,35 @@
+package cn.iocoder.yudao.module.iot.framework.plugin;
+
+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;
+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") // TODO @haohao:1)这个名字,可以搞个 public static final 常量;2)是不是 conditionBefore 啥
+ 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/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..111cf50073
--- /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,10 @@
+package cn.iocoder.yudao.module.iot.mq.consumer.simulatesend;
+
+/**
+ * TODO @alwayssuper:记得实现,还有类注释哈
+ *
+ * @author alwayssuper
+ * @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/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..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
@@ -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/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-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 568cad5020..ad909c437f 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
@@ -7,19 +7,21 @@ import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO;
-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.dataobject.tdengine.FieldParser;
+import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO;
+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.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;
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
-import cn.iocoder.yudao.module.iot.service.product.IotProductService;
import cn.iocoder.yudao.module.iot.service.thingmodel.IotProductThingModelService;
+import cn.iocoder.yudao.module.iot.service.product.IotProductService;
import cn.iocoder.yudao.module.iot.util.IotTdDatabaseUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
@@ -64,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
@@ -81,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. 获取设备属性并进行物模型校验,过滤非物模型属性
@@ -118,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) {
@@ -227,21 +234,22 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
* @param productKey 产品 Key
* @param deviceName 设备名称
* @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..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,8 +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 org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
+import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum;
// TODO @芋艿:可能要思索下,有没更好的处理方式
// TODO @芋艿:怎么改成无状态
@@ -11,19 +12,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);
}
/**
@@ -34,12 +30,17 @@ public class IotTdDatabaseUtils {
* @return 产品超级表表名
*/
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();
- };
+ Assert.notNull(deviceType, "deviceType 不能为空");
+ if (IotProductDeviceTypeEnum.GATEWAY_SUB.getType().equals(deviceType)) {
+ return String.format(IotConstants.GATEWAY_SUB_STABLE_NAME_FORMAT, productKey).toLowerCase();
+ }
+ if (IotProductDeviceTypeEnum.GATEWAY.getType().equals(deviceType)) {
+ return String.format(IotConstants.GATEWAY_STABLE_NAME_FORMAT, productKey).toLowerCase();
+ }
+ if (IotProductDeviceTypeEnum.DIRECT.getType().equals(deviceType)){
+ return String.format(IotConstants.DEVICE_STABLE_NAME_FORMAT, productKey).toLowerCase();
+ }
+ throw new IllegalArgumentException("deviceType 不正确");
}
/**
@@ -50,8 +51,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,8 +61,9 @@ public class IotTdDatabaseUtils {
* @param deviceName 设备名称
* @return 物模型日志设备表名
*/
- public static String getThinkModelMessageDeviceTableName(String productKey, String deviceName) {
- return String.format(IotConstants.THING_MODEL_MESSAGE_TABLE_NAME_FORMAT, productKey.toLowerCase(), deviceName.toLowerCase());
+ 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..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
@@ -2,10 +2,9 @@
-
+
-
CREATE STABLE ${dataBaseName}.${superTableName}(
ts TIMESTAMP,
@@ -14,7 +13,7 @@
method VARCHAR(255),
params VARCHAR(2048)
)TAGS (
- deviceKey VARCHAR(255)
+ device_key VARCHAR(255)
)
@@ -28,7 +27,7 @@
method ,
params
)TAGS(
- #{deviceKey}
+ #{device_key}
)
\ No newline at end of file
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/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..6d0908683b
--- /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,147 @@
+package cn.iocoder.yudao.module.iot.plugin;
+
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import cn.iocoder.yudao.module.iot.api.device.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 接口进行处理。
+ *
+ * 1. 请求格式:JSON 格式,地址为 POST /sys/{productKey}/{deviceName}/thing/event/property/post
+ * 2. 返回结果: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) {
+ // 期望的路径格式: /sys/{productKey}/{deviceName}/thing/event/property/post
+ // 使用 "/" 拆分路径
+ String uri = request.uri();
+ 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) {
+ 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);
+ JSONObject jsonData;
+ try {
+ jsonData = JSONUtil.parseObj(requestBody);
+ } catch (Exception e) {
+ JSONObject res = createResponseJson(
+ 400,
+ new JSONObject(),
+ null,
+ "请求数据不是合法的 JSON 格式: " + e.getMessage(),
+ "thing.event.property.post",
+ "1.0"
+ );
+ writeResponse(ctx, HttpResponseStatus.BAD_REQUEST, res.toString());
+ return;
+ }
+ 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) {
+ 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());
+ 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) {
+ // 设置响应头为 JSON 类型和正确的编码
+ FullHttpResponse response = new DefaultFullHttpResponse(
+ HttpVersion.HTTP_1_1,
+ status,
+ Unpooled.copiedBuffer(content, CharsetUtil.UTF_8)
+ );
+ 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..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,79 +1,89 @@
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.device.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;
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
+}