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,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