Commit a9733b4d2af6caf65445ce2ce4aac3295c106618

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