Commit b4035cb0362ce8dfd11cf8432cc9d7151b4e48cd

Authored by YunaiV
1 parent 1b59aa9c

reactor:【IoT 物联网】数据下行,基于 messagebus 实现订阅消费

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 3 import cn.hutool.core.util.ArrayUtil;
4 4 import cn.hutool.core.util.StrUtil;
5 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 8 import com.fasterxml.jackson.annotation.JsonInclude;
7 9 import com.fasterxml.jackson.core.type.TypeReference;
8 10 import com.fasterxml.jackson.databind.DeserializationFeature;
9 11 import com.fasterxml.jackson.databind.JsonNode;
10 12 import com.fasterxml.jackson.databind.ObjectMapper;
11 13 import com.fasterxml.jackson.databind.SerializationFeature;
  14 +import com.fasterxml.jackson.databind.module.SimpleModule;
12 15 import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
13 16 import lombok.SneakyThrows;
14 17 import lombok.extern.slf4j.Slf4j;
15 18  
16 19 import java.io.IOException;
17 20 import java.lang.reflect.Type;
  21 +import java.time.LocalDateTime;
18 22 import java.util.ArrayList;
19 23 import java.util.List;
20 24  
... ... @@ -32,7 +36,11 @@ public class JsonUtils {
32 36 objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
33 37 objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
34 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 16 ### 请求 /iot/device/downstream 接口(属性设置) => 成功
17 17 POST {{baseUrl}}/iot/device/downstream
18 18 Content-Type: application/json
19   -tenant-id: {{adminTenentId}}
  19 +tenant-id: {{adminTenantId}}
20 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 8 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
9 9 import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.*;
10 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 12 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
12 13 import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInstanceDO;
13 14 import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum;
... ... @@ -52,6 +53,8 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic
52 53  
53 54 @Resource
54 55 private IotDeviceProducer deviceProducer;
  56 + @Resource
  57 + private IotDeviceMessageProducer deviceMessageProducer;
55 58  
56 59 @Override
57 60 public IotDeviceMessage downstreamDevice(IotDeviceDownstreamReqVO downstreamReqVO) {
... ... @@ -150,26 +153,16 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic
150 153 // TODO @super:【可优化】过滤掉不合法的属性
151 154  
152 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 32 *
33 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 71 * 例如说:属性上报的 properties、事件上报的 params
72 72 */
73 73 private Object data;
  74 + // TODO @芋艿:可能会去掉
74 75 /**
75 76 * 响应码
76 77 *
... ... @@ -100,6 +101,20 @@ public class IotDeviceMessage {
100 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 118 public static IotDeviceMessage of(String productKey, String deviceName, String deviceKey,
104 119 String requestId, LocalDateTime reportTime,
105 120 String serverId, Long tenantId) {
... ... @@ -117,7 +132,7 @@ public class IotDeviceMessage {
117 132  
118 133 // ========== Topic 相关 ==========
119 134  
120   - public static String getMessageBusGatewayDeviceMessageTopic(String serverId) {
  135 + public static String buildMessageBusGatewayDeviceMessageTopic(String serverId) {
121 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 30 * @param message 设备消息
31 31 */
32 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 1 package cn.iocoder.yudao.module.iot.net.component.http.config;
2 2  
3   -import cn.hutool.system.SystemUtil;
4 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 7 import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer;
6   -import cn.iocoder.yudao.module.iot.net.component.core.config.IotNetComponentCommonProperties;
7 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 9 import cn.iocoder.yudao.module.iot.net.component.http.downstream.IotDeviceDownstreamHandlerImpl;
11 10 import cn.iocoder.yudao.module.iot.net.component.http.upstream.IotDeviceUpstreamServer;
12 11 import io.vertx.core.Vertx;
... ... @@ -36,15 +35,6 @@ import org.springframework.context.event.EventListener;
36 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 38 * 初始化 HTTP 组件
49 39 *
50 40 * @param event 应用启动事件
... ... @@ -53,27 +43,30 @@ public class IotNetComponentHttpAutoConfiguration {
53 43 public void initialize(ApplicationStartedEvent event) {
54 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 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 32 private final IotDeviceMessageProducer deviceMessageProducer;
33 33  
34 34 @Override
35   - public void start() throws Exception {
  35 + public void start() {
36 36 start(Promise.promise());
37 37 }
38 38  
... ...