Commit c6b58b0ebfbfdac305f8ae9d32de6156faba8131

Authored by YunaiV
1 parent 6a1798bf

【代码评审】IoT:数据桥梁实现

yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java
@@ -7,12 +7,7 @@ import lombok.extern.slf4j.Slf4j; @@ -7,12 +7,7 @@ import lombok.extern.slf4j.Slf4j;
7 7
8 import java.time.Duration; 8 import java.time.Duration;
9 9
10 -// TODO @芋艿:因为下面的,都是有状态的,所以通过 guava 缓存连接,然后通过 RemovalNotification 实现关闭。例如说,一次新建有效期是 10 分钟;  
11 -// TODO @芋艿:mq-redis  
12 -// TODO @芋艿:mq-数据库  
13 -// TODO @芋艿:kafka  
14 -// TODO @芋艿:rocketmq  
15 -// TODO @芋艿:rabbitmq 10 +// TODO @芋艿:数据库
16 // TODO @芋艿:mqtt 11 // TODO @芋艿:mqtt
17 // TODO @芋艿:tcp 12 // TODO @芋艿:tcp
18 // TODO @芋艿:websocket 13 // TODO @芋艿:websocket
@@ -25,6 +20,7 @@ import java.time.Duration; @@ -25,6 +20,7 @@ import java.time.Duration;
25 @Slf4j 20 @Slf4j
26 public abstract class AbstractCacheableDataBridgeExecute implements IotDataBridgeExecute { 21 public abstract class AbstractCacheableDataBridgeExecute implements IotDataBridgeExecute {
27 22
  23 + // TODO @huihui:AbstractCacheableDataBridgeExecute<Producer> 这样,下面的 Object, Object 就有了类型;另外 IotDataBridgeDO.Config 可以替代一个 Object 哇,
28 /** 24 /**
29 * Producer 缓存 25 * Producer 缓存
30 */ 26 */
@@ -43,12 +39,14 @@ public abstract class AbstractCacheableDataBridgeExecute implements IotDataBridg @@ -43,12 +39,14 @@ public abstract class AbstractCacheableDataBridgeExecute implements IotDataBridg
43 } 39 }
44 }) 40 })
45 .build(new CacheLoader<Object, Object>() { 41 .build(new CacheLoader<Object, Object>() {
  42 +
46 @Override 43 @Override
47 public Object load(Object config) throws Exception { 44 public Object load(Object config) throws Exception {
48 Object producer = initProducer(config); 45 Object producer = initProducer(config);
49 log.info("[PRODUCER_CACHE][配置({}) 对应的 producer 已创建并启动]", config); 46 log.info("[PRODUCER_CACHE][配置({}) 对应的 producer 已创建并启动]", config);
50 return producer; 47 return producer;
51 } 48 }
  49 +
52 }); 50 });
53 51
54 /** 52 /**
@@ -77,4 +75,4 @@ public abstract class AbstractCacheableDataBridgeExecute implements IotDataBridg @@ -77,4 +75,4 @@ public abstract class AbstractCacheableDataBridgeExecute implements IotDataBridg
77 */ 75 */
78 protected abstract void closeProducer(Object producer); 76 protected abstract void closeProducer(Object producer);
79 77
80 -}  
81 \ No newline at end of file 78 \ No newline at end of file
  79 +}
82 \ No newline at end of file 80 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java
@@ -11,6 +11,8 @@ import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; @@ -11,6 +11,8 @@ import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
11 */ 11 */
12 public interface IotDataBridgeExecute { 12 public interface IotDataBridgeExecute {
13 13
  14 + // TODO @huihui:要不搞个 getType?然后 execute0 由子类实现。这样,子类的 executeRedisStream ,其实就是 execute0 了。
  15 +
14 /** 16 /**
15 * 执行数据桥梁操作 17 * 执行数据桥梁操作
16 * 18 *
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java
@@ -10,6 +10,7 @@ import org.springframework.kafka.core.DefaultKafkaProducerFactory; @@ -10,6 +10,7 @@ import org.springframework.kafka.core.DefaultKafkaProducerFactory;
10 import org.springframework.kafka.core.KafkaTemplate; 10 import org.springframework.kafka.core.KafkaTemplate;
11 import org.springframework.stereotype.Component; 11 import org.springframework.stereotype.Component;
12 12
  13 +import java.time.Duration;
13 import java.time.LocalDateTime; 14 import java.time.LocalDateTime;
14 import java.util.HashMap; 15 import java.util.HashMap;
15 import java.util.Map; 16 import java.util.Map;
@@ -25,13 +26,15 @@ import java.util.concurrent.TimeoutException; @@ -25,13 +26,15 @@ import java.util.concurrent.TimeoutException;
25 @Slf4j 26 @Slf4j
26 public class IotKafkaMQDataBridgeExecute extends AbstractCacheableDataBridgeExecute { 27 public class IotKafkaMQDataBridgeExecute extends AbstractCacheableDataBridgeExecute {
27 28
  29 + private static final Duration SEND_TIMEOUT = Duration.ofMillis(10);
  30 +
28 @Override 31 @Override
29 public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { 32 public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) {
30 - // 1.1 校验数据桥梁的类型 == KAFKA 33 + // 1. 校验数据桥梁的类型 == KAFKA
31 if (!IotDataBridgTypeEnum.KAFKA.getType().equals(dataBridge.getType())) { 34 if (!IotDataBridgTypeEnum.KAFKA.getType().equals(dataBridge.getType())) {
32 return; 35 return;
33 } 36 }
34 - // 1.2 执行 Kafka 发送消息 37 + // 2. 执行 Kafka 发送消息
35 executeKafka(message, (IotDataBridgeDO.KafkaMQConfig) dataBridge.getConfig()); 38 executeKafka(message, (IotDataBridgeDO.KafkaMQConfig) dataBridge.getConfig());
36 } 39 }
37 40
@@ -43,7 +46,7 @@ public class IotKafkaMQDataBridgeExecute extends AbstractCacheableDataBridgeExec @@ -43,7 +46,7 @@ public class IotKafkaMQDataBridgeExecute extends AbstractCacheableDataBridgeExec
43 46
44 // 2. 发送消息并等待结果 47 // 2. 发送消息并等待结果
45 kafkaTemplate.send(config.getTopic(), message.toString()) 48 kafkaTemplate.send(config.getTopic(), message.toString())
46 - .get(10, TimeUnit.SECONDS); // 添加超时等待 49 + .get(SEND_TIMEOUT.getSeconds(), TimeUnit.SECONDS); // 添加超时等待
47 log.info("[executeKafka][message({}) 发送成功]", message); 50 log.info("[executeKafka][message({}) 发送成功]", message);
48 } catch (TimeoutException e) { 51 } catch (TimeoutException e) {
49 log.error("[executeKafka][message({}) config({}) 发送超时]", message, config, e); 52 log.error("[executeKafka][message({}) config({}) 发送超时]", message, config, e);
@@ -55,13 +58,12 @@ public class IotKafkaMQDataBridgeExecute extends AbstractCacheableDataBridgeExec @@ -55,13 +58,12 @@ public class IotKafkaMQDataBridgeExecute extends AbstractCacheableDataBridgeExec
55 @Override 58 @Override
56 protected Object initProducer(Object config) { 59 protected Object initProducer(Object config) {
57 IotDataBridgeDO.KafkaMQConfig kafkaConfig = (IotDataBridgeDO.KafkaMQConfig) config; 60 IotDataBridgeDO.KafkaMQConfig kafkaConfig = (IotDataBridgeDO.KafkaMQConfig) config;
58 - 61 +
59 // 1.1 构建生产者配置 62 // 1.1 构建生产者配置
60 Map<String, Object> props = new HashMap<>(); 63 Map<String, Object> props = new HashMap<>();
61 props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaConfig.getBootstrapServers()); 64 props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaConfig.getBootstrapServers());
62 props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); 65 props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
63 props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class); 66 props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
64 -  
65 // 1.2 如果配置了认证信息 67 // 1.2 如果配置了认证信息
66 if (kafkaConfig.getUsername() != null && kafkaConfig.getPassword() != null) { 68 if (kafkaConfig.getUsername() != null && kafkaConfig.getPassword() != null) {
67 props.put("security.protocol", "SASL_PLAINTEXT"); 69 props.put("security.protocol", "SASL_PLAINTEXT");
@@ -70,7 +72,6 @@ public class IotKafkaMQDataBridgeExecute extends AbstractCacheableDataBridgeExec @@ -70,7 +72,6 @@ public class IotKafkaMQDataBridgeExecute extends AbstractCacheableDataBridgeExec
70 "org.apache.kafka.common.security.plain.PlainLoginModule required username=\"" 72 "org.apache.kafka.common.security.plain.PlainLoginModule required username=\""
71 + kafkaConfig.getUsername() + "\" password=\"" + kafkaConfig.getPassword() + "\";"); 73 + kafkaConfig.getUsername() + "\" password=\"" + kafkaConfig.getPassword() + "\";");
72 } 74 }
73 -  
74 // 1.3 如果启用 SSL 75 // 1.3 如果启用 SSL
75 if (Boolean.TRUE.equals(kafkaConfig.getSsl())) { 76 if (Boolean.TRUE.equals(kafkaConfig.getSsl())) {
76 props.put("security.protocol", "SSL"); 77 props.put("security.protocol", "SSL");
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java
@@ -51,6 +51,7 @@ public class IotRabbitMQDataBridgeExecute extends AbstractCacheableDataBridgeExe @@ -51,6 +51,7 @@ public class IotRabbitMQDataBridgeExecute extends AbstractCacheableDataBridgeExe
51 } 51 }
52 52
53 @Override 53 @Override
  54 + @SuppressWarnings("resource")
54 protected Object initProducer(Object config) throws Exception { 55 protected Object initProducer(Object config) throws Exception {
55 IotDataBridgeDO.RabbitMQConfig rabbitConfig = (IotDataBridgeDO.RabbitMQConfig) config; 56 IotDataBridgeDO.RabbitMQConfig rabbitConfig = (IotDataBridgeDO.RabbitMQConfig) config;
56 57
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java
@@ -42,6 +42,7 @@ public class IotRedisStreamMQDataBridgeExecute extends AbstractCacheableDataBrid @@ -42,6 +42,7 @@ public class IotRedisStreamMQDataBridgeExecute extends AbstractCacheableDataBrid
42 } 42 }
43 43
44 @SuppressWarnings("unchecked") 44 @SuppressWarnings("unchecked")
  45 + // TODO @huihui:try catch 交给父类来做,子类不处理异常
45 private void executeRedisStream(IotDeviceMessage message, IotDataBridgeDO.RedisStreamMQConfig config) { 46 private void executeRedisStream(IotDeviceMessage message, IotDataBridgeDO.RedisStreamMQConfig config) {
46 try { 47 try {
47 // 1. 获取 RedisTemplate 48 // 1. 获取 RedisTemplate
@@ -71,6 +72,7 @@ public class IotRedisStreamMQDataBridgeExecute extends AbstractCacheableDataBrid @@ -71,6 +72,7 @@ public class IotRedisStreamMQDataBridgeExecute extends AbstractCacheableDataBrid
71 serverConfig.setPassword(redisConfig.getPassword()); 72 serverConfig.setPassword(redisConfig.getPassword());
72 } 73 }
73 74
  75 + // TODO @huihui:看看能不能简化一些。按道理说,不用这么多的哈。
74 // 2.1 创建 RedissonClient 76 // 2.1 创建 RedissonClient
75 RedissonClient redisson = Redisson.create(redissonConfig); 77 RedissonClient redisson = Redisson.create(redissonConfig);
76 // 2.2 创建并配置 RedisTemplate 78 // 2.2 创建并配置 RedisTemplate
@@ -89,6 +91,7 @@ public class IotRedisStreamMQDataBridgeExecute extends AbstractCacheableDataBrid @@ -89,6 +91,7 @@ public class IotRedisStreamMQDataBridgeExecute extends AbstractCacheableDataBrid
89 91
90 @Override 92 @Override
91 protected void closeProducer(Object producer) { 93 protected void closeProducer(Object producer) {
  94 + // TODO @huihui:try catch 交给父类来做。子类不处理异常
92 if (producer instanceof RedisTemplate) { 95 if (producer instanceof RedisTemplate) {
93 RedisConnectionFactory factory = ((RedisTemplate<?, ?>) producer).getConnectionFactory(); 96 RedisConnectionFactory factory = ((RedisTemplate<?, ?>) producer).getConnectionFactory();
94 try { 97 try {
@@ -101,7 +104,7 @@ public class IotRedisStreamMQDataBridgeExecute extends AbstractCacheableDataBrid @@ -101,7 +104,7 @@ public class IotRedisStreamMQDataBridgeExecute extends AbstractCacheableDataBrid
101 } 104 }
102 } 105 }
103 106
104 - 107 + // TODO @huihui:看看能不能简化一些。按道理说,不用这么多的哈。
105 public static RedisSerializer<?> buildRedisSerializer() { 108 public static RedisSerializer<?> buildRedisSerializer() {
106 RedisSerializer<Object> json = RedisSerializer.json(); 109 RedisSerializer<Object> json = RedisSerializer.json();
107 // 解决 LocalDateTime 的序列化 110 // 解决 LocalDateTime 的序列化