Commit 0bdd000226e83ee7b01794030248522b84375616
1 parent
86e4379e
【代码评审】IoT:mqtt 协议的接入
Showing
13 changed files
with
61 additions
and
100 deletions
yudao-module-iot/yudao-module-iot-biz/pom.xml
| ... | ... | @@ -43,6 +43,11 @@ |
| 43 | 43 | |
| 44 | 44 | <!-- DB 相关 --> |
| 45 | 45 | <dependency> |
| 46 | + <groupId>com.taosdata.jdbc</groupId> | |
| 47 | + <artifactId>taos-jdbcdriver</artifactId> | |
| 48 | + </dependency> | |
| 49 | + | |
| 50 | + <dependency> | |
| 46 | 51 | <groupId>cn.iocoder.boot</groupId> |
| 47 | 52 | <artifactId>yudao-spring-boot-starter-mybatis</artifactId> |
| 48 | 53 | </dependency> |
| ... | ... | @@ -107,12 +112,6 @@ |
| 107 | 112 | <version>24.1.2</version> |
| 108 | 113 | </dependency> |
| 109 | 114 | |
| 110 | - <!-- TDengine 相关依赖 --> | |
| 111 | - <dependency> | |
| 112 | - <groupId>com.taosdata.jdbc</groupId> | |
| 113 | - <artifactId>taos-jdbcdriver</artifactId> | |
| 114 | - </dependency> | |
| 115 | - | |
| 116 | 115 | </dependencies> |
| 117 | 116 | |
| 118 | 117 | </project> | ... | ... |
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
| ... | ... | @@ -46,7 +46,6 @@ public class IotDeviceConfigSetVertxHandler implements Handler<RoutingContext> { |
| 46 | 46 | .setConfig(config); |
| 47 | 47 | } catch (Exception e) { |
| 48 | 48 | log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); |
| 49 | - // 使用IotStandardResponse实体类返回错误 | |
| 50 | 49 | IotStandardResponse errorResponse = IotStandardResponse.error( |
| 51 | 50 | null, METHOD, BAD_REQUEST.getCode(), BAD_REQUEST.getMsg()); |
| 52 | 51 | IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); |
| ... | ... | @@ -57,18 +56,16 @@ public class IotDeviceConfigSetVertxHandler implements Handler<RoutingContext> { |
| 57 | 56 | try { |
| 58 | 57 | CommonResult<Boolean> result = deviceDownstreamHandler.setDeviceConfig(reqDTO); |
| 59 | 58 | |
| 60 | - // 使用IotStandardResponse实体类返回结果 | |
| 59 | + // 3. 响应结果 | |
| 61 | 60 | IotStandardResponse response; |
| 62 | 61 | if (result.isSuccess()) { |
| 63 | 62 | response = IotStandardResponse.success(reqDTO.getRequestId(), METHOD, result.getData()); |
| 64 | 63 | } else { |
| 65 | - response = IotStandardResponse.error( | |
| 66 | - reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); | |
| 64 | + response = IotStandardResponse.error(reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); | |
| 67 | 65 | } |
| 68 | 66 | IotPluginCommonUtils.writeJsonResponse(routingContext, response); |
| 69 | 67 | } catch (Exception e) { |
| 70 | 68 | log.error("[handle][请求参数({}) 配置设置异常]", reqDTO, e); |
| 71 | - // 使用IotStandardResponse实体类返回错误 | |
| 72 | 69 | IotStandardResponse errorResponse = IotStandardResponse.error( |
| 73 | 70 | reqDTO.getRequestId(), METHOD, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); |
| 74 | 71 | 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/downstream/router/IotDeviceOtaUpgradeVertxHandler.java
| ... | ... | @@ -51,7 +51,6 @@ public class IotDeviceOtaUpgradeVertxHandler implements Handler<RoutingContext> |
| 51 | 51 | .setInformation(information); |
| 52 | 52 | } catch (Exception e) { |
| 53 | 53 | log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); |
| 54 | - // 使用IotStandardResponse实体类返回错误 | |
| 55 | 54 | IotStandardResponse errorResponse = IotStandardResponse.error( |
| 56 | 55 | null, METHOD, BAD_REQUEST.getCode(), BAD_REQUEST.getMsg()); |
| 57 | 56 | IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); |
| ... | ... | @@ -62,18 +61,16 @@ public class IotDeviceOtaUpgradeVertxHandler implements Handler<RoutingContext> |
| 62 | 61 | try { |
| 63 | 62 | CommonResult<Boolean> result = deviceDownstreamHandler.upgradeDeviceOta(reqDTO); |
| 64 | 63 | |
| 65 | - // 使用IotStandardResponse实体类返回结果 | |
| 64 | + // 3. 响应结果 | |
| 66 | 65 | IotStandardResponse response; |
| 67 | 66 | if (result.isSuccess()) { |
| 68 | 67 | response = IotStandardResponse.success(reqDTO.getRequestId(), METHOD, result.getData()); |
| 69 | 68 | } else { |
| 70 | - response = IotStandardResponse.error( | |
| 71 | - reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); | |
| 69 | + response = IotStandardResponse.error(reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); | |
| 72 | 70 | } |
| 73 | 71 | IotPluginCommonUtils.writeJsonResponse(routingContext, response); |
| 74 | 72 | } catch (Exception e) { |
| 75 | 73 | log.error("[handle][请求参数({}) OTA 升级异常]", reqDTO, e); |
| 76 | - // 使用IotStandardResponse实体类返回错误 | |
| 77 | 74 | IotStandardResponse errorResponse = IotStandardResponse.error( |
| 78 | 75 | reqDTO.getRequestId(), METHOD, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); |
| 79 | 76 | 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/downstream/router/IotDevicePropertyGetVertxHandler.java
| ... | ... | @@ -46,7 +46,6 @@ public class IotDevicePropertyGetVertxHandler implements Handler<RoutingContext> |
| 46 | 46 | .setIdentifiers(identifiers); |
| 47 | 47 | } catch (Exception e) { |
| 48 | 48 | log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); |
| 49 | - // 使用IotStandardResponse实体类返回错误 | |
| 50 | 49 | IotStandardResponse errorResponse = IotStandardResponse.error( |
| 51 | 50 | null, METHOD, BAD_REQUEST.getCode(), BAD_REQUEST.getMsg()); |
| 52 | 51 | IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); |
| ... | ... | @@ -57,18 +56,16 @@ public class IotDevicePropertyGetVertxHandler implements Handler<RoutingContext> |
| 57 | 56 | try { |
| 58 | 57 | CommonResult<Boolean> result = deviceDownstreamHandler.getDeviceProperty(reqDTO); |
| 59 | 58 | |
| 60 | - // 使用IotStandardResponse实体类返回结果 | |
| 59 | + // 3. 响应结果 | |
| 61 | 60 | IotStandardResponse response; |
| 62 | 61 | if (result.isSuccess()) { |
| 63 | 62 | response = IotStandardResponse.success(reqDTO.getRequestId(), METHOD, result.getData()); |
| 64 | 63 | } else { |
| 65 | - response = IotStandardResponse.error( | |
| 66 | - reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); | |
| 64 | + response = IotStandardResponse.error(reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); | |
| 67 | 65 | } |
| 68 | 66 | IotPluginCommonUtils.writeJsonResponse(routingContext, response); |
| 69 | 67 | } catch (Exception e) { |
| 70 | 68 | log.error("[handle][请求参数({}) 属性获取异常]", reqDTO, e); |
| 71 | - // 使用IotStandardResponse实体类返回错误 | |
| 72 | 69 | IotStandardResponse errorResponse = IotStandardResponse.error( |
| 73 | 70 | reqDTO.getRequestId(), METHOD, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); |
| 74 | 71 | 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/downstream/router/IotDevicePropertySetVertxHandler.java
| ... | ... | @@ -46,7 +46,6 @@ public class IotDevicePropertySetVertxHandler implements Handler<RoutingContext> |
| 46 | 46 | .setProperties(properties); |
| 47 | 47 | } catch (Exception e) { |
| 48 | 48 | log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); |
| 49 | - // 使用IotStandardResponse实体类返回错误 | |
| 50 | 49 | IotStandardResponse errorResponse = IotStandardResponse.error( |
| 51 | 50 | null, METHOD, BAD_REQUEST.getCode(), BAD_REQUEST.getMsg()); |
| 52 | 51 | IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); |
| ... | ... | @@ -57,18 +56,16 @@ public class IotDevicePropertySetVertxHandler implements Handler<RoutingContext> |
| 57 | 56 | try { |
| 58 | 57 | CommonResult<Boolean> result = deviceDownstreamHandler.setDeviceProperty(reqDTO); |
| 59 | 58 | |
| 60 | - // 使用IotStandardResponse实体类返回结果 | |
| 59 | + // 3. 响应结果 | |
| 61 | 60 | IotStandardResponse response; |
| 62 | 61 | if (result.isSuccess()) { |
| 63 | 62 | response = IotStandardResponse.success(reqDTO.getRequestId(), METHOD, result.getData()); |
| 64 | 63 | } else { |
| 65 | - response = IotStandardResponse.error( | |
| 66 | - reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); | |
| 64 | + response = IotStandardResponse.error(reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); | |
| 67 | 65 | } |
| 68 | 66 | IotPluginCommonUtils.writeJsonResponse(routingContext, response); |
| 69 | 67 | } catch (Exception e) { |
| 70 | 68 | log.error("[handle][请求参数({}) 属性设置异常]", reqDTO, e); |
| 71 | - // 使用IotStandardResponse实体类返回错误 | |
| 72 | 69 | IotStandardResponse errorResponse = IotStandardResponse.error( |
| 73 | 70 | reqDTO.getRequestId(), METHOD, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); |
| 74 | 71 | 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/downstream/router/IotDeviceServiceInvokeVertxHandler.java
| ... | ... | @@ -48,7 +48,6 @@ public class IotDeviceServiceInvokeVertxHandler implements Handler<RoutingContex |
| 48 | 48 | .setIdentifier(identifier).setParams(params); |
| 49 | 49 | } catch (Exception e) { |
| 50 | 50 | log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); |
| 51 | - // 使用IotStandardResponse实体类返回错误 | |
| 52 | 51 | String method = METHOD_PREFIX + routingContext.pathParam("identifier") + METHOD_SUFFIX; |
| 53 | 52 | IotStandardResponse errorResponse = IotStandardResponse.error( |
| 54 | 53 | null, method, BAD_REQUEST.getCode(), BAD_REQUEST.getMsg()); |
| ... | ... | @@ -60,19 +59,17 @@ public class IotDeviceServiceInvokeVertxHandler implements Handler<RoutingContex |
| 60 | 59 | try { |
| 61 | 60 | CommonResult<Boolean> result = deviceDownstreamHandler.invokeDeviceService(reqDTO); |
| 62 | 61 | |
| 63 | - // 使用IotStandardResponse实体类返回结果 | |
| 62 | + // 3. 响应结果 | |
| 64 | 63 | String method = METHOD_PREFIX + reqDTO.getIdentifier() + METHOD_SUFFIX; |
| 65 | 64 | IotStandardResponse response; |
| 66 | 65 | if (result.isSuccess()) { |
| 67 | 66 | response = IotStandardResponse.success(reqDTO.getRequestId(), method, result.getData()); |
| 68 | 67 | } else { |
| 69 | - response = IotStandardResponse.error( | |
| 70 | - reqDTO.getRequestId(), method, result.getCode(), result.getMsg()); | |
| 68 | + response = IotStandardResponse.error(reqDTO.getRequestId(), method, result.getCode(), result.getMsg()); | |
| 71 | 69 | } |
| 72 | 70 | IotPluginCommonUtils.writeJsonResponse(routingContext, response); |
| 73 | 71 | } catch (Exception e) { |
| 74 | 72 | log.error("[handle][请求参数({}) 服务调用异常]", reqDTO, e); |
| 75 | - // 使用IotStandardResponse实体类返回错误 | |
| 76 | 73 | String method = METHOD_PREFIX + reqDTO.getIdentifier() + METHOD_SUFFIX; |
| 77 | 74 | IotStandardResponse errorResponse = IotStandardResponse.error( |
| 78 | 75 | reqDTO.getRequestId(), method, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); | ... | ... |
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
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotEmqxPlugin.java
| ... | ... | @@ -10,10 +10,9 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext |
| 10 | 10 | /** |
| 11 | 11 | * EMQX 插件实现类 |
| 12 | 12 | * |
| 13 | - * 基于 PF4J 插件框架,实现 EMQX 消息中间件的集成 | |
| 14 | - * 负责插件的生命周期管理,包括启动、停止和应用上下文的创建 | |
| 13 | + * 基于 PF4J 插件框架,实现 EMQX 消息中间件的集成:负责插件的生命周期管理,包括启动、停止和应用上下文的创建 | |
| 15 | 14 | * |
| 16 | - * @author 芋道源码 | |
| 15 | + * @author haohao | |
| 17 | 16 | */ |
| 18 | 17 | @Slf4j |
| 19 | 18 | public class IotEmqxPlugin extends SpringPlugin { |
| ... | ... | @@ -26,7 +25,6 @@ public class IotEmqxPlugin extends SpringPlugin { |
| 26 | 25 | public void start() { |
| 27 | 26 | log.info("[EmqxPlugin][EmqxPlugin 插件启动开始...]"); |
| 28 | 27 | try { |
| 29 | - | |
| 30 | 28 | log.info("[EmqxPlugin][EmqxPlugin 插件启动成功...]"); |
| 31 | 29 | } catch (Exception e) { |
| 32 | 30 | log.error("[EmqxPlugin][EmqxPlugin 插件开启动异常...]", e); |
| ... | ... | @@ -52,6 +50,7 @@ public class IotEmqxPlugin extends SpringPlugin { |
| 52 | 50 | // 继续使用插件自己的 ClassLoader 以加载插件内部的类 |
| 53 | 51 | pluginContext.setClassLoader(getWrapper().getPluginClassLoader()); |
| 54 | 52 | // 扫描当前插件的自动配置包 |
| 53 | + // TODO @芋艿:是不是要配置下包 | |
| 55 | 54 | pluginContext.scan("cn.iocoder.yudao.module.iot.plugin.emqx.config"); |
| 56 | 55 | pluginContext.refresh(); |
| 57 | 56 | return pluginContext; | ... | ... |
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
| ... | ... | @@ -17,7 +17,6 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.MQTT_TOPIC_IL |
| 17 | 17 | |
| 18 | 18 | /** |
| 19 | 19 | * EMQX 插件的 {@link IotDeviceDownstreamHandler} 实现类 |
| 20 | - * <p> | |
| 21 | 20 | * |
| 22 | 21 | * @author 芋道源码 |
| 23 | 22 | */ |
| ... | ... | @@ -26,8 +25,7 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle |
| 26 | 25 | |
| 27 | 26 | private static final String SYS_TOPIC_PREFIX = "/sys/"; |
| 28 | 27 | |
| 29 | - // TODO @haohao:讨论,感觉 mqtt 和 http,可以做个相对统一的格式哈。 | |
| 30 | - // 回复 都使用 Alink 格式,方便后续扩展。 | |
| 28 | + // TODO @haohao:讨论,感觉 mqtt 和 http,可以做个相对统一的格式哈。;回复 都使用 Alink 格式,方便后续扩展。 | |
| 31 | 29 | // 设备服务调用 标准 JSON |
| 32 | 30 | // 请求Topic:/sys/${productKey}/${deviceName}/thing/service/${tsl.service.identifier} |
| 33 | 31 | // 响应Topic:/sys/${productKey}/${deviceName}/thing/service/${tsl.service.identifier}_reply |
| ... | ... | @@ -62,11 +60,8 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle |
| 62 | 60 | try { |
| 63 | 61 | // 构建请求主题 |
| 64 | 62 | String topic = buildServiceTopic(reqDTO.getProductKey(), reqDTO.getDeviceName(), reqDTO.getIdentifier()); |
| 65 | - | |
| 66 | - // 生成请求ID(如果没有提供) | |
| 67 | - String requestId = reqDTO.getRequestId() != null ? reqDTO.getRequestId() : generateRequestId(); | |
| 68 | - | |
| 69 | 63 | // 构建请求消息 |
| 64 | + String requestId = reqDTO.getRequestId() != null ? reqDTO.getRequestId() : generateRequestId(); | |
| 70 | 65 | JSONObject request = buildServiceRequest(requestId, reqDTO.getIdentifier(), reqDTO.getParams()); |
| 71 | 66 | |
| 72 | 67 | // 发送消息 |
| ... | ... | @@ -98,11 +93,8 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle |
| 98 | 93 | try { |
| 99 | 94 | // 构建请求主题 |
| 100 | 95 | String topic = buildPropertySetTopic(reqDTO.getProductKey(), reqDTO.getDeviceName()); |
| 101 | - | |
| 102 | - // 生成请求ID(如果没有提供) | |
| 103 | - String requestId = reqDTO.getRequestId() != null ? reqDTO.getRequestId() : generateRequestId(); | |
| 104 | - | |
| 105 | 96 | // 构建请求消息 |
| 97 | + String requestId = reqDTO.getRequestId() != null ? reqDTO.getRequestId() : generateRequestId(); | |
| 106 | 98 | JSONObject request = buildPropertySetRequest(requestId, reqDTO.getProperties()); |
| 107 | 99 | |
| 108 | 100 | // 发送消息 |
| ... | ... | @@ -163,7 +155,7 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle |
| 163 | 155 | } |
| 164 | 156 | |
| 165 | 157 | /** |
| 166 | - * 发布MQTT消息 | |
| 158 | + * 发布 MQTT 消息 | |
| 167 | 159 | */ |
| 168 | 160 | private void publishMessage(String topic, JSONObject payload) { |
| 169 | 161 | mqttClient.publish( | ... | ... |
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
| ... | ... | @@ -13,13 +13,12 @@ import lombok.extern.slf4j.Slf4j; |
| 13 | 13 | import java.util.Collections; |
| 14 | 14 | |
| 15 | 15 | /** |
| 16 | - * IoT Emqx 连接认证的 Vert.x Handler | |
| 17 | - * <a href= | |
| 18 | - * "https://docs.emqx.com/zh/emqx/latest/access-control/authn/http.html">MQTT | |
| 19 | - * HTTP</a> | |
| 16 | + * IoT EMQX 连接认证的 Vert.x Handler | |
| 17 | + * | |
| 18 | + * <a href="https://docs.emqx.com/zh/emqx/latest/access-control/authn/http.html">EMQX HTTP</a> | |
| 20 | 19 | * |
| 21 | 20 | * 注意:该处理器需要返回特定格式:{"result": "allow"} 或 {"result": "deny"}, |
| 22 | - * 以符合 EMQX 认证插件的要求,因此不使用 IotStandardResponse 实体类。 | |
| 21 | + * 以符合 EMQX 认证插件的要求,因此不使用 IotStandardResponse 实体类 | |
| 23 | 22 | * |
| 24 | 23 | * @author haohao |
| 25 | 24 | */ | ... | ... |
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
| 1 | 1 | package cn.iocoder.yudao.module.iot.plugin.emqx.upstream.router; |
| 2 | 2 | |
| 3 | +import cn.hutool.core.util.StrUtil; | |
| 3 | 4 | import cn.hutool.json.JSONObject; |
| 4 | 5 | import cn.hutool.json.JSONUtil; |
| 5 | 6 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| ... | ... | @@ -21,26 +22,20 @@ import java.util.Map; |
| 21 | 22 | |
| 22 | 23 | /** |
| 23 | 24 | * IoT 设备 MQTT 消息处理器 |
| 24 | - * <p> | |
| 25 | - * 参考: | |
| 26 | - * <p> | |
| 27 | - * "<a href= | |
| 28 | - * "https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services?spm=a2c4g.11186623.0.0.97a72915vRck44#section-g4j-5zg-12b">...</a>"> | |
| 25 | + * | |
| 26 | + * 参考:"<a href="https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services">设备属性、事件、服务</a>"> | |
| 29 | 27 | */ |
| 30 | 28 | @Slf4j |
| 31 | 29 | public class IotDeviceMqttMessageHandler { |
| 32 | 30 | |
| 33 | - // TODO @haohao:讨论,感觉 mqtt 和 http,可以做个相对统一的格式哈。 | |
| 34 | - // 回复 都使用 Alink 格式,方便后续扩展。 | |
| 31 | + // TODO @haohao:讨论,感觉 mqtt 和 http,可以做个相对统一的格式哈;回复 都使用 Alink 格式,方便后续扩展。 | |
| 35 | 32 | // 设备上报属性 标准 JSON |
| 36 | 33 | // 请求 Topic:/sys/${productKey}/${deviceName}/thing/event/property/post |
| 37 | 34 | // 响应 Topic:/sys/${productKey}/${deviceName}/thing/event/property/post_reply |
| 38 | 35 | |
| 39 | 36 | // 设备上报事件 标准 JSON |
| 40 | - // 请求 | |
| 41 | - // Topic:/sys/${productKey}/${deviceName}/thing/event/${tsl.event.identifier}/post | |
| 42 | - // 响应 | |
| 43 | - // Topic:/sys/${productKey}/${deviceName}/thing/event/${tsl.event.identifier}/post_reply | |
| 37 | + // 请求 Topic:/sys/${productKey}/${deviceName}/thing/event/${tsl.event.identifier}/post | |
| 38 | + // 响应 Topic:/sys/${productKey}/${deviceName}/thing/event/${tsl.event.identifier}/post_reply | |
| 44 | 39 | |
| 45 | 40 | private static final String SYS_TOPIC_PREFIX = "/sys/"; |
| 46 | 41 | private static final String PROPERTY_POST_TOPIC = "/thing/event/property/post"; |
| ... | ... | @@ -70,7 +65,7 @@ public class IotDeviceMqttMessageHandler { |
| 70 | 65 | log.info("[messageHandler][接收到消息][topic: {}][payload: {}]", topic, payload); |
| 71 | 66 | |
| 72 | 67 | try { |
| 73 | - if (payload == null || payload.isEmpty()) { | |
| 68 | + if (StrUtil.isEmpty(payload)) { | |
| 74 | 69 | log.warn("[messageHandler][消息内容为空][topic: {}]", topic); |
| 75 | 70 | return; |
| 76 | 71 | } |
| ... | ... | @@ -214,27 +209,20 @@ public class IotDeviceMqttMessageHandler { |
| 214 | 209 | * @param topic 原始主题 |
| 215 | 210 | * @param jsonObject 原始消息JSON对象 |
| 216 | 211 | * @param method 响应方法 |
| 217 | - * @param customData 自定义数据,可为null | |
| 212 | + * @param customData 自定义数据,可为 null | |
| 218 | 213 | */ |
| 219 | 214 | private void sendResponse(String topic, JSONObject jsonObject, String method, Object customData) { |
| 220 | 215 | String replyTopic = topic + REPLY_SUFFIX; |
| 221 | 216 | |
| 222 | - // 使用IotStandardResponse实体类构建响应 | |
| 217 | + // 响应结果 | |
| 223 | 218 | IotStandardResponse response = IotStandardResponse.success( |
| 224 | - jsonObject.getStr("id"), | |
| 225 | - method, | |
| 226 | - customData); | |
| 227 | - | |
| 219 | + jsonObject.getStr("id"), method, customData); | |
| 228 | 220 | try { |
| 229 | - mqttClient.publish(replyTopic, | |
| 230 | - Buffer.buffer(JsonUtils.toJsonString(response)), | |
| 231 | - MqttQoS.AT_LEAST_ONCE, | |
| 232 | - false, | |
| 233 | - false); | |
| 221 | + mqttClient.publish(replyTopic, Buffer.buffer(JsonUtils.toJsonString(response)), | |
| 222 | + MqttQoS.AT_LEAST_ONCE, false, false); | |
| 234 | 223 | log.info("[sendResponse][发送响应消息成功][topic: {}]", replyTopic); |
| 235 | 224 | } catch (Exception e) { |
| 236 | - log.error("[sendResponse][发送响应消息失败][topic: {}][response: {}]", | |
| 237 | - replyTopic, response, e); | |
| 225 | + log.error("[sendResponse][发送响应消息失败][topic: {}][response: {}]", replyTopic, response, e); | |
| 238 | 226 | } |
| 239 | 227 | } |
| 240 | 228 | |
| ... | ... | @@ -304,4 +292,5 @@ public class IotDeviceMqttMessageHandler { |
| 304 | 292 | |
| 305 | 293 | return reportReqDTO; |
| 306 | 294 | } |
| 295 | + | |
| 307 | 296 | } |
| 308 | 297 | \ 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/IotDeviceWebhookVertxHandler.java
| ... | ... | @@ -16,13 +16,12 @@ import java.time.LocalDateTime; |
| 16 | 16 | import java.util.Collections; |
| 17 | 17 | |
| 18 | 18 | /** |
| 19 | - * IoT Emqx Webhook 事件处理的 Vert.x Handler | |
| 19 | + * IoT EMQX Webhook 事件处理的 Vert.x Handler | |
| 20 | 20 | * |
| 21 | - * <a href= | |
| 22 | - * "https://docs.emqx.com/zh/emqx/latest/data-integration/webhook.html">EMQXWebhook</a> | |
| 21 | + * <a href="https://docs.emqx.com/zh/emqx/latest/data-integration/webhook.html">EMQX Webhook</a> | |
| 23 | 22 | * |
| 24 | 23 | * 注意:该处理器需要返回特定格式:{"result": "success"} 或 {"result": "error"}, |
| 25 | - * 以符合 EMQX Webhook 插件的要求,因此不使用 IotStandardResponse 实体类。 | |
| 24 | + * 以符合 EMQX Webhook 插件的要求,因此不使用 IotStandardResponse 实体类。 | |
| 26 | 25 | * |
| 27 | 26 | * @author haohao |
| 28 | 27 | */ |
| ... | ... | @@ -137,7 +136,7 @@ public class IotDeviceWebhookVertxHandler implements Handler<RoutingContext> { |
| 137 | 136 | * 解析用户名,格式为 deviceName&productKey |
| 138 | 137 | * |
| 139 | 138 | * @param username 用户名 |
| 140 | - * @return 解析结果,[0] 为 deviceName,[1] 为productKey,解析失败返回 null | |
| 139 | + * @return 解析结果,[0] 为 deviceName,[1] 为 productKey,解析失败返回 null | |
| 141 | 140 | */ |
| 142 | 141 | private String[] parseUsername(String username) { |
| 143 | 142 | if (StrUtil.isEmpty(username)) { | ... | ... |
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,9 +34,13 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC |
| 34 | 34 | @Slf4j |
| 35 | 35 | public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> { |
| 36 | 36 | |
| 37 | - // 属性上报路径 | |
| 37 | + /** | |
| 38 | + * 属性上报路径 | |
| 39 | + */ | |
| 38 | 40 | public static final String PROPERTY_PATH = "/sys/:productKey/:deviceName/thing/event/property/post"; |
| 39 | - // 事件上报路径 | |
| 41 | + /** | |
| 42 | + * 事件上报路径 | |
| 43 | + */ | |
| 40 | 44 | public static final String EVENT_PATH = "/sys/:productKey/:deviceName/thing/event/:identifier/post"; |
| 41 | 45 | |
| 42 | 46 | private static final String PROPERTY_METHOD = "thing.event.property.post"; |
| ... | ... | @@ -60,7 +64,6 @@ public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> { |
| 60 | 64 | // 2. 根据路径模式处理不同类型的请求 |
| 61 | 65 | CommonResult<Boolean> result; |
| 62 | 66 | String method; |
| 63 | - | |
| 64 | 67 | if (path.matches(".*/thing/event/property/post")) { |
| 65 | 68 | // 处理属性上报 |
| 66 | 69 | IotDevicePropertyReportReqDTO reportReqDTO = parsePropertyReportRequest(productKey, deviceName, requestId, body); |
| ... | ... | @@ -97,13 +100,13 @@ public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> { |
| 97 | 100 | response = IotStandardResponse.error(requestId, method, result.getCode(), result.getMsg()); |
| 98 | 101 | } |
| 99 | 102 | IotPluginCommonUtils.writeJsonResponse(routingContext, response); |
| 100 | - | |
| 101 | 103 | } catch (Exception e) { |
| 102 | 104 | log.error("[handle][处理上行请求异常] path={}", path, e); |
| 103 | - | |
| 104 | 105 | // 构建错误响应 |
| 105 | - String method = path.contains("/property/") ? PROPERTY_METHOD : EVENT_METHOD_PREFIX + (routingContext.pathParams().containsKey("identifier") ? routingContext.pathParam("identifier") : "unknown") + EVENT_METHOD_SUFFIX; | |
| 106 | - | |
| 106 | + String method = path.contains("/property/") ? PROPERTY_METHOD | |
| 107 | + : EVENT_METHOD_PREFIX + (routingContext.pathParams().containsKey("identifier") | |
| 108 | + ? routingContext.pathParam("identifier") | |
| 109 | + : "unknown") + EVENT_METHOD_SUFFIX; | |
| 107 | 110 | IotStandardResponse errorResponse = IotStandardResponse.error(requestId, method, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); |
| 108 | 111 | IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); |
| 109 | 112 | } |
| ... | ... | @@ -130,20 +133,16 @@ public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> { |
| 130 | 133 | */ |
| 131 | 134 | @SuppressWarnings("unchecked") |
| 132 | 135 | private IotDevicePropertyReportReqDTO parsePropertyReportRequest(String productKey, String deviceName, String requestId, JsonObject body) { |
| 133 | - | |
| 134 | - // 按照标准JSON格式处理属性数据 | |
| 136 | + // 按照标准 JSON 格式处理属性数据 | |
| 135 | 137 | Map<String, Object> properties = new HashMap<>(); |
| 136 | - | |
| 137 | - // 优先使用params字段,符合标准 | |
| 138 | + // 优先使用 params 字段,符合标准 | |
| 138 | 139 | Map<String, Object> params = body.getJsonObject("params") != null ? body.getJsonObject("params").getMap() : null; |
| 139 | - | |
| 140 | 140 | if (params != null) { |
| 141 | - // 将标准格式的params转换为平台需要的properties格式 | |
| 141 | + // 将标准格式的 params 转换为平台需要的 properties 格式 | |
| 142 | 142 | for (Map.Entry<String, Object> entry : params.entrySet()) { |
| 143 | 143 | String key = entry.getKey(); |
| 144 | 144 | Object valueObj = entry.getValue(); |
| 145 | - | |
| 146 | - // 如果是复杂结构(包含value和time) | |
| 145 | + // 如果是复杂结构(包含 value 和 time) | |
| 147 | 146 | if (valueObj instanceof Map) { |
| 148 | 147 | Map<String, Object> valueMap = (Map<String, Object>) valueObj; |
| 149 | 148 | properties.put(key, valueMap.getOrDefault("value", valueObj)); |
| ... | ... | @@ -153,6 +152,7 @@ public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> { |
| 153 | 152 | } |
| 154 | 153 | } |
| 155 | 154 | |
| 155 | + // 构建属性上报请求 DTO | |
| 156 | 156 | return ((IotDevicePropertyReportReqDTO) new IotDevicePropertyReportReqDTO().setRequestId(requestId).setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()).setProductKey(productKey).setDeviceName(deviceName)).setProperties(properties); |
| 157 | 157 | } |
| 158 | 158 | |
| ... | ... | @@ -166,12 +166,9 @@ public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> { |
| 166 | 166 | * @param body 请求体 |
| 167 | 167 | * @return 事件上报请求DTO |
| 168 | 168 | */ |
| 169 | - @SuppressWarnings("unchecked") | |
| 170 | 169 | private IotDeviceEventReportReqDTO parseEventReportRequest(String productKey, String deviceName, String identifier, String requestId, JsonObject body) { |
| 171 | - | |
| 172 | 170 | // 按照标准JSON格式处理事件参数 |
| 173 | 171 | Map<String, Object> params; |
| 174 | - | |
| 175 | 172 | // 优先使用params字段,符合标准 |
| 176 | 173 | if (body.getJsonObject("params") != null) { |
| 177 | 174 | params = body.getJsonObject("params").getMap(); |
| ... | ... | @@ -180,6 +177,7 @@ public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> { |
| 180 | 177 | params = new HashMap<>(); |
| 181 | 178 | } |
| 182 | 179 | |
| 180 | + // 构建事件上报请求 DTO | |
| 183 | 181 | return ((IotDeviceEventReportReqDTO) new IotDeviceEventReportReqDTO().setRequestId(requestId).setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()).setProductKey(productKey).setDeviceName(deviceName)).setIdentifier(identifier).setParams(params); |
| 184 | 182 | } |
| 185 | 183 | } |
| 186 | 184 | \ No newline at end of file | ... | ... |