Commit a9733b4d2af6caf65445ce2ce4aac3295c106618
1 parent
b6c7937a
【代码评审】IoT:整体实现
Showing
18 changed files
with
83 additions
and
84 deletions
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonAutoConfiguration.java
| @@ -43,8 +43,9 @@ public class IotPluginCommonAutoConfiguration { | @@ -43,8 +43,9 @@ public class IotPluginCommonAutoConfiguration { | ||
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | @Bean(initMethod = "init", destroyMethod = "stop") | 45 | @Bean(initMethod = "init", destroyMethod = "stop") |
| 46 | - public IotPluginInstanceHeartbeatJob pluginInstanceHeartbeatJob( | ||
| 47 | - IotDeviceUpstreamApi deviceDataApi, IotDeviceDownstreamServer deviceDownstreamServer, IotPluginCommonProperties commonProperties) { | 46 | + public IotPluginInstanceHeartbeatJob pluginInstanceHeartbeatJob(IotDeviceUpstreamApi deviceDataApi, |
| 47 | + IotDeviceDownstreamServer deviceDownstreamServer, | ||
| 48 | + IotPluginCommonProperties commonProperties) { | ||
| 48 | return new IotPluginInstanceHeartbeatJob(deviceDataApi, deviceDownstreamServer, commonProperties); | 49 | return new IotPluginInstanceHeartbeatJob(deviceDataApi, deviceDownstreamServer, commonProperties); |
| 49 | } | 50 | } |
| 50 | 51 |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceConfigSetVertxHandler.java
| @@ -25,6 +25,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC | @@ -25,6 +25,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC | ||
| 25 | @RequiredArgsConstructor | 25 | @RequiredArgsConstructor |
| 26 | public class IotDeviceConfigSetVertxHandler implements Handler<RoutingContext> { | 26 | public class IotDeviceConfigSetVertxHandler implements Handler<RoutingContext> { |
| 27 | 27 | ||
| 28 | + // TODO @haohao:是不是可以把 PATH、Method 所有的,抽到一个枚举类里?因为 topic、path、method 相当于不同的几个表达? | ||
| 28 | public static final String PATH = "/sys/:productKey/:deviceName/thing/service/config/set"; | 29 | public static final String PATH = "/sys/:productKey/:deviceName/thing/service/config/set"; |
| 29 | public static final String METHOD = "thing.service.config.set"; | 30 | public static final String METHOD = "thing.service.config.set"; |
| 30 | 31 | ||
| @@ -57,12 +58,9 @@ public class IotDeviceConfigSetVertxHandler implements Handler<RoutingContext> { | @@ -57,12 +58,9 @@ public class IotDeviceConfigSetVertxHandler implements Handler<RoutingContext> { | ||
| 57 | CommonResult<Boolean> result = deviceDownstreamHandler.setDeviceConfig(reqDTO); | 58 | CommonResult<Boolean> result = deviceDownstreamHandler.setDeviceConfig(reqDTO); |
| 58 | 59 | ||
| 59 | // 3. 响应结果 | 60 | // 3. 响应结果 |
| 60 | - IotStandardResponse response; | ||
| 61 | - if (result.isSuccess()) { | ||
| 62 | - response = IotStandardResponse.success(reqDTO.getRequestId(), METHOD, result.getData()); | ||
| 63 | - } else { | ||
| 64 | - response = IotStandardResponse.error(reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); | ||
| 65 | - } | 61 | + IotStandardResponse response = result.isSuccess() ? |
| 62 | + IotStandardResponse.success(reqDTO.getRequestId(), METHOD, result.getData()) | ||
| 63 | + : IotStandardResponse.error(reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); | ||
| 66 | IotPluginCommonUtils.writeJsonResponse(routingContext, response); | 64 | IotPluginCommonUtils.writeJsonResponse(routingContext, response); |
| 67 | } catch (Exception e) { | 65 | } catch (Exception e) { |
| 68 | log.error("[handle][请求参数({}) 配置设置异常]", reqDTO, e); | 66 | log.error("[handle][请求参数({}) 配置设置异常]", reqDTO, e); |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceOtaUpgradeVertxHandler.java
| @@ -62,15 +62,14 @@ public class IotDeviceOtaUpgradeVertxHandler implements Handler<RoutingContext> | @@ -62,15 +62,14 @@ public class IotDeviceOtaUpgradeVertxHandler implements Handler<RoutingContext> | ||
| 62 | CommonResult<Boolean> result = deviceDownstreamHandler.upgradeDeviceOta(reqDTO); | 62 | CommonResult<Boolean> result = deviceDownstreamHandler.upgradeDeviceOta(reqDTO); |
| 63 | 63 | ||
| 64 | // 3. 响应结果 | 64 | // 3. 响应结果 |
| 65 | - IotStandardResponse response; | ||
| 66 | - if (result.isSuccess()) { | ||
| 67 | - response = IotStandardResponse.success(reqDTO.getRequestId(), METHOD, result.getData()); | ||
| 68 | - } else { | ||
| 69 | - response = IotStandardResponse.error(reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); | ||
| 70 | - } | 65 | + // TODO @haohao:可以考虑 IotStandardResponse.of(requestId, method, CommonResult) |
| 66 | + IotStandardResponse response = result.isSuccess() ? | ||
| 67 | + IotStandardResponse.success(reqDTO.getRequestId(), METHOD, result.getData()) | ||
| 68 | + :IotStandardResponse.error(reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); | ||
| 71 | IotPluginCommonUtils.writeJsonResponse(routingContext, response); | 69 | IotPluginCommonUtils.writeJsonResponse(routingContext, response); |
| 72 | } catch (Exception e) { | 70 | } catch (Exception e) { |
| 73 | log.error("[handle][请求参数({}) OTA 升级异常]", reqDTO, e); | 71 | log.error("[handle][请求参数({}) OTA 升级异常]", reqDTO, e); |
| 72 | + // TODO @haohao:可以考虑 IotStandardResponse.of(requestId, method, ErrorCode) | ||
| 74 | IotStandardResponse errorResponse = IotStandardResponse.error( | 73 | IotStandardResponse errorResponse = IotStandardResponse.error( |
| 75 | reqDTO.getRequestId(), METHOD, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); | 74 | reqDTO.getRequestId(), METHOD, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); |
| 76 | IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); | 75 | IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/pojo/IotStandardResponse.java
| 1 | package cn.iocoder.yudao.module.iot.plugin.common.pojo; | 1 | package cn.iocoder.yudao.module.iot.plugin.common.pojo; |
| 2 | 2 | ||
| 3 | import lombok.Data; | 3 | import lombok.Data; |
| 4 | -import lombok.experimental.Accessors; | ||
| 5 | 4 | ||
| 6 | // TODO @芋艿:1)后续考虑,要不要叫 IoT 网关之类的 Response;2)包名 pojo | 5 | // TODO @芋艿:1)后续考虑,要不要叫 IoT 网关之类的 Response;2)包名 pojo |
| 7 | /** | 6 | /** |
| @@ -12,7 +11,6 @@ import lombok.experimental.Accessors; | @@ -12,7 +11,6 @@ import lombok.experimental.Accessors; | ||
| 12 | * @author haohao | 11 | * @author haohao |
| 13 | */ | 12 | */ |
| 14 | @Data | 13 | @Data |
| 15 | -@Accessors(chain = true) | ||
| 16 | public class IotStandardResponse { | 14 | public class IotStandardResponse { |
| 17 | 15 | ||
| 18 | /** | 16 | /** |
| @@ -92,4 +90,5 @@ public class IotStandardResponse { | @@ -92,4 +90,5 @@ public class IotStandardResponse { | ||
| 92 | .setMethod(method) | 90 | .setMethod(method) |
| 93 | .setVersion("1.0"); | 91 | .setVersion("1.0"); |
| 94 | } | 92 | } |
| 93 | + | ||
| 95 | } | 94 | } |
| 96 | \ No newline at end of file | 95 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java
| @@ -72,4 +72,5 @@ public class IotPluginCommonUtils { | @@ -72,4 +72,5 @@ public class IotPluginCommonUtils { | ||
| 72 | .putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) | 72 | .putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) |
| 73 | .end(JsonUtils.toJsonString(response)); | 73 | .end(JsonUtils.toJsonString(response)); |
| 74 | } | 74 | } |
| 75 | + | ||
| 75 | } | 76 | } |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/pom.xml
| @@ -15,6 +15,7 @@ | @@ -15,6 +15,7 @@ | ||
| 15 | <version>1.0.0</version> | 15 | <version>1.0.0</version> |
| 16 | 16 | ||
| 17 | <name>${project.artifactId}</name> | 17 | <name>${project.artifactId}</name> |
| 18 | + <!-- TODO @芋艿:待整理 --> | ||
| 18 | <description> | 19 | <description> |
| 19 | 物联网 插件模块 - emqx 插件 | 20 | 物联网 插件模块 - emqx 插件 |
| 20 | </description> | 21 | </description> |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxAutoConfiguration.java
| @@ -14,7 +14,7 @@ import org.springframework.context.annotation.Bean; | @@ -14,7 +14,7 @@ import org.springframework.context.annotation.Bean; | ||
| 14 | import org.springframework.context.annotation.Configuration; | 14 | import org.springframework.context.annotation.Configuration; |
| 15 | 15 | ||
| 16 | /** | 16 | /** |
| 17 | - * IoT 插件 Emqx 的专用自动配置类 | 17 | + * IoT 插件 EMQX 的专用自动配置类 |
| 18 | * | 18 | * |
| 19 | * @author haohao | 19 | * @author haohao |
| 20 | */ | 20 | */ |
| @@ -34,7 +34,7 @@ public class IotPluginEmqxAutoConfiguration { | @@ -34,7 +34,7 @@ public class IotPluginEmqxAutoConfiguration { | ||
| 34 | .setClientId("yudao-iot-downstream-" + IdUtil.fastSimpleUUID()) | 34 | .setClientId("yudao-iot-downstream-" + IdUtil.fastSimpleUUID()) |
| 35 | .setUsername(emqxProperties.getMqttUsername()) | 35 | .setUsername(emqxProperties.getMqttUsername()) |
| 36 | .setPassword(emqxProperties.getMqttPassword()) | 36 | .setPassword(emqxProperties.getMqttPassword()) |
| 37 | - .setSsl(emqxProperties.isMqttSsl()); | 37 | + .setSsl(emqxProperties.getMqttSsl()); |
| 38 | return MqttClient.create(vertx, options); | 38 | return MqttClient.create(vertx, options); |
| 39 | } | 39 | } |
| 40 | 40 |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxProperties.java
| @@ -14,6 +14,8 @@ import org.springframework.validation.annotation.Validated; | @@ -14,6 +14,8 @@ import org.springframework.validation.annotation.Validated; | ||
| 14 | @Data | 14 | @Data |
| 15 | public class IotPluginEmqxProperties { | 15 | public class IotPluginEmqxProperties { |
| 16 | 16 | ||
| 17 | + // TODO @haohao:参数校验,加下,啊哈 | ||
| 18 | + | ||
| 17 | /** | 19 | /** |
| 18 | * 服务主机 | 20 | * 服务主机 |
| 19 | */ | 21 | */ |
| @@ -21,12 +23,11 @@ public class IotPluginEmqxProperties { | @@ -21,12 +23,11 @@ public class IotPluginEmqxProperties { | ||
| 21 | /** | 23 | /** |
| 22 | * 服务端口 | 24 | * 服务端口 |
| 23 | */ | 25 | */ |
| 24 | - private int mqttPort; | 26 | + private Integer mqttPort; |
| 25 | /** | 27 | /** |
| 26 | * 服务用户名 | 28 | * 服务用户名 |
| 27 | */ | 29 | */ |
| 28 | private String mqttUsername; | 30 | private String mqttUsername; |
| 29 | - | ||
| 30 | /** | 31 | /** |
| 31 | * 服务密码 | 32 | * 服务密码 |
| 32 | */ | 33 | */ |
| @@ -34,7 +35,7 @@ public class IotPluginEmqxProperties { | @@ -34,7 +35,7 @@ public class IotPluginEmqxProperties { | ||
| 34 | /** | 35 | /** |
| 35 | * 是否启用 SSL | 36 | * 是否启用 SSL |
| 36 | */ | 37 | */ |
| 37 | - private boolean mqttSsl; | 38 | + private Boolean mqttSsl; |
| 38 | 39 | ||
| 39 | /** | 40 | /** |
| 40 | * 订阅的主题列表 | 41 | * 订阅的主题列表 |
| @@ -44,6 +45,6 @@ public class IotPluginEmqxProperties { | @@ -44,6 +45,6 @@ public class IotPluginEmqxProperties { | ||
| 44 | /** | 45 | /** |
| 45 | * 认证端口 | 46 | * 认证端口 |
| 46 | */ | 47 | */ |
| 47 | - private int authPort; | 48 | + private Integer authPort; |
| 48 | 49 | ||
| 49 | } | 50 | } |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/downstream/IotDeviceDownstreamHandlerImpl.java
| @@ -25,6 +25,7 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle | @@ -25,6 +25,7 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle | ||
| 25 | 25 | ||
| 26 | private static final String SYS_TOPIC_PREFIX = "/sys/"; | 26 | private static final String SYS_TOPIC_PREFIX = "/sys/"; |
| 27 | 27 | ||
| 28 | + // TODO @haohao:是不是可以类似 IotDeviceConfigSetVertxHandler 的建议,抽到统一的枚举类 | ||
| 28 | // TODO @haohao:讨论,感觉 mqtt 和 http,可以做个相对统一的格式哈。;回复 都使用 Alink 格式,方便后续扩展。 | 29 | // TODO @haohao:讨论,感觉 mqtt 和 http,可以做个相对统一的格式哈。;回复 都使用 Alink 格式,方便后续扩展。 |
| 29 | // 设备服务调用 标准 JSON | 30 | // 设备服务调用 标准 JSON |
| 30 | // 请求Topic:/sys/${productKey}/${deviceName}/thing/service/${tsl.service.identifier} | 31 | // 请求Topic:/sys/${productKey}/${deviceName}/thing/service/${tsl.service.identifier} |
| @@ -63,7 +64,6 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle | @@ -63,7 +64,6 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle | ||
| 63 | // 构建请求消息 | 64 | // 构建请求消息 |
| 64 | String requestId = reqDTO.getRequestId() != null ? reqDTO.getRequestId() : generateRequestId(); | 65 | String requestId = reqDTO.getRequestId() != null ? reqDTO.getRequestId() : generateRequestId(); |
| 65 | JSONObject request = buildServiceRequest(requestId, reqDTO.getIdentifier(), reqDTO.getParams()); | 66 | JSONObject request = buildServiceRequest(requestId, reqDTO.getIdentifier(), reqDTO.getParams()); |
| 66 | - | ||
| 67 | // 发送消息 | 67 | // 发送消息 |
| 68 | publishMessage(topic, request); | 68 | publishMessage(topic, request); |
| 69 | 69 | ||
| @@ -82,9 +82,8 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle | @@ -82,9 +82,8 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle | ||
| 82 | 82 | ||
| 83 | @Override | 83 | @Override |
| 84 | public CommonResult<Boolean> setDeviceProperty(IotDevicePropertySetReqDTO reqDTO) { | 84 | public CommonResult<Boolean> setDeviceProperty(IotDevicePropertySetReqDTO reqDTO) { |
| 85 | - log.info("[setProperty][开始设置设备属性][reqDTO: {}]", JSONUtil.toJsonStr(reqDTO)); | ||
| 86 | - | ||
| 87 | // 验证参数 | 85 | // 验证参数 |
| 86 | + log.info("[setProperty][开始设置设备属性][reqDTO: {}]", JSONUtil.toJsonStr(reqDTO)); | ||
| 88 | if (reqDTO.getProductKey() == null || reqDTO.getDeviceName() == null) { | 87 | if (reqDTO.getProductKey() == null || reqDTO.getDeviceName() == null) { |
| 89 | log.error("[setProperty][参数不完整][reqDTO: {}]", JSONUtil.toJsonStr(reqDTO)); | 88 | log.error("[setProperty][参数不完整][reqDTO: {}]", JSONUtil.toJsonStr(reqDTO)); |
| 90 | return CommonResult.error(MQTT_TOPIC_ILLEGAL.getCode(), MQTT_TOPIC_ILLEGAL.getMsg()); | 89 | return CommonResult.error(MQTT_TOPIC_ILLEGAL.getCode(), MQTT_TOPIC_ILLEGAL.getMsg()); |
| @@ -96,7 +95,6 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle | @@ -96,7 +95,6 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle | ||
| 96 | // 构建请求消息 | 95 | // 构建请求消息 |
| 97 | String requestId = reqDTO.getRequestId() != null ? reqDTO.getRequestId() : generateRequestId(); | 96 | String requestId = reqDTO.getRequestId() != null ? reqDTO.getRequestId() : generateRequestId(); |
| 98 | JSONObject request = buildPropertySetRequest(requestId, reqDTO.getProperties()); | 97 | JSONObject request = buildPropertySetRequest(requestId, reqDTO.getProperties()); |
| 99 | - | ||
| 100 | // 发送消息 | 98 | // 发送消息 |
| 101 | publishMessage(topic, request); | 99 | publishMessage(topic, request); |
| 102 | 100 | ||
| @@ -132,6 +130,7 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle | @@ -132,6 +130,7 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle | ||
| 132 | return SYS_TOPIC_PREFIX + productKey + "/" + deviceName + PROPERTY_SET_TOPIC; | 130 | return SYS_TOPIC_PREFIX + productKey + "/" + deviceName + PROPERTY_SET_TOPIC; |
| 133 | } | 131 | } |
| 134 | 132 | ||
| 133 | + // TODO @haohao:这个,后面搞个对象,会不会好点哈? | ||
| 135 | /** | 134 | /** |
| 136 | * 构建服务调用请求 | 135 | * 构建服务调用请求 |
| 137 | */ | 136 | */ |
| @@ -168,7 +167,7 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle | @@ -168,7 +167,7 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle | ||
| 168 | } | 167 | } |
| 169 | 168 | ||
| 170 | /** | 169 | /** |
| 171 | - * 生成请求ID | 170 | + * 生成请求 ID |
| 172 | */ | 171 | */ |
| 173 | private String generateRequestId() { | 172 | private String generateRequestId() { |
| 174 | return IdUtil.fastSimpleUUID(); | 173 | return IdUtil.fastSimpleUUID(); |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java
| @@ -37,10 +37,6 @@ public class IotDeviceUpstreamServer { | @@ -37,10 +37,6 @@ public class IotDeviceUpstreamServer { | ||
| 37 | */ | 37 | */ |
| 38 | private static final int CONNECTION_TIMEOUT_MS = 10000; | 38 | private static final int CONNECTION_TIMEOUT_MS = 10000; |
| 39 | /** | 39 | /** |
| 40 | - * 主题分隔符 | ||
| 41 | - */ | ||
| 42 | - private static final String TOPIC_SEPARATOR = ","; | ||
| 43 | - /** | ||
| 44 | * 默认 QoS 级别 | 40 | * 默认 QoS 级别 |
| 45 | */ | 41 | */ |
| 46 | private static final MqttQoS DEFAULT_QOS = MqttQoS.AT_LEAST_ONCE; | 42 | private static final MqttQoS DEFAULT_QOS = MqttQoS.AT_LEAST_ONCE; |
| @@ -84,42 +80,40 @@ public class IotDeviceUpstreamServer { | @@ -84,42 +80,40 @@ public class IotDeviceUpstreamServer { | ||
| 84 | */ | 80 | */ |
| 85 | public void start() { | 81 | public void start() { |
| 86 | if (isRunning) { | 82 | if (isRunning) { |
| 87 | - log.warn("服务已经在运行中,请勿重复启动"); | 83 | + log.warn("[start][服务已经在运行中,请勿重复启动]"); |
| 88 | return; | 84 | return; |
| 89 | } | 85 | } |
| 90 | - | ||
| 91 | - log.info("[start] 开始启动服务"); | 86 | + log.info("[start][开始启动服务]"); |
| 92 | 87 | ||
| 93 | // 1. 启动 HTTP 服务器 | 88 | // 1. 启动 HTTP 服务器 |
| 94 | CompletableFuture<Void> httpFuture = server.listen(emqxProperties.getAuthPort()) | 89 | CompletableFuture<Void> httpFuture = server.listen(emqxProperties.getAuthPort()) |
| 95 | .toCompletionStage() | 90 | .toCompletionStage() |
| 96 | .toCompletableFuture() | 91 | .toCompletableFuture() |
| 97 | - .thenAccept(v -> log.info("[start] HTTP服务器启动完成,端口: {}", server.actualPort())); | 92 | + .thenAccept(v -> log.info("[start][HTTP服务器启动完成,端口: {}]", server.actualPort())); |
| 98 | 93 | ||
| 99 | // 2. 连接 MQTT Broker | 94 | // 2. 连接 MQTT Broker |
| 100 | CompletableFuture<Void> mqttFuture = connectMqtt() | 95 | CompletableFuture<Void> mqttFuture = connectMqtt() |
| 101 | .toCompletionStage() | 96 | .toCompletionStage() |
| 102 | .toCompletableFuture() | 97 | .toCompletableFuture() |
| 103 | .thenAccept(v -> { | 98 | .thenAccept(v -> { |
| 104 | - // 3. 添加 MQTT 断开重连监听器 | 99 | + // 2.1 添加 MQTT 断开重连监听器 |
| 105 | client.closeHandler(closeEvent -> { | 100 | client.closeHandler(closeEvent -> { |
| 106 | - log.warn("[closeHandler] MQTT连接已断开,准备重连"); | 101 | + log.warn("[closeHandler][MQTT连接已断开,准备重连]"); |
| 107 | reconnectWithDelay(); | 102 | reconnectWithDelay(); |
| 108 | }); | 103 | }); |
| 109 | - | ||
| 110 | - // 4. 设置 MQTT 消息处理器 | 104 | + // 2. 设置 MQTT 消息处理器 |
| 111 | setupMessageHandler(); | 105 | setupMessageHandler(); |
| 112 | }); | 106 | }); |
| 113 | 107 | ||
| 114 | - // 等待所有服务启动完成 | 108 | + // 3. 等待所有服务启动完成 |
| 115 | CompletableFuture.allOf(httpFuture, mqttFuture) | 109 | CompletableFuture.allOf(httpFuture, mqttFuture) |
| 116 | .orTimeout(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS) | 110 | .orTimeout(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS) |
| 117 | .whenComplete((result, error) -> { | 111 | .whenComplete((result, error) -> { |
| 118 | if (error != null) { | 112 | if (error != null) { |
| 119 | - log.error("[start] 服务启动失败", error); | 113 | + log.error("[start][服务启动失败]", error); |
| 120 | } else { | 114 | } else { |
| 121 | isRunning = true; | 115 | isRunning = true; |
| 122 | - log.info("[start] 所有服务启动完成"); | 116 | + log.info("[start][所有服务启动完成]"); |
| 123 | } | 117 | } |
| 124 | }); | 118 | }); |
| 125 | } | 119 | } |
| @@ -129,7 +123,7 @@ public class IotDeviceUpstreamServer { | @@ -129,7 +123,7 @@ public class IotDeviceUpstreamServer { | ||
| 129 | */ | 123 | */ |
| 130 | private void setupMessageHandler() { | 124 | private void setupMessageHandler() { |
| 131 | client.publishHandler(mqttMessageHandler::handle); | 125 | client.publishHandler(mqttMessageHandler::handle); |
| 132 | - log.debug("[setupMessageHandler] MQTT消息处理器设置完成"); | 126 | + log.debug("[setupMessageHandler][MQTT消息处理器设置完成]"); |
| 133 | } | 127 | } |
| 134 | 128 | ||
| 135 | /** | 129 | /** |
| @@ -137,12 +131,12 @@ public class IotDeviceUpstreamServer { | @@ -137,12 +131,12 @@ public class IotDeviceUpstreamServer { | ||
| 137 | */ | 131 | */ |
| 138 | private void reconnectWithDelay() { | 132 | private void reconnectWithDelay() { |
| 139 | if (!isRunning) { | 133 | if (!isRunning) { |
| 140 | - log.info("[reconnectWithDelay] 服务已停止,不再尝试重连"); | 134 | + log.info("[reconnectWithDelay][服务已停止,不再尝试重连]"); |
| 141 | return; | 135 | return; |
| 142 | } | 136 | } |
| 143 | 137 | ||
| 144 | vertx.setTimer(RECONNECT_DELAY_MS, id -> { | 138 | vertx.setTimer(RECONNECT_DELAY_MS, id -> { |
| 145 | - log.info("[reconnectWithDelay] 开始重新连接MQTT"); | 139 | + log.info("[reconnectWithDelay][开始重新连接 MQTT]"); |
| 146 | connectMqtt(); | 140 | connectMqtt(); |
| 147 | }); | 141 | }); |
| 148 | } | 142 | } |
| @@ -155,28 +149,28 @@ public class IotDeviceUpstreamServer { | @@ -155,28 +149,28 @@ public class IotDeviceUpstreamServer { | ||
| 155 | private Future<Void> connectMqtt() { | 149 | private Future<Void> connectMqtt() { |
| 156 | return client.connect(emqxProperties.getMqttPort(), emqxProperties.getMqttHost()) | 150 | return client.connect(emqxProperties.getMqttPort(), emqxProperties.getMqttHost()) |
| 157 | .compose(connAck -> { | 151 | .compose(connAck -> { |
| 158 | - log.info("[connectMqtt] MQTT客户端连接成功"); | 152 | + log.info("[connectMqtt][MQTT客户端连接成功]"); |
| 159 | return subscribeToTopics(); | 153 | return subscribeToTopics(); |
| 160 | }) | 154 | }) |
| 161 | - .recover(err -> { | ||
| 162 | - log.error("[connectMqtt] 连接MQTT Broker失败: {}", err.getMessage()); | 155 | + .recover(error -> { |
| 156 | + log.error("[connectMqtt][连接MQTT Broker失败:]", error); | ||
| 163 | reconnectWithDelay(); | 157 | reconnectWithDelay(); |
| 164 | - return Future.failedFuture(err); | 158 | + return Future.failedFuture(error); |
| 165 | }); | 159 | }); |
| 166 | } | 160 | } |
| 167 | 161 | ||
| 168 | /** | 162 | /** |
| 169 | * 订阅设备上行消息主题 | 163 | * 订阅设备上行消息主题 |
| 170 | * | 164 | * |
| 171 | - * @return 订阅结果的Future | 165 | + * @return 订阅结果的 Future |
| 172 | */ | 166 | */ |
| 173 | private Future<Void> subscribeToTopics() { | 167 | private Future<Void> subscribeToTopics() { |
| 174 | String[] topics = emqxProperties.getMqttTopics(); | 168 | String[] topics = emqxProperties.getMqttTopics(); |
| 175 | if (ArrayUtil.isEmpty(topics)) { | 169 | if (ArrayUtil.isEmpty(topics)) { |
| 176 | - log.warn("[subscribeToTopics] 未配置MQTT主题,跳过订阅"); | 170 | + log.warn("[subscribeToTopics][未配置MQTT主题,跳过订阅]"); |
| 177 | return Future.succeededFuture(); | 171 | return Future.succeededFuture(); |
| 178 | } | 172 | } |
| 179 | - log.info("[subscribeToTopics] 开始订阅设备上行消息主题"); | 173 | + log.info("[subscribeToTopics][开始订阅设备上行消息主题]"); |
| 180 | 174 | ||
| 181 | Future<Void> compositeFuture = Future.succeededFuture(); | 175 | Future<Void> compositeFuture = Future.succeededFuture(); |
| 182 | for (String topic : topics) { | 176 | for (String topic : topics) { |
| @@ -186,11 +180,11 @@ public class IotDeviceUpstreamServer { | @@ -186,11 +180,11 @@ public class IotDeviceUpstreamServer { | ||
| 186 | } | 180 | } |
| 187 | compositeFuture = compositeFuture.compose(v -> client.subscribe(trimmedTopic, DEFAULT_QOS.value()) | 181 | compositeFuture = compositeFuture.compose(v -> client.subscribe(trimmedTopic, DEFAULT_QOS.value()) |
| 188 | .<Void>map(ack -> { | 182 | .<Void>map(ack -> { |
| 189 | - log.info("[subscribeToTopics] 成功订阅主题: {}", trimmedTopic); | 183 | + log.info("[subscribeToTopics][成功订阅主题: {}]", trimmedTopic); |
| 190 | return null; | 184 | return null; |
| 191 | }) | 185 | }) |
| 192 | - .recover(err -> { | ||
| 193 | - log.error("[subscribeToTopics] 订阅主题失败: {}, 原因: {}", trimmedTopic, err.getMessage()); | 186 | + .recover(error -> { |
| 187 | + log.error("[subscribeToTopics][订阅主题失败: {}]", trimmedTopic, error); | ||
| 194 | return Future.<Void>succeededFuture(); // 继续订阅其他主题 | 188 | return Future.<Void>succeededFuture(); // 继续订阅其他主题 |
| 195 | })); | 189 | })); |
| 196 | } | 190 | } |
| @@ -202,10 +196,10 @@ public class IotDeviceUpstreamServer { | @@ -202,10 +196,10 @@ public class IotDeviceUpstreamServer { | ||
| 202 | */ | 196 | */ |
| 203 | public void stop() { | 197 | public void stop() { |
| 204 | if (!isRunning) { | 198 | if (!isRunning) { |
| 205 | - log.warn("[stop] 服务未运行,无需停止"); | 199 | + log.warn("[stop][服务未运行,无需停止]"); |
| 206 | return; | 200 | return; |
| 207 | } | 201 | } |
| 208 | - log.info("[stop] 开始关闭服务"); | 202 | + log.info("[stop][开始关闭服务]"); |
| 209 | isRunning = false; | 203 | isRunning = false; |
| 210 | 204 | ||
| 211 | try { | 205 | try { |
| @@ -224,14 +218,14 @@ public class IotDeviceUpstreamServer { | @@ -224,14 +218,14 @@ public class IotDeviceUpstreamServer { | ||
| 224 | .orTimeout(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS) | 218 | .orTimeout(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS) |
| 225 | .whenComplete((result, error) -> { | 219 | .whenComplete((result, error) -> { |
| 226 | if (error != null) { | 220 | if (error != null) { |
| 227 | - log.error("[stop] 服务关闭过程中发生异常", error); | 221 | + log.error("[stop][服务关闭过程中发生异常]", error); |
| 228 | } else { | 222 | } else { |
| 229 | - log.info("[stop] 所有服务关闭完成"); | 223 | + log.info("[stop][所有服务关闭完成]"); |
| 230 | } | 224 | } |
| 231 | }); | 225 | }); |
| 232 | } catch (Exception e) { | 226 | } catch (Exception e) { |
| 233 | - log.error("[stop] 关闭服务异常", e); | ||
| 234 | - throw new RuntimeException("关闭IoT设备上行服务失败", e); | 227 | + log.error("[stop][关闭服务异常]", e); |
| 228 | + throw new RuntimeException("关闭 IoT 设备上行服务失败", e); | ||
| 235 | } | 229 | } |
| 236 | } | 230 | } |
| 237 | } | 231 | } |
| 238 | \ No newline at end of file | 232 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java
| @@ -15,7 +15,7 @@ import java.util.Collections; | @@ -15,7 +15,7 @@ import java.util.Collections; | ||
| 15 | /** | 15 | /** |
| 16 | * IoT EMQX 连接认证的 Vert.x Handler | 16 | * IoT EMQX 连接认证的 Vert.x Handler |
| 17 | * | 17 | * |
| 18 | - * <a href="https://docs.emqx.com/zh/emqx/latest/access-control/authn/http.html">EMQX HTTP</a> | 18 | + * 参考:<a href="https://docs.emqx.com/zh/emqx/latest/access-control/authn/http.html">EMQX HTTP</a> |
| 19 | * | 19 | * |
| 20 | * 注意:该处理器需要返回特定格式:{"result": "allow"} 或 {"result": "deny"}, | 20 | * 注意:该处理器需要返回特定格式:{"result": "allow"} 或 {"result": "deny"}, |
| 21 | * 以符合 EMQX 认证插件的要求,因此不使用 IotStandardResponse 实体类 | 21 | * 以符合 EMQX 认证插件的要求,因此不使用 IotStandardResponse 实体类 |
| @@ -31,7 +31,6 @@ public class IotDeviceAuthVertxHandler implements Handler<RoutingContext> { | @@ -31,7 +31,6 @@ public class IotDeviceAuthVertxHandler implements Handler<RoutingContext> { | ||
| 31 | private final IotDeviceUpstreamApi deviceUpstreamApi; | 31 | private final IotDeviceUpstreamApi deviceUpstreamApi; |
| 32 | 32 | ||
| 33 | @Override | 33 | @Override |
| 34 | - @SuppressWarnings("unchecked") | ||
| 35 | public void handle(RoutingContext routingContext) { | 34 | public void handle(RoutingContext routingContext) { |
| 36 | try { | 35 | try { |
| 37 | // 构建认证请求 DTO | 36 | // 构建认证请求 DTO |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java
| @@ -23,7 +23,7 @@ import java.util.Map; | @@ -23,7 +23,7 @@ import java.util.Map; | ||
| 23 | /** | 23 | /** |
| 24 | * IoT 设备 MQTT 消息处理器 | 24 | * IoT 设备 MQTT 消息处理器 |
| 25 | * | 25 | * |
| 26 | - * 参考:"<a href="https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services">设备属性、事件、服务</a>"> | 26 | + * 参考:<a href="https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services">设备属性、事件、服务</a> |
| 27 | */ | 27 | */ |
| 28 | @Slf4j | 28 | @Slf4j |
| 29 | public class IotDeviceMqttMessageHandler { | 29 | public class IotDeviceMqttMessageHandler { |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceWebhookVertxHandler.java
| @@ -18,7 +18,7 @@ import java.util.Collections; | @@ -18,7 +18,7 @@ import java.util.Collections; | ||
| 18 | /** | 18 | /** |
| 19 | * IoT EMQX Webhook 事件处理的 Vert.x Handler | 19 | * IoT EMQX Webhook 事件处理的 Vert.x Handler |
| 20 | * | 20 | * |
| 21 | - * <a href="https://docs.emqx.com/zh/emqx/latest/data-integration/webhook.html">EMQX Webhook</a> | 21 | + * 参考:<a href="https://docs.emqx.com/zh/emqx/latest/data-integration/webhook.html">EMQX Webhook</a> |
| 22 | * | 22 | * |
| 23 | * 注意:该处理器需要返回特定格式:{"result": "success"} 或 {"result": "error"}, | 23 | * 注意:该处理器需要返回特定格式:{"result": "success"} 或 {"result": "error"}, |
| 24 | * 以符合 EMQX Webhook 插件的要求,因此不使用 IotStandardResponse 实体类。 | 24 | * 以符合 EMQX Webhook 插件的要求,因此不使用 IotStandardResponse 实体类。 |
| @@ -51,8 +51,7 @@ public class IotDeviceWebhookVertxHandler implements Handler<RoutingContext> { | @@ -51,8 +51,7 @@ public class IotDeviceWebhookVertxHandler implements Handler<RoutingContext> { | ||
| 51 | handleClientDisconnected(clientId, username); | 51 | handleClientDisconnected(clientId, username); |
| 52 | break; | 52 | break; |
| 53 | default: | 53 | default: |
| 54 | - log.info("[handle][未处理的 Webhook 事件] event={}, clientId={}, username={}", event, clientId, | ||
| 55 | - username); | 54 | + log.info("[handle][未处理的 Webhook 事件] event={}, clientId={}, username={}", event, clientId, username); |
| 56 | break; | 55 | break; |
| 57 | } | 56 | } |
| 58 | 57 |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotHttpVertxPlugin.java
| @@ -23,10 +23,8 @@ public class IotHttpVertxPlugin extends SpringPlugin { | @@ -23,10 +23,8 @@ public class IotHttpVertxPlugin extends SpringPlugin { | ||
| 23 | public void start() { | 23 | public void start() { |
| 24 | log.info("[HttpVertxPlugin][HttpVertxPlugin 插件启动开始...]"); | 24 | log.info("[HttpVertxPlugin][HttpVertxPlugin 插件启动开始...]"); |
| 25 | try { | 25 | try { |
| 26 | - // 1. 获取插件上下文 | ||
| 27 | ApplicationContext pluginContext = getApplicationContext(); | 26 | ApplicationContext pluginContext = getApplicationContext(); |
| 28 | Assert.notNull(pluginContext, "pluginContext 不能为空"); | 27 | Assert.notNull(pluginContext, "pluginContext 不能为空"); |
| 29 | - | ||
| 30 | log.info("[HttpVertxPlugin][HttpVertxPlugin 插件启动成功...]"); | 28 | log.info("[HttpVertxPlugin][HttpVertxPlugin 插件启动成功...]"); |
| 31 | } catch (Exception e) { | 29 | } catch (Exception e) { |
| 32 | log.error("[HttpVertxPlugin][HttpVertxPlugin 插件开启动异常...]", e); | 30 | log.error("[HttpVertxPlugin][HttpVertxPlugin 插件开启动异常...]", e); |
| @@ -43,6 +41,7 @@ public class IotHttpVertxPlugin extends SpringPlugin { | @@ -43,6 +41,7 @@ public class IotHttpVertxPlugin extends SpringPlugin { | ||
| 43 | } | 41 | } |
| 44 | } | 42 | } |
| 45 | 43 | ||
| 44 | + // TODO @芋艿:思考下,未来要不要。。。 | ||
| 46 | @Override | 45 | @Override |
| 47 | protected ApplicationContext createApplicationContext() { | 46 | protected ApplicationContext createApplicationContext() { |
| 48 | // 创建插件自己的 ApplicationContext | 47 | // 创建插件自己的 ApplicationContext |
| @@ -52,6 +51,7 @@ public class IotHttpVertxPlugin extends SpringPlugin { | @@ -52,6 +51,7 @@ public class IotHttpVertxPlugin extends SpringPlugin { | ||
| 52 | // 继续使用插件自己的 ClassLoader 以加载插件内部的类 | 51 | // 继续使用插件自己的 ClassLoader 以加载插件内部的类 |
| 53 | pluginContext.setClassLoader(getWrapper().getPluginClassLoader()); | 52 | pluginContext.setClassLoader(getWrapper().getPluginClassLoader()); |
| 54 | // 扫描当前插件的自动配置包 | 53 | // 扫描当前插件的自动配置包 |
| 54 | + // TODO @芋艿:后续看看,怎么配置类包 | ||
| 55 | pluginContext.scan("cn.iocoder.yudao.module.iot.plugin.http.config"); | 55 | pluginContext.scan("cn.iocoder.yudao.module.iot.plugin.http.config"); |
| 56 | pluginContext.refresh(); | 56 | pluginContext.refresh(); |
| 57 | return pluginContext; | 57 | return pluginContext; |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceUpstreamVertxHandler.java
| @@ -34,6 +34,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC | @@ -34,6 +34,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC | ||
| 34 | @Slf4j | 34 | @Slf4j |
| 35 | public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> { | 35 | public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> { |
| 36 | 36 | ||
| 37 | + // TODO @haohao:要不要类似 IotDeviceConfigSetVertxHandler 写的,把这些 PATH、METHOD 之类的抽走 | ||
| 37 | /** | 38 | /** |
| 38 | * 属性上报路径 | 39 | * 属性上报路径 |
| 39 | */ | 40 | */ |
| @@ -49,6 +50,7 @@ public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> { | @@ -49,6 +50,7 @@ public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> { | ||
| 49 | 50 | ||
| 50 | private final IotDeviceUpstreamApi deviceUpstreamApi; | 51 | private final IotDeviceUpstreamApi deviceUpstreamApi; |
| 51 | 52 | ||
| 53 | + // TODO @haohao:要不要分成多个 Handler?每个只解决一个问题哈。 | ||
| 52 | @Override | 54 | @Override |
| 53 | public void handle(RoutingContext routingContext) { | 55 | public void handle(RoutingContext routingContext) { |
| 54 | String path = routingContext.request().path(); | 56 | String path = routingContext.request().path(); |
| @@ -102,7 +104,6 @@ public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> { | @@ -102,7 +104,6 @@ public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> { | ||
| 102 | IotPluginCommonUtils.writeJsonResponse(routingContext, response); | 104 | IotPluginCommonUtils.writeJsonResponse(routingContext, response); |
| 103 | } catch (Exception e) { | 105 | } catch (Exception e) { |
| 104 | log.error("[handle][处理上行请求异常] path={}", path, e); | 106 | log.error("[handle][处理上行请求异常] path={}", path, e); |
| 105 | - // 构建错误响应 | ||
| 106 | String method = path.contains("/property/") ? PROPERTY_METHOD | 107 | String method = path.contains("/property/") ? PROPERTY_METHOD |
| 107 | : EVENT_METHOD_PREFIX + (routingContext.pathParams().containsKey("identifier") | 108 | : EVENT_METHOD_PREFIX + (routingContext.pathParams().containsKey("identifier") |
| 108 | ? routingContext.pathParam("identifier") | 109 | ? routingContext.pathParam("identifier") |
| @@ -115,27 +116,28 @@ public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> { | @@ -115,27 +116,28 @@ public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> { | ||
| 115 | /** | 116 | /** |
| 116 | * 更新设备状态 | 117 | * 更新设备状态 |
| 117 | * | 118 | * |
| 118 | - * @param productKey 产品Key | 119 | + * @param productKey 产品 Key |
| 119 | * @param deviceName 设备名称 | 120 | * @param deviceName 设备名称 |
| 120 | */ | 121 | */ |
| 121 | private void updateDeviceState(String productKey, String deviceName) { | 122 | private void updateDeviceState(String productKey, String deviceName) { |
| 122 | - deviceUpstreamApi.updateDeviceState(((IotDeviceStateUpdateReqDTO) new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()).setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()).setProductKey(productKey).setDeviceName(deviceName)).setState(IotDeviceStateEnum.ONLINE.getState())); | 123 | + deviceUpstreamApi.updateDeviceState(((IotDeviceStateUpdateReqDTO) new IotDeviceStateUpdateReqDTO() |
| 124 | + .setRequestId(IdUtil.fastSimpleUUID()).setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) | ||
| 125 | + .setProductKey(productKey).setDeviceName(deviceName)).setState(IotDeviceStateEnum.ONLINE.getState())); | ||
| 123 | } | 126 | } |
| 124 | 127 | ||
| 125 | /** | 128 | /** |
| 126 | * 解析属性上报请求 | 129 | * 解析属性上报请求 |
| 127 | * | 130 | * |
| 128 | - * @param productKey 产品Key | 131 | + * @param productKey 产品 Key |
| 129 | * @param deviceName 设备名称 | 132 | * @param deviceName 设备名称 |
| 130 | - * @param requestId 请求ID | 133 | + * @param requestId 请求 ID |
| 131 | * @param body 请求体 | 134 | * @param body 请求体 |
| 132 | - * @return 属性上报请求DTO | 135 | + * @return 属性上报请求 DTO |
| 133 | */ | 136 | */ |
| 134 | @SuppressWarnings("unchecked") | 137 | @SuppressWarnings("unchecked") |
| 135 | private IotDevicePropertyReportReqDTO parsePropertyReportRequest(String productKey, String deviceName, String requestId, JsonObject body) { | 138 | private IotDevicePropertyReportReqDTO parsePropertyReportRequest(String productKey, String deviceName, String requestId, JsonObject body) { |
| 136 | // 按照标准 JSON 格式处理属性数据 | 139 | // 按照标准 JSON 格式处理属性数据 |
| 137 | Map<String, Object> properties = new HashMap<>(); | 140 | Map<String, Object> properties = new HashMap<>(); |
| 138 | - // 优先使用 params 字段,符合标准 | ||
| 139 | Map<String, Object> params = body.getJsonObject("params") != null ? body.getJsonObject("params").getMap() : null; | 141 | Map<String, Object> params = body.getJsonObject("params") != null ? body.getJsonObject("params").getMap() : null; |
| 140 | if (params != null) { | 142 | if (params != null) { |
| 141 | // 将标准格式的 params 转换为平台需要的 properties 格式 | 143 | // 将标准格式的 params 转换为平台需要的 properties 格式 |
| @@ -153,24 +155,25 @@ public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> { | @@ -153,24 +155,25 @@ public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> { | ||
| 153 | } | 155 | } |
| 154 | 156 | ||
| 155 | // 构建属性上报请求 DTO | 157 | // 构建属性上报请求 DTO |
| 156 | - return ((IotDevicePropertyReportReqDTO) new IotDevicePropertyReportReqDTO().setRequestId(requestId).setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()).setProductKey(productKey).setDeviceName(deviceName)).setProperties(properties); | 158 | + return ((IotDevicePropertyReportReqDTO) new IotDevicePropertyReportReqDTO().setRequestId(requestId) |
| 159 | + .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) | ||
| 160 | + .setProductKey(productKey).setDeviceName(deviceName)).setProperties(properties); | ||
| 157 | } | 161 | } |
| 158 | 162 | ||
| 159 | /** | 163 | /** |
| 160 | * 解析事件上报请求 | 164 | * 解析事件上报请求 |
| 161 | * | 165 | * |
| 162 | - * @param productKey 产品Key | 166 | + * @param productKey 产品K ey |
| 163 | * @param deviceName 设备名称 | 167 | * @param deviceName 设备名称 |
| 164 | * @param identifier 事件标识符 | 168 | * @param identifier 事件标识符 |
| 165 | - * @param requestId 请求ID | 169 | + * @param requestId 请求 ID |
| 166 | * @param body 请求体 | 170 | * @param body 请求体 |
| 167 | - * @return 事件上报请求DTO | 171 | + * @return 事件上报请求 DTO |
| 168 | */ | 172 | */ |
| 169 | private IotDeviceEventReportReqDTO parseEventReportRequest(String productKey, String deviceName, String identifier, String requestId, JsonObject body) { | 173 | private IotDeviceEventReportReqDTO parseEventReportRequest(String productKey, String deviceName, String identifier, String requestId, JsonObject body) { |
| 170 | - // 按照标准JSON格式处理事件参数 | 174 | + // 按照标准 JSON 格式处理事件参数 |
| 171 | Map<String, Object> params; | 175 | Map<String, Object> params; |
| 172 | - // 优先使用params字段,符合标准 | ||
| 173 | - if (body.getJsonObject("params") != null) { | 176 | + if (body.containsKey("params")) { |
| 174 | params = body.getJsonObject("params").getMap(); | 177 | params = body.getJsonObject("params").getMap(); |
| 175 | } else { | 178 | } else { |
| 176 | // 兼容旧格式 | 179 | // 兼容旧格式 |
| @@ -178,6 +181,8 @@ public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> { | @@ -178,6 +181,8 @@ public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> { | ||
| 178 | } | 181 | } |
| 179 | 182 | ||
| 180 | // 构建事件上报请求 DTO | 183 | // 构建事件上报请求 DTO |
| 181 | - return ((IotDeviceEventReportReqDTO) new IotDeviceEventReportReqDTO().setRequestId(requestId).setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()).setProductKey(productKey).setDeviceName(deviceName)).setIdentifier(identifier).setParams(params); | 184 | + return ((IotDeviceEventReportReqDTO) new IotDeviceEventReportReqDTO().setRequestId(requestId) |
| 185 | + .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) | ||
| 186 | + .setProductKey(productKey).setDeviceName(deviceName)).setIdentifier(identifier).setParams(params); | ||
| 182 | } | 187 | } |
| 183 | } | 188 | } |
| 184 | \ No newline at end of file | 189 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/pom.xml
| @@ -14,6 +14,7 @@ | @@ -14,6 +14,7 @@ | ||
| 14 | <artifactId>yudao-module-iot-plugin-mqtt</artifactId> | 14 | <artifactId>yudao-module-iot-plugin-mqtt</artifactId> |
| 15 | 15 | ||
| 16 | <name>${project.artifactId}</name> | 16 | <name>${project.artifactId}</name> |
| 17 | + <!-- TODO @芋艿:待整理 --> | ||
| 17 | <description> | 18 | <description> |
| 18 | 物联网 插件模块 - mqtt 插件 | 19 | 物联网 插件模块 - mqtt 插件 |
| 19 | </description> | 20 | </description> |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java
| @@ -4,6 +4,7 @@ import lombok.extern.slf4j.Slf4j; | @@ -4,6 +4,7 @@ import lombok.extern.slf4j.Slf4j; | ||
| 4 | import org.pf4j.Plugin; | 4 | import org.pf4j.Plugin; |
| 5 | import org.pf4j.PluginWrapper; | 5 | import org.pf4j.PluginWrapper; |
| 6 | 6 | ||
| 7 | +// TODO @芋艿:暂未实现 | ||
| 7 | @Slf4j | 8 | @Slf4j |
| 8 | public class MqttPlugin extends Plugin { | 9 | public class MqttPlugin extends Plugin { |
| 9 | 10 |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java
| @@ -21,6 +21,7 @@ import java.nio.charset.Charset; | @@ -21,6 +21,7 @@ import java.nio.charset.Charset; | ||
| 21 | import java.util.ArrayList; | 21 | import java.util.ArrayList; |
| 22 | import java.util.List; | 22 | import java.util.List; |
| 23 | 23 | ||
| 24 | +// TODO @芋艿:暂未实现 | ||
| 24 | /** | 25 | /** |
| 25 | * 根据官方示例,整合常见 MQTT 功能到 PF4J 的 Extension 类中 | 26 | * 根据官方示例,整合常见 MQTT 功能到 PF4J 的 Extension 类中 |
| 26 | */ | 27 | */ |