Commit b4035cb0362ce8dfd11cf8432cc9d7151b4e48cd
1 parent
1b59aa9c
reactor:【IoT 物联网】数据下行,基于 messagebus 实现订阅消费
Showing
7 changed files
with
64 additions
and
55 deletions
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/JsonUtils.java
| @@ -3,18 +3,22 @@ package cn.iocoder.yudao.framework.common.util.json; | @@ -3,18 +3,22 @@ package cn.iocoder.yudao.framework.common.util.json; | ||
| 3 | import cn.hutool.core.util.ArrayUtil; | 3 | import cn.hutool.core.util.ArrayUtil; |
| 4 | import cn.hutool.core.util.StrUtil; | 4 | import cn.hutool.core.util.StrUtil; |
| 5 | import cn.hutool.json.JSONUtil; | 5 | import cn.hutool.json.JSONUtil; |
| 6 | +import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeDeserializer; | ||
| 7 | +import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeSerializer; | ||
| 6 | import com.fasterxml.jackson.annotation.JsonInclude; | 8 | import com.fasterxml.jackson.annotation.JsonInclude; |
| 7 | import com.fasterxml.jackson.core.type.TypeReference; | 9 | import com.fasterxml.jackson.core.type.TypeReference; |
| 8 | import com.fasterxml.jackson.databind.DeserializationFeature; | 10 | import com.fasterxml.jackson.databind.DeserializationFeature; |
| 9 | import com.fasterxml.jackson.databind.JsonNode; | 11 | import com.fasterxml.jackson.databind.JsonNode; |
| 10 | import com.fasterxml.jackson.databind.ObjectMapper; | 12 | import com.fasterxml.jackson.databind.ObjectMapper; |
| 11 | import com.fasterxml.jackson.databind.SerializationFeature; | 13 | import com.fasterxml.jackson.databind.SerializationFeature; |
| 14 | +import com.fasterxml.jackson.databind.module.SimpleModule; | ||
| 12 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; | 15 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; |
| 13 | import lombok.SneakyThrows; | 16 | import lombok.SneakyThrows; |
| 14 | import lombok.extern.slf4j.Slf4j; | 17 | import lombok.extern.slf4j.Slf4j; |
| 15 | 18 | ||
| 16 | import java.io.IOException; | 19 | import java.io.IOException; |
| 17 | import java.lang.reflect.Type; | 20 | import java.lang.reflect.Type; |
| 21 | +import java.time.LocalDateTime; | ||
| 18 | import java.util.ArrayList; | 22 | import java.util.ArrayList; |
| 19 | import java.util.List; | 23 | import java.util.List; |
| 20 | 24 | ||
| @@ -32,7 +36,11 @@ public class JsonUtils { | @@ -32,7 +36,11 @@ public class JsonUtils { | ||
| 32 | objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); | 36 | objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); |
| 33 | objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); | 37 | objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); |
| 34 | objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 忽略 null 值 | 38 | objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 忽略 null 值 |
| 35 | - objectMapper.registerModules(new JavaTimeModule()); // 解决 LocalDateTime 的序列化 | 39 | + // 解决 LocalDateTime 的序列化 |
| 40 | + SimpleModule simpleModule = new JavaTimeModule() | ||
| 41 | + .addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE) | ||
| 42 | + .addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE); | ||
| 43 | + objectMapper.registerModules(simpleModule); | ||
| 36 | } | 44 | } |
| 37 | 45 | ||
| 38 | /** | 46 | /** |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.http
| @@ -16,7 +16,7 @@ Authorization: Bearer {{token}} | @@ -16,7 +16,7 @@ Authorization: Bearer {{token}} | ||
| 16 | ### 请求 /iot/device/downstream 接口(属性设置) => 成功 | 16 | ### 请求 /iot/device/downstream 接口(属性设置) => 成功 |
| 17 | POST {{baseUrl}}/iot/device/downstream | 17 | POST {{baseUrl}}/iot/device/downstream |
| 18 | Content-Type: application/json | 18 | Content-Type: application/json |
| 19 | -tenant-id: {{adminTenentId}} | 19 | +tenant-id: {{adminTenantId}} |
| 20 | Authorization: Bearer {{token}} | 20 | Authorization: Bearer {{token}} |
| 21 | 21 | ||
| 22 | { | 22 | { |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java
| @@ -8,6 +8,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; | @@ -8,6 +8,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 8 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | 8 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 9 | import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.*; | 9 | import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.*; |
| 10 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceDownstreamReqVO; | 10 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceDownstreamReqVO; |
| 11 | +import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer; | ||
| 11 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | 12 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; |
| 12 | import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInstanceDO; | 13 | import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInstanceDO; |
| 13 | import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; | 14 | import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; |
| @@ -52,6 +53,8 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic | @@ -52,6 +53,8 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic | ||
| 52 | 53 | ||
| 53 | @Resource | 54 | @Resource |
| 54 | private IotDeviceProducer deviceProducer; | 55 | private IotDeviceProducer deviceProducer; |
| 56 | + @Resource | ||
| 57 | + private IotDeviceMessageProducer deviceMessageProducer; | ||
| 55 | 58 | ||
| 56 | @Override | 59 | @Override |
| 57 | public IotDeviceMessage downstreamDevice(IotDeviceDownstreamReqVO downstreamReqVO) { | 60 | public IotDeviceMessage downstreamDevice(IotDeviceDownstreamReqVO downstreamReqVO) { |
| @@ -150,26 +153,16 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic | @@ -150,26 +153,16 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic | ||
| 150 | // TODO @super:【可优化】过滤掉不合法的属性 | 153 | // TODO @super:【可优化】过滤掉不合法的属性 |
| 151 | 154 | ||
| 152 | // 2. 发送请求 | 155 | // 2. 发送请求 |
| 153 | - String url = String.format("sys/%s/%s/thing/service/property/set", | ||
| 154 | - getProductKey(device, parentDevice), getDeviceName(device, parentDevice)); | ||
| 155 | - IotDevicePropertySetReqDTO reqDTO = new IotDevicePropertySetReqDTO() | ||
| 156 | - .setProperties((Map<String, Object>) downstreamReqVO.getData()); | ||
| 157 | - CommonResult<Boolean> result = requestPlugin(url, reqDTO, device); | ||
| 158 | - | ||
| 159 | - // 3. 发送设备消息 | ||
| 160 | - IotDeviceMessage message = new IotDeviceMessage().setRequestId(reqDTO.getRequestId()) | ||
| 161 | - .setType(IotDeviceMessageTypeEnum.PROPERTY.getType()) | ||
| 162 | - .setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier()) | ||
| 163 | - .setData(reqDTO.getProperties()); | ||
| 164 | - sendDeviceMessage(message, device, result.getCode()); | ||
| 165 | - | ||
| 166 | - // 4. 如果不成功,抛出异常,提示用户 | ||
| 167 | - if (result.isError()) { | ||
| 168 | - log.error("[setDeviceProperty][设备({})属性设置失败,请求参数:({}),响应结果:({})]", | ||
| 169 | - device.getDeviceKey(), reqDTO, result); | ||
| 170 | - throw exception(DEVICE_DOWNSTREAM_FAILED, result.getMsg()); | ||
| 171 | - } | ||
| 172 | - return message; | 156 | + // TODO @芋艿:deviceName 的设置 |
| 157 | + String deviceName = "xx"; | ||
| 158 | + Long tenantId = 1L; | ||
| 159 | + cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage message = cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage | ||
| 160 | + .of(getProductKey(device, parentDevice), getDeviceName(device, parentDevice), deviceName, | ||
| 161 | + null, tenantId); | ||
| 162 | + String serverId = "yy"; | ||
| 163 | + deviceMessageProducer.sendGatewayDeviceMessage(serverId, message); | ||
| 164 | + // TODO @芋艿:后续可以清理掉 | ||
| 165 | + return null; | ||
| 173 | } | 166 | } |
| 174 | 167 | ||
| 175 | /** | 168 | /** |
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/mq/message/IotDeviceMessage.java
| @@ -32,7 +32,7 @@ public class IotDeviceMessage { | @@ -32,7 +32,7 @@ public class IotDeviceMessage { | ||
| 32 | * | 32 | * |
| 33 | * 其中,%s 就是该“server”(protocol) 的标识 | 33 | * 其中,%s 就是该“server”(protocol) 的标识 |
| 34 | */ | 34 | */ |
| 35 | - public static final String MESSAGE_BUS_GATEWAY_DEVICE_MESSAGE_TOPIC = MESSAGE_BUS_DEVICE_MESSAGE_TOPIC + "/%s"; | 35 | + public static final String MESSAGE_BUS_GATEWAY_DEVICE_MESSAGE_TOPIC = MESSAGE_BUS_DEVICE_MESSAGE_TOPIC + "_%s"; |
| 36 | 36 | ||
| 37 | /** | 37 | /** |
| 38 | * 请求编号 | 38 | * 请求编号 |
| @@ -71,6 +71,7 @@ public class IotDeviceMessage { | @@ -71,6 +71,7 @@ public class IotDeviceMessage { | ||
| 71 | * 例如说:属性上报的 properties、事件上报的 params | 71 | * 例如说:属性上报的 properties、事件上报的 params |
| 72 | */ | 72 | */ |
| 73 | private Object data; | 73 | private Object data; |
| 74 | + // TODO @芋艿:可能会去掉 | ||
| 74 | /** | 75 | /** |
| 75 | * 响应码 | 76 | * 响应码 |
| 76 | * | 77 | * |
| @@ -100,6 +101,20 @@ public class IotDeviceMessage { | @@ -100,6 +101,20 @@ public class IotDeviceMessage { | ||
| 100 | return this; | 101 | return this; |
| 101 | } | 102 | } |
| 102 | 103 | ||
| 104 | + public IotDeviceMessage ofPropertySet(Map<String, Object> properties) { | ||
| 105 | + this.setType(IotDeviceMessageTypeEnum.PROPERTY.getType()); | ||
| 106 | + this.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier()); | ||
| 107 | + this.setData(properties); | ||
| 108 | + return this; | ||
| 109 | + } | ||
| 110 | + | ||
| 111 | + public static IotDeviceMessage of(String productKey, String deviceName, String deviceKey, | ||
| 112 | + String serverId, Long tenantId) { | ||
| 113 | + return of(productKey, deviceName, deviceKey, | ||
| 114 | + null, null, | ||
| 115 | + serverId, tenantId); | ||
| 116 | + } | ||
| 117 | + | ||
| 103 | public static IotDeviceMessage of(String productKey, String deviceName, String deviceKey, | 118 | public static IotDeviceMessage of(String productKey, String deviceName, String deviceKey, |
| 104 | String requestId, LocalDateTime reportTime, | 119 | String requestId, LocalDateTime reportTime, |
| 105 | String serverId, Long tenantId) { | 120 | String serverId, Long tenantId) { |
| @@ -117,7 +132,7 @@ public class IotDeviceMessage { | @@ -117,7 +132,7 @@ public class IotDeviceMessage { | ||
| 117 | 132 | ||
| 118 | // ========== Topic 相关 ========== | 133 | // ========== Topic 相关 ========== |
| 119 | 134 | ||
| 120 | - public static String getMessageBusGatewayDeviceMessageTopic(String serverId) { | 135 | + public static String buildMessageBusGatewayDeviceMessageTopic(String serverId) { |
| 121 | return String.format(MESSAGE_BUS_GATEWAY_DEVICE_MESSAGE_TOPIC, serverId); | 136 | return String.format(MESSAGE_BUS_GATEWAY_DEVICE_MESSAGE_TOPIC, serverId); |
| 122 | } | 137 | } |
| 123 | 138 |
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/mq/producer/IotDeviceMessageProducer.java
| @@ -30,7 +30,7 @@ public class IotDeviceMessageProducer { | @@ -30,7 +30,7 @@ public class IotDeviceMessageProducer { | ||
| 30 | * @param message 设备消息 | 30 | * @param message 设备消息 |
| 31 | */ | 31 | */ |
| 32 | public void sendGatewayDeviceMessage(String serverId, Object message) { | 32 | public void sendGatewayDeviceMessage(String serverId, Object message) { |
| 33 | - messageBus.post(IotDeviceMessage.getMessageBusGatewayDeviceMessageTopic(serverId), message); | 33 | + messageBus.post(IotDeviceMessage.buildMessageBusGatewayDeviceMessageTopic(serverId), message); |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | } | 36 | } |
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/config/IotNetComponentHttpAutoConfiguration.java
| 1 | package cn.iocoder.yudao.module.iot.net.component.http.config; | 1 | package cn.iocoder.yudao.module.iot.net.component.http.config; |
| 2 | 2 | ||
| 3 | -import cn.hutool.system.SystemUtil; | ||
| 4 | import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; | 3 | import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; |
| 4 | +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; | ||
| 5 | +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBusSubscriber; | ||
| 6 | +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; | ||
| 5 | import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer; | 7 | import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer; |
| 6 | -import cn.iocoder.yudao.module.iot.net.component.core.config.IotNetComponentCommonProperties; | ||
| 7 | import cn.iocoder.yudao.module.iot.net.component.core.downstream.IotDeviceDownstreamHandler; | 8 | import cn.iocoder.yudao.module.iot.net.component.core.downstream.IotDeviceDownstreamHandler; |
| 8 | -import cn.iocoder.yudao.module.iot.net.component.core.heartbeat.IotNetComponentRegistry; | ||
| 9 | -import cn.iocoder.yudao.module.iot.net.component.core.util.IotNetComponentCommonUtils; | ||
| 10 | import cn.iocoder.yudao.module.iot.net.component.http.downstream.IotDeviceDownstreamHandlerImpl; | 9 | import cn.iocoder.yudao.module.iot.net.component.http.downstream.IotDeviceDownstreamHandlerImpl; |
| 11 | import cn.iocoder.yudao.module.iot.net.component.http.upstream.IotDeviceUpstreamServer; | 10 | import cn.iocoder.yudao.module.iot.net.component.http.upstream.IotDeviceUpstreamServer; |
| 12 | import io.vertx.core.Vertx; | 11 | import io.vertx.core.Vertx; |
| @@ -36,15 +35,6 @@ import org.springframework.context.event.EventListener; | @@ -36,15 +35,6 @@ import org.springframework.context.event.EventListener; | ||
| 36 | public class IotNetComponentHttpAutoConfiguration { | 35 | public class IotNetComponentHttpAutoConfiguration { |
| 37 | 36 | ||
| 38 | /** | 37 | /** |
| 39 | - * 组件 key | ||
| 40 | - */ | ||
| 41 | - private static final String PLUGIN_KEY = "http"; | ||
| 42 | - | ||
| 43 | - public IotNetComponentHttpAutoConfiguration() { | ||
| 44 | - // 构造函数中不输出日志,移到 initialize 方法中 | ||
| 45 | - } | ||
| 46 | - | ||
| 47 | - /** | ||
| 48 | * 初始化 HTTP 组件 | 38 | * 初始化 HTTP 组件 |
| 49 | * | 39 | * |
| 50 | * @param event 应用启动事件 | 40 | * @param event 应用启动事件 |
| @@ -53,27 +43,30 @@ public class IotNetComponentHttpAutoConfiguration { | @@ -53,27 +43,30 @@ public class IotNetComponentHttpAutoConfiguration { | ||
| 53 | public void initialize(ApplicationStartedEvent event) { | 43 | public void initialize(ApplicationStartedEvent event) { |
| 54 | log.info("[IotNetComponentHttpAutoConfiguration][开始初始化]"); | 44 | log.info("[IotNetComponentHttpAutoConfiguration][开始初始化]"); |
| 55 | 45 | ||
| 56 | - // 从应用上下文中获取需要的 Bean | ||
| 57 | - IotNetComponentRegistry componentRegistry = event.getApplicationContext() | ||
| 58 | - .getBean(IotNetComponentRegistry.class); | ||
| 59 | - IotNetComponentCommonProperties commonProperties = event.getApplicationContext() | ||
| 60 | - .getBean(IotNetComponentCommonProperties.class); | 46 | + // TODO @芋艿:临时处理 |
| 47 | + IotMessageBus messageBus = event.getApplicationContext() | ||
| 48 | + .getBean(IotMessageBus.class); | ||
| 49 | + messageBus.register(new IotMessageBusSubscriber<IotDeviceMessage>() { | ||
| 50 | + | ||
| 51 | + @Override | ||
| 52 | + public String getTopic() { | ||
| 53 | + return IotDeviceMessage.buildMessageBusGatewayDeviceMessageTopic("yy"); | ||
| 54 | + } | ||
| 61 | 55 | ||
| 62 | - // 设置当前组件的核心标识 | ||
| 63 | - // 注意:这里只为当前 HTTP 组件设置 pluginKey,不影响其他组件 | ||
| 64 | - // TODO @haohao:多个会存在冲突的问题哇? | ||
| 65 | - commonProperties.setPluginKey(PLUGIN_KEY); | 56 | + @Override |
| 57 | + public String getGroup() { | ||
| 58 | + return "test"; | ||
| 59 | + } | ||
| 66 | 60 | ||
| 67 | - // 将 HTTP 组件注册到组件注册表 | ||
| 68 | - componentRegistry.registerComponent( | ||
| 69 | - PLUGIN_KEY, | ||
| 70 | - SystemUtil.getHostInfo().getAddress(), | ||
| 71 | - 0, // 内嵌模式固定为 0:自动生成对应的 port 端口号 | ||
| 72 | - IotNetComponentCommonUtils.getProcessId()); | 61 | + @Override |
| 62 | + public void onMessage(IotDeviceMessage message) { | ||
| 63 | + System.out.println(message); | ||
| 64 | + } | ||
| 73 | 65 | ||
| 74 | - log.info("[initialize][IoT HTTP 组件初始化完成]"); | 66 | + }); |
| 75 | } | 67 | } |
| 76 | 68 | ||
| 69 | + // TODO @芋艿:貌似这里不用注册 bean? | ||
| 77 | /** | 70 | /** |
| 78 | * 创建 Vert.x 实例 | 71 | * 创建 Vert.x 实例 |
| 79 | * | 72 | * |
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/upstream/IotDeviceUpstreamServer.java
| @@ -32,7 +32,7 @@ public class IotDeviceUpstreamServer extends AbstractVerticle { | @@ -32,7 +32,7 @@ public class IotDeviceUpstreamServer extends AbstractVerticle { | ||
| 32 | private final IotDeviceMessageProducer deviceMessageProducer; | 32 | private final IotDeviceMessageProducer deviceMessageProducer; |
| 33 | 33 | ||
| 34 | @Override | 34 | @Override |
| 35 | - public void start() throws Exception { | 35 | + public void start() { |
| 36 | start(Promise.promise()); | 36 | start(Promise.promise()); |
| 37 | } | 37 | } |
| 38 | 38 |