Commit c6b58b0ebfbfdac305f8ae9d32de6156faba8131
1 parent
6a1798bf
【代码评审】IoT:数据桥梁实现
Showing
5 changed files
with
19 additions
and
14 deletions
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 的序列化 |