Commit 3ca4cf265a0323bc06768a5be88955b1a9c1cdda
1 parent
bf41d47f
feat:【IoT 物联网】优化根据消息方法和回复状态构建主题逻辑
Showing
2 changed files
with
20 additions
and
138 deletions
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java
| ... | ... | @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.iot.gateway.protocol.emqx.router; |
| 3 | 3 | import cn.hutool.core.util.StrUtil; |
| 4 | 4 | import cn.hutool.extra.spring.SpringUtil; |
| 5 | 5 | import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceRespDTO; |
| 6 | -import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; | |
| 7 | 6 | import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; |
| 8 | 7 | import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils; |
| 9 | 8 | import cn.iocoder.yudao.module.iot.gateway.protocol.emqx.IotEmqxUpstreamProtocol; |
| ... | ... | @@ -69,58 +68,11 @@ public class IotEmqxDownstreamHandler { |
| 69 | 68 | * @return 构建的主题,如果方法不支持返回 null |
| 70 | 69 | */ |
| 71 | 70 | private String buildTopicByMethod(IotDeviceMessage message, String productKey, String deviceName) { |
| 72 | - // 1. 解析消息方法 | |
| 73 | - IotDeviceMessageMethodEnum methodEnum = IotDeviceMessageMethodEnum.of(message.getMethod()); | |
| 74 | - if (methodEnum == null) { | |
| 75 | - log.warn("[buildTopicByMethod][未知的消息方法: {}]", message.getMethod()); | |
| 76 | - return null; | |
| 77 | - } | |
| 78 | - | |
| 79 | - // 2. 根据消息方法和回复状态,构建 topic | |
| 71 | + // 1. 判断是否为回复消息 | |
| 80 | 72 | boolean isReply = IotDeviceMessageUtils.isReplyMessage(message); |
| 81 | 73 | |
| 82 | - // TODO @haohao:看看基于 message 的 method 去反向推导; | |
| 83 | - // 3. 根据消息方法类型构建对应的主题 | |
| 84 | - switch (methodEnum) { | |
| 85 | - case PROPERTY_POST: | |
| 86 | - // 属性上报:只支持回复消息(下行) | |
| 87 | - if (isReply) { | |
| 88 | - return IotMqttTopicUtils.buildPropertyPostReplyTopic(productKey, deviceName); | |
| 89 | - } | |
| 90 | - break; | |
| 91 | - case PROPERTY_SET: | |
| 92 | - // 属性设置:只支持非回复消息(下行) | |
| 93 | - if (!isReply) { | |
| 94 | - return IotMqttTopicUtils.buildPropertySetTopic(productKey, deviceName); | |
| 95 | - } | |
| 96 | - break; | |
| 97 | - case EVENT_POST: | |
| 98 | - // 事件上报:只支持回复消息(下行) | |
| 99 | - if (isReply) { | |
| 100 | - return IotMqttTopicUtils.buildEventPostReplyTopicGeneric(productKey, deviceName); | |
| 101 | - } | |
| 102 | - break; | |
| 103 | - case SERVICE_INVOKE: | |
| 104 | - // 服务调用:支持请求和回复 | |
| 105 | - if (isReply) { | |
| 106 | - return IotMqttTopicUtils.buildServiceReplyTopicGeneric(productKey, deviceName); | |
| 107 | - } else { | |
| 108 | - return IotMqttTopicUtils.buildServiceTopicGeneric(productKey, deviceName); | |
| 109 | - } | |
| 110 | - case CONFIG_PUSH: | |
| 111 | - // 配置推送:平台向设备推送配置(下行请求),设备回复确认(上行回复) | |
| 112 | - if (!isReply) { | |
| 113 | - return IotMqttTopicUtils.buildConfigPushTopic(productKey, deviceName); | |
| 114 | - } | |
| 115 | - break; | |
| 116 | - default: | |
| 117 | - log.warn("[buildTopicByMethod][未处理的消息方法: {}]", methodEnum); | |
| 118 | - break; | |
| 119 | - } | |
| 120 | - | |
| 121 | - log.warn("[buildTopicByMethod][暂时不支持的下行消息: method={}, isReply={}]", | |
| 122 | - message.getMethod(), isReply); | |
| 123 | - return null; | |
| 74 | + // 2. 根据消息方法类型构建对应的主题 | |
| 75 | + return IotMqttTopicUtils.buildTopicByMethod(message.getMethod(), productKey, deviceName, isReply); | |
| 124 | 76 | } |
| 125 | 77 | |
| 126 | 78 | } |
| 127 | 79 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/util/IotMqttTopicUtils.java
| 1 | 1 | package cn.iocoder.yudao.module.iot.gateway.util; |
| 2 | 2 | |
| 3 | +import cn.hutool.core.util.StrUtil; | |
| 4 | + | |
| 3 | 5 | /** |
| 4 | 6 | * IoT 网关 MQTT 主题工具类 |
| 5 | 7 | * <p> |
| ... | ... | @@ -16,12 +18,6 @@ public final class IotMqttTopicUtils { |
| 16 | 18 | */ |
| 17 | 19 | private static final String SYS_TOPIC_PREFIX = "/sys/"; |
| 18 | 20 | |
| 19 | - // TODO @haohao:这个要删除哇? | |
| 20 | - /** | |
| 21 | - * 服务调用主题前缀 | |
| 22 | - */ | |
| 23 | - private static final String SERVICE_TOPIC_PREFIX = "/thing/"; | |
| 24 | - | |
| 25 | 21 | // ========== MQTT HTTP 接口路径常量 ========== |
| 26 | 22 | |
| 27 | 23 | /** |
| ... | ... | @@ -37,98 +33,32 @@ public final class IotMqttTopicUtils { |
| 37 | 33 | */ |
| 38 | 34 | public static final String MQTT_EVENT_PATH = "/mqtt/event"; |
| 39 | 35 | |
| 40 | - // TODO @haohao:这个要删除哇? | |
| 41 | - /** | |
| 42 | - * MQTT 授权接口路径(预留) | |
| 43 | - * 对应 EMQX HTTP 授权插件的授权检查接口 | |
| 44 | - */ | |
| 45 | - public static final String MQTT_AUTHZ_PATH = "/mqtt/authz"; | |
| 46 | - | |
| 47 | 36 | // ========== 工具方法 ========== |
| 48 | 37 | |
| 49 | 38 | /** |
| 50 | - * 构建设备主题前缀 | |
| 51 | - * | |
| 52 | - * @param productKey 产品 Key | |
| 53 | - * @param deviceName 设备名称 | |
| 54 | - * @return 设备主题前缀:/sys/{productKey}/{deviceName} | |
| 55 | - */ | |
| 56 | - private static String buildDeviceTopicPrefix(String productKey, String deviceName) { | |
| 57 | - return SYS_TOPIC_PREFIX + productKey + "/" + deviceName; | |
| 58 | - } | |
| 59 | - | |
| 60 | - /** | |
| 61 | - * 构建设备属性设置主题 | |
| 39 | + * 根据消息方法构建对应的主题 | |
| 62 | 40 | * |
| 41 | + * @param method 消息方法,例如 thing.property.post | |
| 63 | 42 | * @param productKey 产品 Key |
| 64 | 43 | * @param deviceName 设备名称 |
| 44 | + * @param isReply 是否为回复消息 | |
| 65 | 45 | * @return 完整的主题路径 |
| 66 | 46 | */ |
| 67 | - public static String buildPropertySetTopic(String productKey, String deviceName) { | |
| 68 | - return buildDeviceTopicPrefix(productKey, deviceName) + "/thing/property/set"; | |
| 69 | - } | |
| 47 | + public static String buildTopicByMethod(String method, String productKey, String deviceName, boolean isReply) { | |
| 48 | + if (StrUtil.isBlank(method)) { | |
| 49 | + return null; | |
| 50 | + } | |
| 70 | 51 | |
| 71 | - /** | |
| 72 | - * 构建设备属性上报回复主题 | |
| 73 | - * <p> | |
| 74 | - * 当设备上报属性时,会收到该主题的回复 | |
| 75 | - * | |
| 76 | - * @param productKey 产品 Key | |
| 77 | - * @param deviceName 设备名称 | |
| 78 | - * @return 完整的主题路径 | |
| 79 | - */ | |
| 80 | - public static String buildPropertyPostReplyTopic(String productKey, String deviceName) { | |
| 81 | - return buildDeviceTopicPrefix(productKey, deviceName) + "/thing/property/post_reply"; | |
| 82 | - } | |
| 52 | + // 1. 将点分隔符转换为斜杠 | |
| 53 | + String topicSuffix = method.replace('.', '/'); | |
| 83 | 54 | |
| 84 | - /** | |
| 85 | - * 构建设备配置推送主题 | |
| 86 | - * | |
| 87 | - * @param productKey 产品 Key | |
| 88 | - * @param deviceName 设备名称 | |
| 89 | - * @return 完整的主题路径 | |
| 90 | - */ | |
| 91 | - public static String buildConfigPushTopic(String productKey, String deviceName) { | |
| 92 | - return buildDeviceTopicPrefix(productKey, deviceName) + "/thing/config/push"; | |
| 93 | - } | |
| 55 | + // 2. 对于回复消息,添加 _reply 后缀 | |
| 56 | + if (isReply) { | |
| 57 | + topicSuffix += "_reply"; | |
| 58 | + } | |
| 94 | 59 | |
| 95 | - /** | |
| 96 | - * 构建设备事件上报通用回复主题 | |
| 97 | - * <p> | |
| 98 | - * 不包含具体的事件标识符,事件标识符通过消息 data 中的 identifier 字段传递 | |
| 99 | - * | |
| 100 | - * @param productKey 产品 Key | |
| 101 | - * @param deviceName 设备名称 | |
| 102 | - * @return 完整的主题路径 | |
| 103 | - */ | |
| 104 | - public static String buildEventPostReplyTopicGeneric(String productKey, String deviceName) { | |
| 105 | - return buildDeviceTopicPrefix(productKey, deviceName) + "/thing/event/post_reply"; | |
| 106 | - } | |
| 107 | - | |
| 108 | - /** | |
| 109 | - * 构建设备服务调用通用主题 | |
| 110 | - * <p> | |
| 111 | - * 不包含具体的服务标识符,服务标识符通过消息 data 中的 identifier 字段传递 | |
| 112 | - * | |
| 113 | - * @param productKey 产品 Key | |
| 114 | - * @param deviceName 设备名称 | |
| 115 | - * @return 完整的主题路径 | |
| 116 | - */ | |
| 117 | - public static String buildServiceTopicGeneric(String productKey, String deviceName) { | |
| 118 | - return buildDeviceTopicPrefix(productKey, deviceName) + "/thing/service/invoke"; | |
| 119 | - } | |
| 120 | - | |
| 121 | - /** | |
| 122 | - * 构建设备服务调用通用回复主题 | |
| 123 | - * <p> | |
| 124 | - * 不包含具体的服务标识符,服务标识符通过消息 data 中的 identifier 字段传递 | |
| 125 | - * | |
| 126 | - * @param productKey 产品 Key | |
| 127 | - * @param deviceName 设备名称 | |
| 128 | - * @return 完整的主题路径 | |
| 129 | - */ | |
| 130 | - public static String buildServiceReplyTopicGeneric(String productKey, String deviceName) { | |
| 131 | - return buildDeviceTopicPrefix(productKey, deviceName) + "/thing/service/invoke_reply"; | |
| 60 | + // 3. 构建完整主题 | |
| 61 | + return SYS_TOPIC_PREFIX + productKey + "/" + deviceName + "/" + topicSuffix; | |
| 132 | 62 | } |
| 133 | 63 | |
| 134 | 64 | } |
| 135 | 65 | \ No newline at end of file | ... | ... |