Commit 006ef40c4b325b32e1aad54f55d7176e23554ad6
1 parent
4cefea68
【功能完善】IoT: 添加 MQTT 主题非法错误码,重构设备服务调用和属性设置逻辑,优化 MQTT 消息处理流程
Showing
5 changed files
with
450 additions
and
150 deletions
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
| ... | ... | @@ -67,4 +67,7 @@ public interface ErrorCodeConstants { |
| 67 | 67 | ErrorCode OTA_UPGRADE_RECORD_DUPLICATE = new ErrorCode(1_050_008_007, "升级记录重复"); |
| 68 | 68 | ErrorCode OTA_UPGRADE_RECORD_CANNOT_RETRY = new ErrorCode(1_050_008_008, "升级记录不能重试"); |
| 69 | 69 | |
| 70 | + // ========== MQTT 通信相关 1-050-009-000 ========== | |
| 71 | + ErrorCode MQTT_TOPIC_ILLEGAL = new ErrorCode(1_050_009_000, "topic illegal"); | |
| 72 | + | |
| 70 | 73 | } |
| 71 | 74 | \ 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/config/IotPluginEmqxAutoConfiguration.java
| 1 | 1 | package cn.iocoder.yudao.module.iot.plugin.emqx.config; |
| 2 | 2 | |
| 3 | +import cn.hutool.core.util.IdUtil; | |
| 3 | 4 | import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; |
| 4 | 5 | import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; |
| 5 | 6 | import cn.iocoder.yudao.module.iot.plugin.emqx.downstream.IotDeviceDownstreamHandlerImpl; |
| 6 | 7 | import cn.iocoder.yudao.module.iot.plugin.emqx.upstream.IotDeviceUpstreamServer; |
| 8 | +import io.vertx.core.Vertx; | |
| 9 | +import io.vertx.mqtt.MqttClient; | |
| 10 | +import io.vertx.mqtt.MqttClientOptions; | |
| 11 | +import lombok.extern.slf4j.Slf4j; | |
| 7 | 12 | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| 8 | 13 | import org.springframework.context.annotation.Bean; |
| 9 | 14 | import org.springframework.context.annotation.Configuration; |
| ... | ... | @@ -13,19 +18,37 @@ import org.springframework.context.annotation.Configuration; |
| 13 | 18 | * |
| 14 | 19 | * @author haohao |
| 15 | 20 | */ |
| 21 | +@Slf4j | |
| 16 | 22 | @Configuration |
| 17 | 23 | @EnableConfigurationProperties(IotPluginEmqxProperties.class) |
| 18 | 24 | public class IotPluginEmqxAutoConfiguration { |
| 19 | 25 | |
| 26 | + @Bean | |
| 27 | + public Vertx vertx() { | |
| 28 | + return Vertx.vertx(); | |
| 29 | + } | |
| 30 | + | |
| 31 | + @Bean | |
| 32 | + public MqttClient mqttClient(Vertx vertx, IotPluginEmqxProperties emqxProperties) { | |
| 33 | + MqttClientOptions options = new MqttClientOptions() | |
| 34 | + .setClientId("yudao-iot-downstream-" + IdUtil.fastSimpleUUID()) | |
| 35 | + .setUsername(emqxProperties.getMqttUsername()) | |
| 36 | + .setPassword(emqxProperties.getMqttPassword()) | |
| 37 | + .setSsl(emqxProperties.isMqttSsl()); | |
| 38 | + return MqttClient.create(vertx, options); | |
| 39 | + } | |
| 40 | + | |
| 20 | 41 | @Bean(initMethod = "start", destroyMethod = "stop") |
| 21 | 42 | public IotDeviceUpstreamServer deviceUpstreamServer(IotDeviceUpstreamApi deviceUpstreamApi, |
| 22 | - IotPluginEmqxProperties emqxProperties) { | |
| 23 | - return new IotDeviceUpstreamServer(emqxProperties, deviceUpstreamApi); | |
| 43 | + IotPluginEmqxProperties emqxProperties, | |
| 44 | + Vertx vertx, | |
| 45 | + MqttClient mqttClient) { | |
| 46 | + return new IotDeviceUpstreamServer(emqxProperties, deviceUpstreamApi, vertx, mqttClient); | |
| 24 | 47 | } |
| 25 | 48 | |
| 26 | 49 | @Bean |
| 27 | - public IotDeviceDownstreamHandler deviceDownstreamHandler() { | |
| 28 | - return new IotDeviceDownstreamHandlerImpl(); | |
| 50 | + public IotDeviceDownstreamHandler deviceDownstreamHandler(MqttClient mqttClient) { | |
| 51 | + return new IotDeviceDownstreamHandlerImpl(mqttClient); | |
| 29 | 52 | } |
| 30 | 53 | |
| 31 | 54 | -} |
| 55 | +} | |
| 32 | 56 | \ 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/downstream/IotDeviceDownstreamHandlerImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.iot.plugin.emqx.downstream; |
| 2 | 2 | |
| 3 | +import cn.hutool.core.util.IdUtil; | |
| 4 | +import cn.hutool.json.JSONObject; | |
| 5 | +import cn.hutool.json.JSONUtil; | |
| 3 | 6 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | 7 | import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.*; |
| 5 | 8 | import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; |
| 9 | +import io.netty.handler.codec.mqtt.MqttQoS; | |
| 10 | +import io.vertx.core.buffer.Buffer; | |
| 11 | +import io.vertx.mqtt.MqttClient; | |
| 12 | +import lombok.extern.slf4j.Slf4j; | |
| 13 | + | |
| 14 | +import java.util.Map; | |
| 15 | + | |
| 16 | +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.MQTT_TOPIC_ILLEGAL; | |
| 6 | 17 | |
| 7 | 18 | /** |
| 8 | 19 | * EMQX 插件的 {@link IotDeviceDownstreamHandler} 实现类 |
| ... | ... | @@ -10,14 +21,61 @@ import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamH |
| 10 | 21 | * |
| 11 | 22 | * @author 芋道源码 |
| 12 | 23 | */ |
| 24 | +@Slf4j | |
| 13 | 25 | public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandler { |
| 14 | 26 | |
| 27 | + private static final String SYS_TOPIC_PREFIX = "/sys/"; | |
| 28 | + | |
| 29 | + // 设备服务调用 标准 JSON | |
| 30 | + // 请求Topic:/sys/${productKey}/${deviceName}/thing/service/${tsl.service.identifier} | |
| 31 | + // 响应Topic:/sys/${productKey}/${deviceName}/thing/service/${tsl.service.identifier}_reply | |
| 32 | + private static final String SERVICE_TOPIC_PREFIX = "/thing/service/"; | |
| 33 | + | |
| 34 | + // 设置设备属性 标准 JSON | |
| 35 | + // 请求Topic:/sys/${productKey}/${deviceName}/thing/service/property/set | |
| 36 | + // 响应Topic:/sys/${productKey}/${deviceName}/thing/service/property/set_reply | |
| 37 | + private static final String PROPERTY_SET_TOPIC = "/thing/service/property/set"; | |
| 38 | + | |
| 39 | + private final MqttClient mqttClient; | |
| 40 | + | |
| 41 | + /** | |
| 42 | + * 构造函数 | |
| 43 | + * | |
| 44 | + * @param mqttClient MQTT客户端 | |
| 45 | + */ | |
| 46 | + public IotDeviceDownstreamHandlerImpl(MqttClient mqttClient) { | |
| 47 | + this.mqttClient = mqttClient; | |
| 48 | + } | |
| 49 | + | |
| 15 | 50 | @Override |
| 16 | - public CommonResult<Boolean> invokeDeviceService(IotDeviceServiceInvokeReqDTO invokeReqDTO) { | |
| 17 | - // 设备服务调用 | |
| 18 | - // 请求Topic:/sys/${productKey}/${deviceName}/thing/service/${tsl.service.identifier} | |
| 19 | - // 响应Topic:/sys/${productKey}/${deviceName}/thing/service/${tsl.service.identifier}_reply | |
| 20 | - return CommonResult.success(true); | |
| 51 | + public CommonResult<Boolean> invokeDeviceService(IotDeviceServiceInvokeReqDTO reqDTO) { | |
| 52 | + log.info("[invokeService][开始调用设备服务][reqDTO: {}]", JSONUtil.toJsonStr(reqDTO)); | |
| 53 | + | |
| 54 | + // 验证参数 | |
| 55 | + if (reqDTO.getProductKey() == null || reqDTO.getDeviceName() == null || reqDTO.getIdentifier() == null) { | |
| 56 | + log.error("[invokeService][参数不完整][reqDTO: {}]", JSONUtil.toJsonStr(reqDTO)); | |
| 57 | + return CommonResult.error(MQTT_TOPIC_ILLEGAL.getCode(), MQTT_TOPIC_ILLEGAL.getMsg()); | |
| 58 | + } | |
| 59 | + | |
| 60 | + try { | |
| 61 | + // 构建请求主题 | |
| 62 | + String topic = buildServiceTopic(reqDTO.getProductKey(), reqDTO.getDeviceName(), reqDTO.getIdentifier()); | |
| 63 | + | |
| 64 | + // 生成请求ID(如果没有提供) | |
| 65 | + String requestId = reqDTO.getRequestId() != null ? reqDTO.getRequestId() : generateRequestId(); | |
| 66 | + | |
| 67 | + // 构建请求消息 | |
| 68 | + JSONObject request = buildServiceRequest(requestId, reqDTO.getIdentifier(), reqDTO.getParams()); | |
| 69 | + | |
| 70 | + // 发送消息 | |
| 71 | + publishMessage(topic, request); | |
| 72 | + | |
| 73 | + log.info("[invokeService][调用设备服务成功][requestId: {}][topic: {}]", requestId, topic); | |
| 74 | + return CommonResult.success(true); | |
| 75 | + } catch (Exception e) { | |
| 76 | + log.error("[invokeService][调用设备服务异常][reqDTO: {}]", JSONUtil.toJsonStr(reqDTO), e); | |
| 77 | + return CommonResult.error(MQTT_TOPIC_ILLEGAL.getCode(), MQTT_TOPIC_ILLEGAL.getMsg()); | |
| 78 | + } | |
| 21 | 79 | } |
| 22 | 80 | |
| 23 | 81 | @Override |
| ... | ... | @@ -26,11 +84,34 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle |
| 26 | 84 | } |
| 27 | 85 | |
| 28 | 86 | @Override |
| 29 | - public CommonResult<Boolean> setDeviceProperty(IotDevicePropertySetReqDTO setReqDTO) { | |
| 30 | - // 设置设备属性 标准 JSON | |
| 31 | - // 请求Topic:/sys/${productKey}/${deviceName}/thing/service/property/set | |
| 32 | - // 响应Topic:/sys/${productKey}/${deviceName}/thing/service/property/set_reply | |
| 33 | - return CommonResult.success(true); | |
| 87 | + public CommonResult<Boolean> setDeviceProperty(IotDevicePropertySetReqDTO reqDTO) { | |
| 88 | + log.info("[setProperty][开始设置设备属性][reqDTO: {}]", JSONUtil.toJsonStr(reqDTO)); | |
| 89 | + | |
| 90 | + // 验证参数 | |
| 91 | + if (reqDTO.getProductKey() == null || reqDTO.getDeviceName() == null) { | |
| 92 | + log.error("[setProperty][参数不完整][reqDTO: {}]", JSONUtil.toJsonStr(reqDTO)); | |
| 93 | + return CommonResult.error(MQTT_TOPIC_ILLEGAL.getCode(), MQTT_TOPIC_ILLEGAL.getMsg()); | |
| 94 | + } | |
| 95 | + | |
| 96 | + try { | |
| 97 | + // 构建请求主题 | |
| 98 | + String topic = buildPropertySetTopic(reqDTO.getProductKey(), reqDTO.getDeviceName()); | |
| 99 | + | |
| 100 | + // 生成请求ID(如果没有提供) | |
| 101 | + String requestId = reqDTO.getRequestId() != null ? reqDTO.getRequestId() : generateRequestId(); | |
| 102 | + | |
| 103 | + // 构建请求消息 | |
| 104 | + JSONObject request = buildPropertySetRequest(requestId, reqDTO.getProperties()); | |
| 105 | + | |
| 106 | + // 发送消息 | |
| 107 | + publishMessage(topic, request); | |
| 108 | + | |
| 109 | + log.info("[setProperty][设置设备属性成功][requestId: {}][topic: {}]", requestId, topic); | |
| 110 | + return CommonResult.success(true); | |
| 111 | + } catch (Exception e) { | |
| 112 | + log.error("[setProperty][设置设备属性异常][reqDTO: {}]", JSONUtil.toJsonStr(reqDTO), e); | |
| 113 | + return CommonResult.error(MQTT_TOPIC_ILLEGAL.getCode(), MQTT_TOPIC_ILLEGAL.getMsg()); | |
| 114 | + } | |
| 34 | 115 | } |
| 35 | 116 | |
| 36 | 117 | @Override |
| ... | ... | @@ -43,4 +124,60 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle |
| 43 | 124 | return CommonResult.success(true); |
| 44 | 125 | } |
| 45 | 126 | |
| 127 | + /** | |
| 128 | + * 构建服务调用主题 | |
| 129 | + */ | |
| 130 | + private String buildServiceTopic(String productKey, String deviceName, String serviceIdentifier) { | |
| 131 | + return SYS_TOPIC_PREFIX + productKey + "/" + deviceName + SERVICE_TOPIC_PREFIX + serviceIdentifier; | |
| 132 | + } | |
| 133 | + | |
| 134 | + /** | |
| 135 | + * 构建属性设置主题 | |
| 136 | + */ | |
| 137 | + private String buildPropertySetTopic(String productKey, String deviceName) { | |
| 138 | + return SYS_TOPIC_PREFIX + productKey + "/" + deviceName + PROPERTY_SET_TOPIC; | |
| 139 | + } | |
| 140 | + | |
| 141 | + /** | |
| 142 | + * 构建服务调用请求 | |
| 143 | + */ | |
| 144 | + private JSONObject buildServiceRequest(String requestId, String serviceIdentifier, Map<String, Object> params) { | |
| 145 | + return new JSONObject() | |
| 146 | + .set("id", requestId) | |
| 147 | + .set("version", "1.0") | |
| 148 | + .set("method", "thing.service." + serviceIdentifier) | |
| 149 | + .set("params", params != null ? params : new JSONObject()); | |
| 150 | + } | |
| 151 | + | |
| 152 | + /** | |
| 153 | + * 构建属性设置请求 | |
| 154 | + */ | |
| 155 | + private JSONObject buildPropertySetRequest(String requestId, Map<String, Object> properties) { | |
| 156 | + return new JSONObject() | |
| 157 | + .set("id", requestId) | |
| 158 | + .set("version", "1.0") | |
| 159 | + .set("method", "thing.service.property.set") | |
| 160 | + .set("params", properties); | |
| 161 | + } | |
| 162 | + | |
| 163 | + /** | |
| 164 | + * 发布MQTT消息 | |
| 165 | + */ | |
| 166 | + private void publishMessage(String topic, JSONObject payload) { | |
| 167 | + mqttClient.publish( | |
| 168 | + topic, | |
| 169 | + Buffer.buffer(payload.toString()), | |
| 170 | + MqttQoS.AT_LEAST_ONCE, | |
| 171 | + false, | |
| 172 | + false); | |
| 173 | + log.info("[publishMessage][发送消息成功][topic: {}][payload: {}]", topic, payload); | |
| 174 | + } | |
| 175 | + | |
| 176 | + /** | |
| 177 | + * 生成请求ID | |
| 178 | + */ | |
| 179 | + private String generateRequestId() { | |
| 180 | + return IdUtil.fastSimpleUUID(); | |
| 181 | + } | |
| 182 | + | |
| 46 | 183 | } |
| 47 | 184 | \ 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/IotDeviceUpstreamServer.java
| 1 | 1 | package cn.iocoder.yudao.module.iot.plugin.emqx.upstream; |
| 2 | 2 | |
| 3 | -import cn.hutool.core.util.IdUtil; | |
| 4 | 3 | import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; |
| 5 | 4 | import cn.iocoder.yudao.module.iot.plugin.emqx.config.IotPluginEmqxProperties; |
| 6 | 5 | import cn.iocoder.yudao.module.iot.plugin.emqx.upstream.router.IotDeviceAuthVertxHandler; |
| 7 | 6 | import cn.iocoder.yudao.module.iot.plugin.emqx.upstream.router.IotDeviceMqttMessageHandler; |
| 8 | 7 | import io.netty.handler.codec.mqtt.MqttQoS; |
| 8 | +import io.vertx.core.Future; | |
| 9 | 9 | import io.vertx.core.Vertx; |
| 10 | 10 | import io.vertx.core.http.HttpServer; |
| 11 | 11 | import io.vertx.ext.web.Router; |
| 12 | 12 | import io.vertx.ext.web.handler.BodyHandler; |
| 13 | 13 | import io.vertx.mqtt.MqttClient; |
| 14 | -import io.vertx.mqtt.MqttClientOptions; | |
| 15 | 14 | import lombok.extern.slf4j.Slf4j; |
| 16 | 15 | |
| 16 | +import java.util.concurrent.CompletableFuture; | |
| 17 | +import java.util.concurrent.TimeUnit; | |
| 18 | + | |
| 17 | 19 | /** |
| 18 | 20 | * IoT 设备下行服务端,接收来自 device 设备的请求,转发给 server 服务器 |
| 19 | 21 | * <p> |
| ... | ... | @@ -24,20 +26,26 @@ import lombok.extern.slf4j.Slf4j; |
| 24 | 26 | @Slf4j |
| 25 | 27 | public class IotDeviceUpstreamServer { |
| 26 | 28 | |
| 27 | - private static final int RECONNECT_DELAY = 5000; // 重连延迟时间(毫秒) | |
| 29 | + private static final int RECONNECT_DELAY_MS = 5000; // 重连延迟时间(毫秒) | |
| 30 | + private static final int CONNECTION_TIMEOUT_MS = 10000; // 连接超时时间(毫秒) | |
| 31 | + private static final String TOPIC_SEPARATOR = ","; // 主题分隔符 | |
| 32 | + private static final MqttQoS DEFAULT_QOS = MqttQoS.AT_LEAST_ONCE; // 默认QoS级别 | |
| 28 | 33 | |
| 29 | 34 | private final Vertx vertx; |
| 30 | 35 | private final HttpServer server; |
| 31 | 36 | private final MqttClient client; |
| 32 | 37 | private final IotPluginEmqxProperties emqxProperties; |
| 33 | 38 | private final IotDeviceMqttMessageHandler mqttMessageHandler; |
| 39 | + private volatile boolean isRunning = false; // 服务运行状态标志 | |
| 34 | 40 | |
| 35 | 41 | public IotDeviceUpstreamServer(IotPluginEmqxProperties emqxProperties, |
| 36 | - IotDeviceUpstreamApi deviceUpstreamApi) { | |
| 42 | + IotDeviceUpstreamApi deviceUpstreamApi, | |
| 43 | + Vertx vertx, | |
| 44 | + MqttClient client) { | |
| 45 | + this.vertx = vertx; | |
| 37 | 46 | this.emqxProperties = emqxProperties; |
| 47 | + this.client = client; | |
| 38 | 48 | |
| 39 | - // 创建 Vertx 实例 | |
| 40 | - this.vertx = Vertx.vertx(); | |
| 41 | 49 | // 创建 Router 实例 |
| 42 | 50 | Router router = Router.router(vertx); |
| 43 | 51 | router.route().handler(BodyHandler.create()); // 处理 Body |
| ... | ... | @@ -45,14 +53,6 @@ public class IotDeviceUpstreamServer { |
| 45 | 53 | .handler(new IotDeviceAuthVertxHandler(deviceUpstreamApi)); |
| 46 | 54 | // 创建 HttpServer 实例 |
| 47 | 55 | this.server = vertx.createHttpServer().requestHandler(router); |
| 48 | - | |
| 49 | - // 创建 MQTT 客户端 | |
| 50 | - MqttClientOptions options = new MqttClientOptions() | |
| 51 | - .setClientId("yudao-iot-server-" + IdUtil.fastSimpleUUID()) | |
| 52 | - .setUsername(emqxProperties.getMqttUsername()) | |
| 53 | - .setPassword(emqxProperties.getMqttPassword()) | |
| 54 | - .setSsl(emqxProperties.isMqttSsl()); | |
| 55 | - client = MqttClient.create(vertx, options); | |
| 56 | 56 | this.mqttMessageHandler = new IotDeviceMqttMessageHandler(deviceUpstreamApi, client); |
| 57 | 57 | } |
| 58 | 58 | |
| ... | ... | @@ -60,25 +60,45 @@ public class IotDeviceUpstreamServer { |
| 60 | 60 | * 启动 HTTP 服务器、MQTT 客户端 |
| 61 | 61 | */ |
| 62 | 62 | public void start() { |
| 63 | + if (isRunning) { | |
| 64 | + log.warn("服务已经在运行中,请勿重复启动"); | |
| 65 | + return; | |
| 66 | + } | |
| 67 | + | |
| 68 | + log.info("[start] 开始启动服务"); | |
| 69 | + | |
| 63 | 70 | // 1. 启动 HTTP 服务器 |
| 64 | - log.info("[start][开始启动]"); | |
| 65 | - server.listen(emqxProperties.getAuthPort()) | |
| 71 | + CompletableFuture<Void> httpFuture = server.listen(emqxProperties.getAuthPort()) | |
| 66 | 72 | .toCompletionStage() |
| 67 | 73 | .toCompletableFuture() |
| 68 | - .join(); | |
| 69 | - log.info("[start][HTTP服务器启动完成,端口({})]", this.server.actualPort()); | |
| 74 | + .thenAccept(v -> log.info("[start] HTTP服务器启动完成,端口: {}", server.actualPort())); | |
| 70 | 75 | |
| 71 | 76 | // 2. 连接 MQTT Broker |
| 72 | - connectMqtt(); | |
| 73 | - | |
| 74 | - // 3. 添加 MQTT 断开重连监听器 | |
| 75 | - client.closeHandler(v -> { | |
| 76 | - log.warn("[closeHandler][MQTT 连接已断开,准备重连]"); | |
| 77 | - reconnectWithDelay(); | |
| 78 | - }); | |
| 77 | + CompletableFuture<Void> mqttFuture = connectMqtt() | |
| 78 | + .toCompletionStage() | |
| 79 | + .toCompletableFuture() | |
| 80 | + .thenAccept(v -> { | |
| 81 | + // 3. 添加 MQTT 断开重连监听器 | |
| 82 | + client.closeHandler(closeEvent -> { | |
| 83 | + log.warn("[closeHandler] MQTT连接已断开,准备重连"); | |
| 84 | + reconnectWithDelay(); | |
| 85 | + }); | |
| 86 | + | |
| 87 | + // 4. 设置 MQTT 消息处理器 | |
| 88 | + setupMessageHandler(); | |
| 89 | + }); | |
| 79 | 90 | |
| 80 | - // 4. 设置 MQTT 消息处理器 | |
| 81 | - setupMessageHandler(); | |
| 91 | + // 等待所有服务启动完成 | |
| 92 | + CompletableFuture.allOf(httpFuture, mqttFuture) | |
| 93 | + .orTimeout(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS) | |
| 94 | + .whenComplete((result, error) -> { | |
| 95 | + if (error != null) { | |
| 96 | + log.error("[start] 服务启动失败", error); | |
| 97 | + } else { | |
| 98 | + isRunning = true; | |
| 99 | + log.info("[start] 所有服务启动完成"); | |
| 100 | + } | |
| 101 | + }); | |
| 82 | 102 | } |
| 83 | 103 | |
| 84 | 104 | /** |
| ... | ... | @@ -86,79 +106,118 @@ public class IotDeviceUpstreamServer { |
| 86 | 106 | */ |
| 87 | 107 | private void setupMessageHandler() { |
| 88 | 108 | client.publishHandler(mqttMessageHandler::handle); |
| 109 | + log.debug("[setupMessageHandler] MQTT消息处理器设置完成"); | |
| 89 | 110 | } |
| 90 | 111 | |
| 91 | 112 | /** |
| 92 | 113 | * 重连 MQTT 客户端 |
| 93 | 114 | */ |
| 94 | 115 | private void reconnectWithDelay() { |
| 95 | - vertx.setTimer(RECONNECT_DELAY, id -> { | |
| 96 | - log.info("[reconnectWithDelay][开始重新连接 MQTT]"); | |
| 116 | + if (!isRunning) { | |
| 117 | + log.info("[reconnectWithDelay] 服务已停止,不再尝试重连"); | |
| 118 | + return; | |
| 119 | + } | |
| 120 | + | |
| 121 | + vertx.setTimer(RECONNECT_DELAY_MS, id -> { | |
| 122 | + log.info("[reconnectWithDelay] 开始重新连接MQTT"); | |
| 97 | 123 | connectMqtt(); |
| 98 | 124 | }); |
| 99 | 125 | } |
| 100 | 126 | |
| 101 | 127 | /** |
| 102 | 128 | * 连接 MQTT Broker 并订阅主题 |
| 129 | + * | |
| 130 | + * @return 连接结果的Future | |
| 103 | 131 | */ |
| 104 | - private void connectMqtt() { | |
| 105 | - client.connect(emqxProperties.getMqttPort(), emqxProperties.getMqttHost()) | |
| 106 | - .onSuccess(connAck -> { | |
| 107 | - log.info("[connectMqtt][MQTT客户端连接成功]"); | |
| 108 | - subscribeToTopics(); | |
| 132 | + private Future<Void> connectMqtt() { | |
| 133 | + return client.connect(emqxProperties.getMqttPort(), emqxProperties.getMqttHost()) | |
| 134 | + .compose(connAck -> { | |
| 135 | + log.info("[connectMqtt] MQTT客户端连接成功"); | |
| 136 | + return subscribeToTopics(); | |
| 109 | 137 | }) |
| 110 | - .onFailure(err -> { | |
| 111 | - log.error("[connectMqtt][连接 MQTT Broker 失败]", err); | |
| 138 | + .recover(err -> { | |
| 139 | + log.error("[connectMqtt] 连接MQTT Broker失败: {}", err.getMessage()); | |
| 112 | 140 | reconnectWithDelay(); |
| 141 | + return Future.failedFuture(err); | |
| 113 | 142 | }); |
| 114 | 143 | } |
| 115 | 144 | |
| 116 | 145 | /** |
| 117 | 146 | * 订阅设备上行消息主题 |
| 147 | + * | |
| 148 | + * @return 订阅结果的Future | |
| 118 | 149 | */ |
| 119 | - private void subscribeToTopics() { | |
| 120 | - String[] topics = emqxProperties.getMqttTopics().split(","); | |
| 150 | + private Future<Void> subscribeToTopics() { | |
| 151 | + String topicsStr = emqxProperties.getMqttTopics(); | |
| 152 | + if (topicsStr == null || topicsStr.trim().isEmpty()) { | |
| 153 | + log.warn("[subscribeToTopics] 未配置MQTT主题,跳过订阅"); | |
| 154 | + return Future.succeededFuture(); | |
| 155 | + } | |
| 156 | + | |
| 157 | + log.info("[subscribeToTopics] 开始订阅设备上行消息主题"); | |
| 158 | + | |
| 159 | + String[] topics = topicsStr.split(TOPIC_SEPARATOR); | |
| 160 | + Future<Void> compositeFuture = Future.succeededFuture(); | |
| 161 | + | |
| 121 | 162 | for (String topic : topics) { |
| 122 | - client.subscribe(topic, MqttQoS.AT_LEAST_ONCE.value()) | |
| 123 | - .onSuccess(v -> log.info("[subscribeToTopics][成功订阅主题: {}]", topic)) | |
| 124 | - .onFailure(err -> log.error("[subscribeToTopics][订阅主题失败: {}]", topic, err)); | |
| 163 | + String trimmedTopic = topic.trim(); | |
| 164 | + if (trimmedTopic.isEmpty()) { | |
| 165 | + continue; | |
| 166 | + } | |
| 167 | + | |
| 168 | + compositeFuture = compositeFuture.compose(v -> client.subscribe(trimmedTopic, DEFAULT_QOS.value()) | |
| 169 | + .<Void>map(ack -> { | |
| 170 | + log.info("[subscribeToTopics] 成功订阅主题: {}", trimmedTopic); | |
| 171 | + return null; | |
| 172 | + }) | |
| 173 | + .recover(err -> { | |
| 174 | + log.error("[subscribeToTopics] 订阅主题失败: {}, 原因: {}", | |
| 175 | + trimmedTopic, err.getMessage()); | |
| 176 | + return Future.<Void>succeededFuture(); // 继续订阅其他主题 | |
| 177 | + })); | |
| 125 | 178 | } |
| 126 | - log.info("[subscribeToTopics][开始订阅设备上行消息主题]"); | |
| 179 | + | |
| 180 | + return compositeFuture; | |
| 127 | 181 | } |
| 128 | 182 | |
| 129 | 183 | /** |
| 130 | - * 停止所有 | |
| 184 | + * 停止所有服务 | |
| 131 | 185 | */ |
| 132 | 186 | public void stop() { |
| 133 | - log.info("[stop][开始关闭]"); | |
| 134 | - try { | |
| 135 | - // 关闭 HTTP 服务器 | |
| 136 | - if (server != null) { | |
| 137 | - server.close() | |
| 138 | - .toCompletionStage() | |
| 139 | - .toCompletableFuture() | |
| 140 | - .join(); | |
| 141 | - } | |
| 187 | + if (!isRunning) { | |
| 188 | + log.warn("[stop] 服务未运行,无需停止"); | |
| 189 | + return; | |
| 190 | + } | |
| 142 | 191 | |
| 143 | - // 关闭 MQTT 客户端 | |
| 144 | - if (client != null) { | |
| 145 | - client.disconnect() | |
| 146 | - .toCompletionStage() | |
| 147 | - .toCompletableFuture() | |
| 148 | - .join(); | |
| 149 | - } | |
| 192 | + log.info("[stop] 开始关闭服务"); | |
| 193 | + isRunning = false; | |
| 150 | 194 | |
| 151 | - // 关闭 Vertx 实例 | |
| 152 | - if (vertx != null) { | |
| 153 | - vertx.close() | |
| 154 | - .toCompletionStage() | |
| 155 | - .toCompletableFuture() | |
| 156 | - .join(); | |
| 157 | - } | |
| 158 | - log.info("[stop][关闭完成]"); | |
| 195 | + try { | |
| 196 | + CompletableFuture<Void> serverFuture = server != null | |
| 197 | + ? server.close().toCompletionStage().toCompletableFuture() | |
| 198 | + : CompletableFuture.completedFuture(null); | |
| 199 | + | |
| 200 | + CompletableFuture<Void> clientFuture = client != null | |
| 201 | + ? client.disconnect().toCompletionStage().toCompletableFuture() | |
| 202 | + : CompletableFuture.completedFuture(null); | |
| 203 | + | |
| 204 | + CompletableFuture<Void> vertxFuture = vertx != null | |
| 205 | + ? vertx.close().toCompletionStage().toCompletableFuture() | |
| 206 | + : CompletableFuture.completedFuture(null); | |
| 207 | + | |
| 208 | + // 等待所有资源关闭 | |
| 209 | + CompletableFuture.allOf(serverFuture, clientFuture, vertxFuture) | |
| 210 | + .orTimeout(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS) | |
| 211 | + .whenComplete((result, error) -> { | |
| 212 | + if (error != null) { | |
| 213 | + log.error("[stop] 服务关闭过程中发生异常", error); | |
| 214 | + } else { | |
| 215 | + log.info("[stop] 所有服务关闭完成"); | |
| 216 | + } | |
| 217 | + }); | |
| 159 | 218 | } catch (Exception e) { |
| 160 | - log.error("[stop][关闭异常]", e); | |
| 161 | - throw new RuntimeException(e); | |
| 219 | + log.error("[stop] 关闭服务异常", e); | |
| 220 | + throw new RuntimeException("关闭IoT设备上行服务失败", e); | |
| 162 | 221 | } |
| 163 | 222 | } |
| 164 | 223 | } |
| 165 | 224 | \ 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/IotDeviceMqttMessageHandler.java
| ... | ... | @@ -13,13 +13,15 @@ import io.vertx.mqtt.messages.MqttPublishMessage; |
| 13 | 13 | import lombok.extern.slf4j.Slf4j; |
| 14 | 14 | |
| 15 | 15 | import java.time.LocalDateTime; |
| 16 | +import java.util.Arrays; | |
| 16 | 17 | |
| 17 | 18 | /** |
| 18 | 19 | * IoT 设备 MQTT 消息处理器 |
| 19 | 20 | * <p> |
| 20 | 21 | * 参考: |
| 21 | 22 | * <p> |
| 22 | - * "<a href="https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services?spm=a2c4g.11186623.0.0.97a72915vRck44#section-g4j-5zg-12b">...</a>"> | |
| 23 | + * "<a href= | |
| 24 | + * "https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services?spm=a2c4g.11186623.0.0.97a72915vRck44#section-g4j-5zg-12b">...</a>"> | |
| 23 | 25 | */ |
| 24 | 26 | @Slf4j |
| 25 | 27 | public class IotDeviceMqttMessageHandler { |
| ... | ... | @@ -35,6 +37,12 @@ public class IotDeviceMqttMessageHandler { |
| 35 | 37 | private static final String PROPERTY_POST_TOPIC = "/thing/event/property/post"; |
| 36 | 38 | private static final String EVENT_POST_TOPIC_PREFIX = "/thing/event/"; |
| 37 | 39 | private static final String EVENT_POST_TOPIC_SUFFIX = "/post"; |
| 40 | + private static final String REPLY_SUFFIX = "_reply"; | |
| 41 | + private static final int SUCCESS_CODE = 200; | |
| 42 | + private static final String SUCCESS_MESSAGE = "success"; | |
| 43 | + private static final String PROPERTY_METHOD = "thing.event.property.post"; | |
| 44 | + private static final String EVENT_METHOD_PREFIX = "thing.event."; | |
| 45 | + private static final String EVENT_METHOD_SUFFIX = ".post"; | |
| 38 | 46 | |
| 39 | 47 | private final IotDeviceUpstreamApi deviceUpstreamApi; |
| 40 | 48 | private final MqttClient mqttClient; |
| ... | ... | @@ -44,18 +52,33 @@ public class IotDeviceMqttMessageHandler { |
| 44 | 52 | this.mqttClient = mqttClient; |
| 45 | 53 | } |
| 46 | 54 | |
| 55 | + /** | |
| 56 | + * 处理MQTT消息 | |
| 57 | + * | |
| 58 | + * @param message MQTT发布消息 | |
| 59 | + */ | |
| 47 | 60 | public void handle(MqttPublishMessage message) { |
| 48 | 61 | String topic = message.topicName(); |
| 49 | 62 | String payload = message.payload().toString(); |
| 50 | 63 | log.info("[messageHandler][接收到消息][topic: {}][payload: {}]", topic, payload); |
| 51 | 64 | |
| 52 | 65 | try { |
| 66 | + if (payload == null || payload.isEmpty()) { | |
| 67 | + log.warn("[messageHandler][消息内容为空][topic: {}]", topic); | |
| 68 | + return; | |
| 69 | + } | |
| 53 | 70 | handleMessage(topic, payload); |
| 54 | 71 | } catch (Exception e) { |
| 55 | 72 | log.error("[messageHandler][处理消息失败][topic: {}][payload: {}]", topic, payload, e); |
| 56 | 73 | } |
| 57 | 74 | } |
| 58 | 75 | |
| 76 | + /** | |
| 77 | + * 根据主题类型处理消息 | |
| 78 | + * | |
| 79 | + * @param topic 主题 | |
| 80 | + * @param payload 消息内容 | |
| 81 | + */ | |
| 59 | 82 | private void handleMessage(String topic, String payload) { |
| 60 | 83 | // 校验前缀 |
| 61 | 84 | if (!topic.startsWith(SYS_TOPIC_PREFIX)) { |
| ... | ... | @@ -88,34 +111,26 @@ public class IotDeviceMqttMessageHandler { |
| 88 | 111 | * @param payload 消息内容 |
| 89 | 112 | */ |
| 90 | 113 | private void handlePropertyPost(String topic, String payload) { |
| 91 | - // 解析消息内容 | |
| 92 | - JSONObject jsonObject = JSONUtil.parseObj(payload); | |
| 93 | - String[] topicParts = topic.split("/"); | |
| 114 | + try { | |
| 115 | + // 解析消息内容 | |
| 116 | + JSONObject jsonObject = JSONUtil.parseObj(payload); | |
| 117 | + String[] topicParts = parseTopic(topic); | |
| 118 | + if (topicParts == null) { | |
| 119 | + return; | |
| 120 | + } | |
| 94 | 121 | |
| 95 | - // 构建设备属性上报请求对象 | |
| 96 | - IotDevicePropertyReportReqDTO reportReqDTO = buildPropertyReportDTO(jsonObject, topicParts); | |
| 122 | + // 构建设备属性上报请求对象 | |
| 123 | + IotDevicePropertyReportReqDTO reportReqDTO = buildPropertyReportDTO(jsonObject, topicParts); | |
| 97 | 124 | |
| 98 | - // 调用上游 API 处理设备上报数据 | |
| 99 | - deviceUpstreamApi.reportDeviceProperty(reportReqDTO); | |
| 100 | - log.info("[handlePropertyPost][处理设备上行消息成功][topic: {}][reportReqDTO: {}]", | |
| 101 | - topic, JSONUtil.toJsonStr(reportReqDTO)); | |
| 125 | + // 调用上游 API 处理设备上报数据 | |
| 126 | + deviceUpstreamApi.reportDeviceProperty(reportReqDTO); | |
| 127 | + log.info("[handlePropertyPost][处理设备属性上报成功][topic: {}]", topic); | |
| 102 | 128 | |
| 103 | - // 发送响应消息 | |
| 104 | - String replyTopic = topic + "_reply"; | |
| 105 | - JSONObject response = new JSONObject() | |
| 106 | - .set("id", jsonObject.getStr("id")) | |
| 107 | - .set("code", 200) | |
| 108 | - .set("data", new JSONObject()) | |
| 109 | - .set("message", "success") | |
| 110 | - .set("method", "thing.event.property.post"); | |
| 111 | - | |
| 112 | - mqttClient.publish(replyTopic, | |
| 113 | - Buffer.buffer(response.toString()), | |
| 114 | - MqttQoS.AT_LEAST_ONCE, | |
| 115 | - false, | |
| 116 | - false); | |
| 117 | - log.info("[handlePropertyPost][发送响应消息成功][topic: {}][response: {}]", | |
| 118 | - replyTopic, response.toString()); | |
| 129 | + // 发送响应消息 | |
| 130 | + sendResponse(topic, jsonObject, PROPERTY_METHOD, null); | |
| 131 | + } catch (Exception e) { | |
| 132 | + log.error("[handlePropertyPost][处理设备属性上报失败][topic: {}][payload: {}]", topic, payload, e); | |
| 133 | + } | |
| 119 | 134 | } |
| 120 | 135 | |
| 121 | 136 | /** |
| ... | ... | @@ -125,35 +140,97 @@ public class IotDeviceMqttMessageHandler { |
| 125 | 140 | * @param payload 消息内容 |
| 126 | 141 | */ |
| 127 | 142 | private void handleEventPost(String topic, String payload) { |
| 128 | - // 解析消息内容 | |
| 129 | - JSONObject jsonObject = JSONUtil.parseObj(payload); | |
| 143 | + try { | |
| 144 | + // 解析消息内容 | |
| 145 | + JSONObject jsonObject = JSONUtil.parseObj(payload); | |
| 146 | + String[] topicParts = parseTopic(topic); | |
| 147 | + if (topicParts == null) { | |
| 148 | + return; | |
| 149 | + } | |
| 150 | + | |
| 151 | + // 构建设备事件上报请求对象 | |
| 152 | + IotDeviceEventReportReqDTO reportReqDTO = buildEventReportDTO(jsonObject, topicParts); | |
| 153 | + | |
| 154 | + // 调用上游 API 处理设备上报数据 | |
| 155 | + deviceUpstreamApi.reportDeviceEvent(reportReqDTO); | |
| 156 | + log.info("[handleEventPost][处理设备事件上报成功][topic: {}]", topic); | |
| 157 | + | |
| 158 | + // 从 topic 中获取事件标识符 | |
| 159 | + String eventIdentifier = getEventIdentifier(topicParts, topic); | |
| 160 | + if (eventIdentifier == null) { | |
| 161 | + return; | |
| 162 | + } | |
| 163 | + | |
| 164 | + // 发送响应消息 | |
| 165 | + String method = EVENT_METHOD_PREFIX + eventIdentifier + EVENT_METHOD_SUFFIX; | |
| 166 | + sendResponse(topic, jsonObject, method, null); | |
| 167 | + } catch (Exception e) { | |
| 168 | + log.error("[handleEventPost][处理设备事件上报失败][topic: {}][payload: {}]", topic, payload, e); | |
| 169 | + } | |
| 170 | + } | |
| 171 | + | |
| 172 | + /** | |
| 173 | + * 解析主题,获取主题各部分 | |
| 174 | + * | |
| 175 | + * @param topic 主题 | |
| 176 | + * @return 主题各部分数组,如果解析失败返回null | |
| 177 | + */ | |
| 178 | + private String[] parseTopic(String topic) { | |
| 130 | 179 | String[] topicParts = topic.split("/"); |
| 180 | + if (topicParts.length < 7) { | |
| 181 | + log.warn("[parseTopic][主题格式不正确][topic: {}]", topic); | |
| 182 | + return null; | |
| 183 | + } | |
| 184 | + return topicParts; | |
| 185 | + } | |
| 131 | 186 | |
| 132 | - // 构建设备事件上报请求对象 | |
| 133 | - IotDeviceEventReportReqDTO reportReqDTO = buildEventReportDTO(jsonObject, topicParts); | |
| 187 | + /** | |
| 188 | + * 从主题部分中获取事件标识符 | |
| 189 | + * | |
| 190 | + * @param topicParts 主题各部分 | |
| 191 | + * @param topic 原始主题,用于日志 | |
| 192 | + * @return 事件标识符,如果获取失败返回null | |
| 193 | + */ | |
| 194 | + private String getEventIdentifier(String[] topicParts, String topic) { | |
| 195 | + try { | |
| 196 | + return topicParts[6]; | |
| 197 | + } catch (ArrayIndexOutOfBoundsException e) { | |
| 198 | + log.warn("[getEventIdentifier][无法从主题中获取事件标识符][topic: {}][topicParts: {}]", | |
| 199 | + topic, Arrays.toString(topicParts)); | |
| 200 | + return null; | |
| 201 | + } | |
| 202 | + } | |
| 134 | 203 | |
| 135 | - // 调用上游 API 处理设备上报数据 | |
| 136 | - deviceUpstreamApi.reportDeviceEvent(reportReqDTO); | |
| 137 | - log.info("[handleEventPost][处理设备上行消息成功][topic: {}][reportReqDTO: {}]", | |
| 138 | - topic, JSONUtil.toJsonStr(reportReqDTO)); | |
| 204 | + /** | |
| 205 | + * 发送响应消息 | |
| 206 | + * | |
| 207 | + * @param topic 原始主题 | |
| 208 | + * @param jsonObject 原始消息JSON对象 | |
| 209 | + * @param method 响应方法 | |
| 210 | + * @param customData 自定义数据,可为null | |
| 211 | + */ | |
| 212 | + private void sendResponse(String topic, JSONObject jsonObject, String method, JSONObject customData) { | |
| 213 | + String replyTopic = topic + REPLY_SUFFIX; | |
| 214 | + JSONObject data = customData != null ? customData : new JSONObject(); | |
| 139 | 215 | |
| 140 | - // 发送响应消息 | |
| 141 | - String replyTopic = topic + "_reply"; | |
| 142 | - String eventIdentifier = topicParts[6]; // 从 topic 中获取事件标识符 | |
| 143 | 216 | JSONObject response = new JSONObject() |
| 144 | 217 | .set("id", jsonObject.getStr("id")) |
| 145 | - .set("code", 200) | |
| 146 | - .set("data", new JSONObject()) | |
| 147 | - .set("message", "success") | |
| 148 | - .set("method", "thing.event." + eventIdentifier + ".post"); | |
| 149 | - | |
| 150 | - mqttClient.publish(replyTopic, | |
| 151 | - Buffer.buffer(response.toString()), | |
| 152 | - MqttQoS.AT_LEAST_ONCE, | |
| 153 | - false, | |
| 154 | - false); | |
| 155 | - log.info("[handleEventPost][发送响应消息成功][topic: {}][response: {}]", | |
| 156 | - replyTopic, response.toString()); | |
| 218 | + .set("code", SUCCESS_CODE) | |
| 219 | + .set("data", data) | |
| 220 | + .set("message", SUCCESS_MESSAGE) | |
| 221 | + .set("method", method); | |
| 222 | + | |
| 223 | + try { | |
| 224 | + mqttClient.publish(replyTopic, | |
| 225 | + Buffer.buffer(response.toString()), | |
| 226 | + MqttQoS.AT_LEAST_ONCE, | |
| 227 | + false, | |
| 228 | + false); | |
| 229 | + log.info("[sendResponse][发送响应消息成功][topic: {}]", replyTopic); | |
| 230 | + } catch (Exception e) { | |
| 231 | + log.error("[sendResponse][发送响应消息失败][topic: {}][response: {}]", | |
| 232 | + replyTopic, response.toString(), e); | |
| 233 | + } | |
| 157 | 234 | } |
| 158 | 235 | |
| 159 | 236 | /** |
| ... | ... | @@ -163,15 +240,15 @@ public class IotDeviceMqttMessageHandler { |
| 163 | 240 | * @param topicParts 主题部分 |
| 164 | 241 | * @return 设备属性上报请求对象 |
| 165 | 242 | */ |
| 166 | - private IotDevicePropertyReportReqDTO buildPropertyReportDTO(JSONObject jsonObject, | |
| 167 | - String[] topicParts) { | |
| 168 | - return ((IotDevicePropertyReportReqDTO) new IotDevicePropertyReportReqDTO() | |
| 169 | - .setRequestId(jsonObject.getStr("id")) | |
| 170 | - .setProcessId(IotPluginCommonUtils.getProcessId()) | |
| 171 | - .setReportTime(LocalDateTime.now()) | |
| 172 | - .setProductKey(topicParts[2]) | |
| 173 | - .setDeviceName(topicParts[3])) | |
| 174 | - .setProperties(jsonObject.getJSONObject("params")); | |
| 243 | + private IotDevicePropertyReportReqDTO buildPropertyReportDTO(JSONObject jsonObject, String[] topicParts) { | |
| 244 | + IotDevicePropertyReportReqDTO reportReqDTO = new IotDevicePropertyReportReqDTO(); | |
| 245 | + reportReqDTO.setRequestId(jsonObject.getStr("id")); | |
| 246 | + reportReqDTO.setProcessId(IotPluginCommonUtils.getProcessId()); | |
| 247 | + reportReqDTO.setReportTime(LocalDateTime.now()); | |
| 248 | + reportReqDTO.setProductKey(topicParts[2]); | |
| 249 | + reportReqDTO.setDeviceName(topicParts[3]); | |
| 250 | + reportReqDTO.setProperties(jsonObject.getJSONObject("params")); | |
| 251 | + return reportReqDTO; | |
| 175 | 252 | } |
| 176 | 253 | |
| 177 | 254 | /** |
| ... | ... | @@ -182,13 +259,14 @@ public class IotDeviceMqttMessageHandler { |
| 182 | 259 | * @return 设备事件上报请求对象 |
| 183 | 260 | */ |
| 184 | 261 | private IotDeviceEventReportReqDTO buildEventReportDTO(JSONObject jsonObject, String[] topicParts) { |
| 185 | - return ((IotDeviceEventReportReqDTO) new IotDeviceEventReportReqDTO() | |
| 186 | - .setRequestId(jsonObject.getStr("id")) | |
| 187 | - .setProcessId(IotPluginCommonUtils.getProcessId()) | |
| 188 | - .setReportTime(LocalDateTime.now()) | |
| 189 | - .setProductKey(topicParts[2]) | |
| 190 | - .setDeviceName(topicParts[3])) | |
| 191 | - .setIdentifier(topicParts[4]) | |
| 192 | - .setParams(jsonObject.getJSONObject("params")); | |
| 262 | + IotDeviceEventReportReqDTO reportReqDTO = new IotDeviceEventReportReqDTO(); | |
| 263 | + reportReqDTO.setRequestId(jsonObject.getStr("id")); | |
| 264 | + reportReqDTO.setProcessId(IotPluginCommonUtils.getProcessId()); | |
| 265 | + reportReqDTO.setReportTime(LocalDateTime.now()); | |
| 266 | + reportReqDTO.setProductKey(topicParts[2]); | |
| 267 | + reportReqDTO.setDeviceName(topicParts[3]); | |
| 268 | + reportReqDTO.setIdentifier(topicParts[6]); | |
| 269 | + reportReqDTO.setParams(jsonObject.getJSONObject("params")); | |
| 270 | + return reportReqDTO; | |
| 193 | 271 | } |
| 194 | 272 | } |
| 195 | 273 | \ No newline at end of file | ... | ... |