Răsfoiți Sursa

Merge branch 'master' into master-pdy-1219

# Conflicts:
#	iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/mapper/IotDeviceMapper.java
#	iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/mapper/IotProductMapper.java
#	iot-module/iot-module-manage/iot-module-manage-biz/src/main/resources/mapper/IotDeviceMapper.xml
#	iot-module/iot-module-manage/iot-module-manage-biz/src/main/resources/mapper/IotProductMapper.xml
sptkw 2 ani în urmă
părinte
comite
2df989b664
85 a modificat fișierele cu 1840 adăugiri și 162 ștergeri
  1. 8 0
      iot-framework/iot-starter-redis/src/main/java/com/middle/platform/redis/constant/CacheConstant.java
  2. 33 0
      iot-framework/iot-starter-redis/src/main/java/com/middle/platform/redis/service/CacheService.java
  3. 1 0
      iot-framework/iot-starter-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
  4. 3 1
      iot-gateway/src/main/resources/logback-spring.xml
  5. 1 1
      iot-module/iot-module-auth/iot-module-auth-api/src/main/java/com/middle/platform/auth/api/feign/AuthApi.java
  6. 3 1
      iot-module/iot-module-auth/iot-module-auth-biz/src/main/resources/logback-spring.xml
  7. 5 5
      iot-module/iot-module-data/iot-module-data-api/src/main/java/com/middle/platform/data/api/constant/TopicConstant.java
  8. 11 0
      iot-module/iot-module-data/iot-module-data-api/src/main/java/com/middle/platform/data/api/constant/TopicType.java
  9. 1 1
      iot-module/iot-module-data/iot-module-data-api/src/main/java/com/middle/platform/data/api/feign/DataApi.java
  10. 3 0
      iot-module/iot-module-data/iot-module-data-api/src/main/java/com/middle/platform/data/api/feign/DynamicTopicApi.java
  11. 21 0
      iot-module/iot-module-data/iot-module-data-api/src/main/java/com/middle/platform/data/api/feign/TdApi.java
  12. 6 0
      iot-module/iot-module-data/iot-module-data-api/src/main/java/com/middle/platform/data/api/pojo/TopicDto.java
  13. 8 0
      iot-module/iot-module-data/iot-module-data-biz/pom.xml
  14. 13 0
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/api/DynamicTopicApiImpl.java
  15. 24 0
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/api/TdApiImpl.java
  16. 18 0
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/config/FeignConfig.java
  17. 1 1
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/config/MqttConfig.java
  18. 22 0
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/controller/DataController.java
  19. 3 2
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/controller/IndexController.java
  20. 19 0
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/event/DataEvent.java
  21. 0 18
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/mapper/ProductMapper.java
  22. 84 0
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/mapper/TaosMapper.java
  23. 27 0
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/pojo/OriginalPara.java
  24. 16 7
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/pojo/ProductPara.java
  25. 15 0
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/pojo/mod/DataTypeDto.java
  26. 22 0
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/pojo/mod/ModDto.java
  27. 41 0
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/pojo/mod/Property.java
  28. 20 0
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/pojo/mod/SpecsDto.java
  29. 88 0
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/service/DataService.java
  30. 5 3
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/service/MqttService.java
  31. 128 0
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/service/ProductAnalyse.java
  32. 1 1
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/service/mqtt/FuncPerEnum.java
  33. 1 1
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/service/mqtt/MqttStrategyFactory.java
  34. 32 22
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/service/mqtt/MqttTopicInit.java
  35. 7 1
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/service/mqtt/MqttTopicStrategy.java
  36. 11 0
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/service/mqtt/impl/DynamicTopic.java
  37. 29 3
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/service/mqtt/strategy/AttrReportStrategy.java
  38. 1 1
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/service/mqtt/strategy/EventReportStrategy.java
  39. 22 0
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/service/runner/TopicRunner.java
  40. 50 0
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/utils/MqttTopicUtil.java
  41. 28 0
      iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/utils/TsUtil.java
  42. 4 1
      iot-module/iot-module-data/iot-module-data-biz/src/main/resources/bootstrap.yaml
  43. 3 1
      iot-module/iot-module-data/iot-module-data-biz/src/main/resources/logback-spring.xml
  44. 0 5
      iot-module/iot-module-data/iot-module-data-biz/src/main/resources/mapper/ProductMapper.xml
  45. 43 0
      iot-module/iot-module-data/iot-module-data-biz/src/main/resources/mapper/TaosMapper.xml
  46. 10 1
      iot-module/iot-module-manage/iot-module-manage-api/pom.xml
  47. 0 8
      iot-module/iot-module-manage/iot-module-manage-api/src/main/java/com/middle/platform/manage/api/Test.java
  48. 11 0
      iot-module/iot-module-manage/iot-module-manage-api/src/main/java/com/middle/platform/manage/api/enums/DataFormatConstant.java
  49. 29 0
      iot-module/iot-module-manage/iot-module-manage-api/src/main/java/com/middle/platform/manage/api/feign/CloudApi.java
  50. 20 0
      iot-module/iot-module-manage/iot-module-manage-api/src/main/java/com/middle/platform/manage/api/feign/ModApi.java
  51. 38 0
      iot-module/iot-module-manage/iot-module-manage-api/src/main/java/com/middle/platform/manage/api/feign/ProductApi.java
  52. 26 0
      iot-module/iot-module-manage/iot-module-manage-api/src/main/java/com/middle/platform/manage/api/pojo/IotCloudVo.java
  53. 31 0
      iot-module/iot-module-manage/iot-module-manage-api/src/main/java/com/middle/platform/manage/api/pojo/ProductVo.java
  54. 21 0
      iot-module/iot-module-manage/iot-module-manage-api/src/main/java/com/middle/platform/manage/api/pojo/TopicVo.java
  55. 22 0
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/api/CloudApiImpl.java
  56. 21 0
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/api/ModApiImpl.java
  57. 30 0
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/api/ProductApiImpl.java
  58. 2 1
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/config/FeignConfig.java
  59. 2 2
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/constant/UrlInit.java
  60. 10 0
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/constant/UrlType.java
  61. 35 1
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/controller/IotDeviceController.java
  62. 15 3
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/controller/IotProductController.java
  63. 1 0
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/domain/req/DevicePage.java
  64. 1 32
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/domain/req/IotDevicePara.java
  65. 1 0
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/domain/req/IotUrlPara.java
  66. 4 0
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/domain/req/ProductPage.java
  67. 54 1
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/domain/vo/IotDeviceDetailVo.java
  68. 5 1
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/domain/vo/IotDeviceVo.java
  69. 82 0
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/domain/vo/IotProductDetailVo.java
  70. 27 0
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/domain/vo/IotProductDownVo.java
  71. 13 4
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/mapper/IotCloudMapper.java
  72. 13 0
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/mapper/IotDeviceMapper.java
  73. 16 0
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/mapper/IotProductMapper.java
  74. 22 0
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/service/IotCloudService.java
  75. 53 2
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/service/IotDeviceService.java
  76. 24 0
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/service/IotModService.java
  77. 68 8
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/service/IotProductService.java
  78. 98 6
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/service/IotUrlService.java
  79. 25 0
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/service/ThreadTask.java
  80. 2 3
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/resources/bootstrap.yaml
  81. 2 1
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/resources/logback-spring.xml
  82. 16 2
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/resources/mapper/IotCloudMapper.xml
  83. 67 9
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/resources/mapper/IotDeviceMapper.xml
  84. 39 0
      iot-module/iot-module-manage/iot-module-manage-biz/src/main/resources/mapper/IotProductMapper.xml
  85. 2 1
      iot-module/iot-module-system/iot-module-system-biz/src/main/resources/logback-spring.xml

+ 8 - 0
iot-framework/iot-starter-redis/src/main/java/com/middle/platform/redis/constant/CacheConstant.java

@@ -9,4 +9,12 @@ public interface CacheConstant {
     String DICT_CACHE = "dict:%s";
     String DICT_ITEM_CACHE = "dictItem:%s:%s";
     String TOPIC_CACHE = "topic:%s";
+    String PRODUCT_CACHE = "product:%s:%s";
+    String MOD_CACHE = "mod:%s";
+    String CLOUD_CACHE = "cloud:%s";
+    //td源数据,是否建子表缓存
+    String TD_ORG_CACHE = "td:org:%s:%s";
+    //td转换后的数据,是否建子表缓存
+    String TD_CACHE = "td:%s:%s";
+
 }

+ 33 - 0
iot-framework/iot-starter-redis/src/main/java/com/middle/platform/redis/service/CacheService.java

@@ -0,0 +1,33 @@
+package com.middle.platform.redis.service;
+
+import com.middle.platform.redis.constant.CacheConstant;
+import jakarta.annotation.Resource;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+/**
+ * 产品相关缓存
+ *
+ * @author xucaiqin
+ * @date 2023-12-23 15:56:57
+ */
+@Component
+public class CacheService {
+    @Resource
+    private RedisTemplate<String, Object> redisTemplate;
+
+    /**
+     * CacheConstant.TOPIC_CACHE 保存
+     *
+     * @param key
+     * @param val
+     */
+    public void setTopic(String key, String val) {
+        redisTemplate.opsForValue().set(String.format(CacheConstant.TOPIC_CACHE, key), val);
+    }
+    public void delTopic(String key){
+        redisTemplate.delete(String.format(CacheConstant.TOPIC_CACHE, key));
+    }
+
+
+}

+ 1 - 0
iot-framework/iot-starter-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

@@ -1 +1,2 @@
 com.middle.platform.redis.config.RedisAutoConfiguration
+com.middle.platform.redis.service.CacheService

+ 3 - 1
iot-gateway/src/main/resources/logback-spring.xml

@@ -11,7 +11,9 @@
 
     <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义后,可以使“${}”来使用变量。 -->
     <property name="log.path" value="logs"/>
-    <springProperty scope="context" name="LOG_HOME" source="spring.application.name" defaultValue="iot-gateway"/>
+    <property name="LOG_HOME" value="iot-gateway"/>
+
+<!--    <springProperty scope="context" name="LOG_HOME" source="spring.application.name" defaultValue="iot-gateway"/>-->
     <!--0. 日志格式和颜色渲染 -->
     <!-- 彩色日志依赖的渲染类 -->
     <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>

+ 1 - 1
iot-module/iot-module-auth/iot-module-auth-api/src/main/java/com/middle/platform/auth/api/feign/AuthApi.java

@@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.RequestParam;
  */
 @FeignClient(name = ApiConstants.NAME)
 public interface AuthApi {
-    String prefix = RpcConstants.RPC_API_PREFIX+"auth";
+    String prefix = RpcConstants.RPC_API_PREFIX+"/auth";
 
     @GetMapping(prefix + "/get")
     String queryAccount(@RequestParam("account") String account);

+ 3 - 1
iot-module/iot-module-auth/iot-module-auth-biz/src/main/resources/logback-spring.xml

@@ -11,7 +11,9 @@
 
     <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义后,可以使“${}”来使用变量。 -->
     <property name="log.path" value="logs"/>
-    <springProperty scope="context" name="LOG_HOME" source="spring.application.name" defaultValue="iot-auth"/>
+    <property name="LOG_HOME" value="iot-auth"/>
+
+<!--    <springProperty scope="context" name="LOG_HOME" source="spring.application.name" defaultValue="iot-auth"/>-->
     <!--0. 日志格式和颜色渲染 -->
     <!-- 彩色日志依赖的渲染类 -->
     <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>

+ 5 - 5
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/constant/TopicConstant.java → iot-module/iot-module-data/iot-module-data-api/src/main/java/com/middle/platform/data/api/constant/TopicConstant.java

@@ -1,4 +1,4 @@
-package com.middle.platform.data.biz.constant;
+package com.middle.platform.data.api.constant;
 
 /**
  * @author xucaiqin
@@ -6,12 +6,12 @@ package com.middle.platform.data.biz.constant;
  */
 public interface TopicConstant {
     //属性上报-发布
-    String ATTR_PUB = "1-1";
+    String ATTR_PUB = "1"+TopicType.PUB;
     //云端响应属性上报-订阅
-    String ATTR_SUB = "1-2";
+    String ATTR_SUB = "1"+TopicType.SUB;
     //事件上报
-    String EVENT_PUB = "2-1";
+    String EVENT_PUB = "2"+TopicType.PUB;
     //云端响应事件上报-订阅
-    String EVENT_SUB = "2-2";
+    String EVENT_SUB = "2"+TopicType.SUB;
 
 }

+ 11 - 0
iot-module/iot-module-data/iot-module-data-api/src/main/java/com/middle/platform/data/api/constant/TopicType.java

@@ -0,0 +1,11 @@
+package com.middle.platform.data.api.constant;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-22 16:22:37
+ */
+public interface TopicType {
+    Integer PUB = 1;
+    Integer SUB = 2;
+    Integer BOTH = 3;
+}

+ 1 - 1
iot-module/iot-module-data/iot-module-data-api/src/main/java/com/middle/platform/data/api/feign/DataApi.java

@@ -4,5 +4,5 @@ package com.middle.platform.data.api.feign;
  * @author xucaiqin
  * @date 2023-12-17 16:05:08
  */
-public class DataApi {
+public interface DataApi {
 }

+ 3 - 0
iot-module/iot-module-data/iot-module-data-api/src/main/java/com/middle/platform/data/api/feign/DynamicTopicApi.java

@@ -15,6 +15,9 @@ import org.springframework.web.bind.annotation.RequestBody;
 public interface DynamicTopicApi {
     String PREFIX = RpcConstants.RPC_API_PREFIX + "/dynamic-topic";
 
+    @PostMapping(PREFIX + "/removeTopic")
+    Boolean removeTopic(@RequestBody TopicDto topicDto);
+
     @PostMapping(PREFIX + "/saveTopic")
     Boolean saveTopic(@RequestBody TopicDto topicDto);
 

+ 21 - 0
iot-module/iot-module-data/iot-module-data-api/src/main/java/com/middle/platform/data/api/feign/TdApi.java

@@ -0,0 +1,21 @@
+package com.middle.platform.data.api.feign;
+
+import com.middle.platform.common.constant.RpcConstants;
+import com.middle.platform.data.api.enums.ApiConstants;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+/**
+ * td相关接口
+ *
+ * @author xucaiqin
+ * @date 2023-12-17 16:05:08
+ */
+@FeignClient(name = ApiConstants.NAME, contextId = "tdApi")
+public interface TdApi {
+    String PREFIX = RpcConstants.RPC_API_PREFIX + "/taos";
+
+    @PostMapping(PREFIX + "/createProduct")
+    void createProduct(@RequestParam("code") String code);
+}

+ 6 - 0
iot-module/iot-module-data/iot-module-data-api/src/main/java/com/middle/platform/data/api/pojo/TopicDto.java

@@ -1,6 +1,8 @@
 package com.middle.platform.data.api.pojo;
 
+import lombok.AllArgsConstructor;
 import lombok.Getter;
+import lombok.NoArgsConstructor;
 import lombok.Setter;
 
 /**
@@ -9,5 +11,9 @@ import lombok.Setter;
  */
 @Getter
 @Setter
+@AllArgsConstructor
+@NoArgsConstructor
 public class TopicDto {
+    private String topic;
+    private Integer qos;
 }

+ 8 - 0
iot-module/iot-module-data/iot-module-data-biz/pom.xml

@@ -17,6 +17,10 @@
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     </properties>
     <dependencies>
+        <dependency>
+            <groupId>com.middle.platform</groupId>
+            <artifactId>iot-common</artifactId>
+        </dependency>
         <!-- Spring Cloud 基础 -->
         <dependency>
             <groupId>org.springframework.cloud</groupId>
@@ -64,6 +68,10 @@
             <groupId>com.middle.platform</groupId>
             <artifactId>iot-module-data-api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.middle.platform</groupId>
+            <artifactId>iot-module-manage-api</artifactId>
+        </dependency>
 
     </dependencies>
 </project>

+ 13 - 0
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/api/DynamicTopicApiImpl.java

@@ -1,6 +1,7 @@
 package com.middle.platform.data.biz.api;
 
 import com.middle.platform.data.api.feign.DynamicTopicApi;
+import com.middle.platform.data.api.pojo.TopicDto;
 import com.middle.platform.data.biz.service.mqtt.impl.DynamicTopic;
 import lombok.RequiredArgsConstructor;
 import org.springframework.validation.annotation.Validated;
@@ -15,4 +16,16 @@ import org.springframework.web.bind.annotation.RestController;
 @RequiredArgsConstructor
 public class DynamicTopicApiImpl implements DynamicTopicApi {
     private final DynamicTopic dynamicTopic;
+
+    @Override
+    public Boolean removeTopic(TopicDto topicDto) {
+        dynamicTopic.removeTopic(topicDto.getTopic());
+        return true;
+    }
+
+    @Override
+    public Boolean saveTopic(TopicDto topicDto) {
+        dynamicTopic.addTopic(topicDto.getTopic(), topicDto.getQos());
+        return true;
+    }
 }

+ 24 - 0
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/api/TdApiImpl.java

@@ -0,0 +1,24 @@
+package com.middle.platform.data.biz.api;
+
+import com.middle.platform.data.api.feign.TdApi;
+import com.middle.platform.data.biz.mapper.TaosMapper;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-24 16:22:04
+ */
+@RestController
+@Validated
+@RequiredArgsConstructor
+public class TdApiImpl implements TdApi {
+    private final TaosMapper taosMapper;
+
+    @Override
+    public void createProduct(String code) {
+        taosMapper.createProduct(code);
+        taosMapper.createOriginal(code);
+    }
+}

+ 18 - 0
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/config/FeignConfig.java

@@ -0,0 +1,18 @@
+package com.middle.platform.data.biz.config;
+
+import com.middle.platform.manage.api.feign.CloudApi;
+import com.middle.platform.manage.api.feign.ModApi;
+import com.middle.platform.manage.api.feign.ProductApi;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 配置feign接口
+ *
+ * @author xucaiqin
+ * @date 2023-12-19 11:00:25
+ */
+@Configuration
+@EnableFeignClients(clients = {CloudApi.class, ModApi.class, ProductApi.class})
+public class FeignConfig {
+}

+ 1 - 1
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/config/MqttConfig.java

@@ -53,7 +53,7 @@ public class MqttConfig {
     @Bean("mqttPahoMessageDrivenChannelAdapter")
     public MessageProducer inbound(MqttPahoClientFactory mqttPahoClientFactory) {
         MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(
-                mqttProperties.getClientId(), mqttPahoClientFactory,"/iot/device");
+                mqttProperties.getClientId(), mqttPahoClientFactory);
         adapter.setCompletionTimeout(5000);
         adapter.setConverter(new DefaultPahoMessageConverter());
         adapter.setQos(1);

+ 22 - 0
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/controller/DataController.java

@@ -0,0 +1,22 @@
+package com.middle.platform.data.biz.controller;
+
+import com.middle.platform.data.biz.pojo.ProductPara;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-15 08:46:49
+ */
+@RestController
+@RequestMapping("/data")
+public class DataController {
+
+
+    @PostMapping("/up")
+    public void test(@RequestBody ProductPara productPara) {
+    }
+
+}

+ 3 - 2
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/controller/IndexController.java

@@ -2,7 +2,7 @@ package com.middle.platform.data.biz.controller;
 
 import com.middle.platform.common.utils.DateTimeUtil;
 import com.middle.platform.common.utils.Result;
-import com.middle.platform.data.biz.mapper.ProductMapper;
+import com.middle.platform.data.biz.mapper.TaosMapper;
 import com.middle.platform.data.biz.pojo.ProductPara;
 import jakarta.annotation.Resource;
 import org.springframework.beans.factory.annotation.Value;
@@ -21,7 +21,7 @@ public class IndexController {
     @Value("${spring.application.name}")
     private String name;
     @Resource
-    private ProductMapper productMapper;
+    private TaosMapper productMapper;
     @Resource
     private MqttPahoMessageDrivenChannelAdapter mqttPahoMessageDrivenChannelAdapter;
 
@@ -36,4 +36,5 @@ public class IndexController {
     public void test(@RequestBody ProductPara productPara) {
         productMapper.insert(productPara);
     }
+
 }

+ 19 - 0
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/event/DataEvent.java

@@ -0,0 +1,19 @@
+package com.middle.platform.data.biz.event;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-24 11:07:47
+ */
+@Component
+@Slf4j
+public class DataEvent implements ApplicationListener<ApplicationEvent> {
+    @Override
+    public void onApplicationEvent(ApplicationEvent event) {
+        log.info("事件:{}", event.getClass().getName());
+    }
+}

+ 0 - 18
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/mapper/ProductMapper.java

@@ -1,18 +0,0 @@
-package com.middle.platform.data.biz.mapper;
-
-import com.baomidou.dynamic.datasource.annotation.DS;
-import com.middle.platform.data.biz.pojo.ProductPara;
-import org.apache.ibatis.annotations.Insert;
-import org.apache.ibatis.annotations.Mapper;
-
-/**
- * @author xucaiqin
- * @date 2023-12-20 09:22:38
- */
-@Mapper
-@DS("td")
-public interface ProductMapper {
-    @Insert("INSERT INTO device_gnss_${deviceId} (create_time,point_value,raw_value,origin_time) VALUES (#{createTime},#{pointValue},#{rawValue},#{originTime})")
-    void insert(ProductPara productPara);
-
-}

+ 84 - 0
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/mapper/TaosMapper.java

@@ -0,0 +1,84 @@
+package com.middle.platform.data.biz.mapper;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.middle.platform.data.biz.pojo.OriginalPara;
+import com.middle.platform.data.biz.pojo.ProductPara;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-20 09:22:38
+ */
+@Mapper
+@DS("td")
+public interface TaosMapper {
+    /**
+     * 产品(超级表)
+     *
+     * @param code 产品编码
+     * @return
+     */
+    void createProduct(@Param("code") String code);
+
+    /**
+     * 创建设备表(子表)
+     *
+     * @param guid 设备guid
+     * @param code 产品编码
+     * @return
+     */
+    int createDeviceTable(@Param("guid") String guid, @Param("code") String code);
+
+    /**
+     * 写入设备表数据
+     *
+     * @param productPara
+     */
+    void insert(ProductPara productPara);
+
+    /**
+     * 批量写入设备表数据
+     *
+     * @param collect
+     * @return
+     */
+    int batchInsert(@Param("list") List<ProductPara> collect, @Param("guid") String guid, @Param("code") String code);
+
+
+    /*原始数据*/
+
+    /**
+     * 原始数据表(超级表)
+     *
+     * @param code
+     * @return
+     */
+    void createOriginal(@Param("code") String code);
+
+    /**
+     * 原始数据表(子表)
+     *
+     * @param guid
+     * @param code 产品编码
+     * @return
+     */
+    void createOriginalTable(@Param("guid") String guid, @Param("code") String code);
+
+    /**
+     * 写入原始数据表数据
+     *
+     * @param originalPara
+     */
+    int insertOriginal(OriginalPara originalPara);
+
+    /**
+     * 批量写入设备表数据
+     *
+     * @param collect
+     * @return
+     */
+    int batchInsertOriginal(@Param("list") List<OriginalPara> collect, @Param("guid") String guid, @Param("code") String code);
+}

+ 27 - 0
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/pojo/OriginalPara.java

@@ -0,0 +1,27 @@
+package com.middle.platform.data.biz.pojo;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-20 09:26:56
+ */
+@Getter
+@Setter
+public class OriginalPara {
+    private String code;
+    private String guid;
+    /**
+     * 源数据
+     */
+    private String rawStr;
+    /**
+     * 创建时间
+     */
+    private Date ts;
+    private String msgId;
+
+}

+ 16 - 7
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/pojo/ProductPara.java

@@ -12,19 +12,28 @@ import java.util.Date;
 @Getter
 @Setter
 public class ProductPara {
-    private String deviceId;
-    private String pointId;
+    private String code;
+
+    private String guid;
+    /**
+     * 字段
+     */
+    private String line;
     /**
-     * 处理值,进行过缩放、格式化等操作
+     * 预留字段
      */
-    private String pointValue;
+    private String reserve;
 
     /**
-     * 原始值
+     * 值
+     */
+    private String val;
+    /**
+     * 消息唯一id
      */
-    private String rawValue;
+    private String msgId;
 
-    private Date createTime;
+    private Long ts;
 
     private Date originTime;
 }

+ 15 - 0
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/pojo/mod/DataTypeDto.java

@@ -0,0 +1,15 @@
+package com.middle.platform.data.biz.pojo.mod;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-24 11:31:39
+ */
+@Getter
+@Setter
+public class DataTypeDto {
+    private String type;
+    private SpecsDto specs;
+}

+ 22 - 0
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/pojo/mod/ModDto.java

@@ -0,0 +1,22 @@
+package com.middle.platform.data.biz.pojo.mod;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-24 11:21:47
+ */
+@Getter
+@Setter
+public class ModDto {
+    /**
+     * 属性
+     */
+    private List<Property> properties;
+
+    private List<Property> event;
+
+}

+ 41 - 0
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/pojo/mod/Property.java

@@ -0,0 +1,41 @@
+package com.middle.platform.data.biz.pojo.mod;
+
+import lombok.Data;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-24 11:22:21
+ */
+@NoArgsConstructor
+@Data
+@Getter
+@Setter
+public class Property {
+    /**
+     * 标识符
+     */
+    private String identifier;
+    /**
+     * 名称
+     */
+    private String name;
+    /**
+     * 读写/只读
+     */
+    private String accessMode;
+    /**
+     * 是否必填
+     */
+    private Boolean required;
+    /**
+     * 数据类型
+     */
+    private DataTypeDto dataTypeDto;
+    /**
+     * 描述
+     */
+    private String desc;
+}

+ 20 - 0
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/pojo/mod/SpecsDto.java

@@ -0,0 +1,20 @@
+package com.middle.platform.data.biz.pojo.mod;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-24 11:32:09
+ */
+@Getter
+@Setter
+public class SpecsDto {
+    private String min;
+    private String max;
+    private String step;
+    private String unit;
+    private String unitName;
+
+
+}

+ 88 - 0
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/service/DataService.java

@@ -0,0 +1,88 @@
+package com.middle.platform.data.biz.service;
+
+import cn.hutool.core.collection.CollUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.middle.platform.data.biz.mapper.TaosMapper;
+import com.middle.platform.data.biz.pojo.OriginalPara;
+import com.middle.platform.data.biz.pojo.ProductPara;
+import com.middle.platform.data.biz.utils.TsUtil;
+import com.middle.platform.manage.api.pojo.ProductVo;
+import com.middle.platform.redis.constant.CacheConstant;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-24 15:33:31
+ */
+@Component
+@Slf4j
+public class DataService {
+    @Resource
+    private TaosMapper taosMapper;
+    @Resource
+    private RedisTemplate<String, Object> redisTemplate;
+
+    /**
+     * 源数据处理
+     *
+     * @param productVo
+     * @param payload
+     */
+    public void rawData(String msgId, ProductVo productVo, Object payload) {
+        Object o = redisTemplate.opsForValue().get(String.format(CacheConstant.TD_ORG_CACHE, productVo.getCode(), productVo.getGuid()));
+        if (Objects.isNull(o)) {
+            taosMapper.createOriginalTable(productVo.getGuid(), productVo.getCode());
+            redisTemplate.opsForValue().set(String.format(CacheConstant.TD_ORG_CACHE, productVo.getCode(), productVo.getGuid()), true);
+        }
+        OriginalPara originalPara = new OriginalPara();
+        originalPara.setCode(productVo.getCode());
+        originalPara.setGuid(productVo.getGuid());
+        originalPara.setRawStr(payload.toString());
+        originalPara.setTs(new Date());
+        originalPara.setMsgId(msgId);
+
+        taosMapper.insertOriginal(originalPara);
+    }
+
+    /**
+     * 解析后的数据
+     *
+     * @param msgId
+     * @param productVo
+     * @param modData
+     */
+    public void analyzeData(String msgId, ProductVo productVo, Object modData) {
+        log.info("解析后的数据:{}", modData);
+        Object o = redisTemplate.opsForValue().get(String.format(CacheConstant.TD_CACHE, productVo.getCode(), productVo.getGuid()));
+        if (Objects.isNull(o)) {
+            taosMapper.createDeviceTable(productVo.getGuid(), productVo.getCode());
+            redisTemplate.opsForValue().set(String.format(CacheConstant.TD_CACHE, productVo.getCode(), productVo.getGuid()), true);
+        }
+        if (modData instanceof JSONObject jsonObject) {
+            List<ProductPara> list = new ArrayList<>();
+            ProductPara productPara;
+            for (Map.Entry<String, Object> map : jsonObject.entrySet()) {
+                productPara = new ProductPara();
+                productPara.setCode(productVo.getCode());
+                productPara.setGuid(productVo.getGuid());
+                productPara.setLine(map.getKey());
+                productPara.setReserve("");
+                productPara.setVal(String.valueOf(map.getValue()));
+                productPara.setMsgId(msgId);
+                productPara.setTs(TsUtil.getAndIncrement());
+                productPara.setOriginTime(new Date());//todo 有则获取
+                list.add(productPara);
+            }
+            if (CollUtil.isNotEmpty(list)) {
+                taosMapper.batchInsert(list, productVo.getGuid(), productVo.getCode());
+            }
+        }
+
+    }
+
+}

+ 5 - 3
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/service/MqttService.java

@@ -3,6 +3,7 @@ package com.middle.platform.data.biz.service;
 import com.middle.platform.data.biz.config.MqttConfig;
 import com.middle.platform.data.biz.service.mqtt.MqttStrategyFactory;
 import com.middle.platform.data.biz.service.mqtt.MqttTopicStrategy;
+import com.middle.platform.data.biz.utils.MqttTopicUtil;
 import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.context.annotation.Bean;
@@ -21,16 +22,17 @@ public class MqttService {
 
     @ServiceActivator(inputChannel = MqttConfig.input)
     @Bean
-    public MessageHandler test() {
+    public MessageHandler data() {
         return message -> {
             MessageHeaders headers = message.getHeaders();
             Object payload = message.getPayload();
             String topic = (String) headers.get("mqtt_receivedTopic");
             log.info("topic {}", topic);
             log.info("payload {}", payload);
-            MqttTopicStrategy mqttTopicStrategy = mqttStrategyFactory.getByTopic(topic);
+
+            MqttTopicStrategy mqttTopicStrategy = mqttStrategyFactory.getByTopic(MqttTopicUtil.replaceTopic(topic));
             if (Objects.nonNull(mqttTopicStrategy)) {
-                mqttTopicStrategy.dealMsg(payload);
+                mqttTopicStrategy.dealMsg(topic, payload);
             }
         };
     }

+ 128 - 0
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/service/ProductAnalyse.java

@@ -0,0 +1,128 @@
+package com.middle.platform.data.biz.service;
+
+import cn.hutool.core.collection.CollUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.middle.platform.data.biz.pojo.mod.ModDto;
+import com.middle.platform.data.biz.pojo.mod.Property;
+import com.middle.platform.manage.api.enums.DataFormatConstant;
+import com.middle.platform.manage.api.feign.CloudApi;
+import com.middle.platform.manage.api.feign.ModApi;
+import com.middle.platform.manage.api.feign.ProductApi;
+import com.middle.platform.manage.api.pojo.IotCloudVo;
+import com.middle.platform.manage.api.pojo.ProductVo;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+
+/**
+ * 产品解析
+ *
+ * @author xucaiqin
+ * @date 2023-12-23 13:56:23
+ */
+@Component
+@Slf4j
+public class ProductAnalyse {
+    @Resource
+    private CloudApi cloudApi;
+    @Resource
+    private ModApi modApi;
+    @Resource
+    private ProductApi productApi;
+
+    private Object objStrToJSON(Object object) {
+        try {
+            return JSONObject.parseObject(JSONObject.toJSONString(object));
+        } catch (Exception e) {
+            return object;
+        }
+    }
+
+    /**
+     * 通过产品key查询产品信息
+     *
+     * @param productKey 产品key
+     * @return
+     */
+    public ProductVo getProduct(String productKey, String deviceSn) {
+        return productApi.queryProduct(productKey, deviceSn);
+    }
+
+
+    /**
+     * 云函数转换数据
+     *
+     * @param productVo 产品
+     * @param payload   上报数据
+     * @return 云函数转换后的数据
+     */
+    public Object dataConvert(ProductVo productVo, Object payload) {
+        log.info("源数据:{}", payload);
+        IotCloudVo iotCloudVo = cloudApi.queryCloud(productVo.getId());
+        if (Objects.isNull(iotCloudVo)) {
+            log.warn("未找到云函数");
+            return objStrToJSON(payload);
+        }
+        //通过云函数转换 todo
+        if (productVo.getDataFormat().equals(DataFormatConstant.json)) {
+
+        }
+        return objStrToJSON(payload);
+    }
+
+    /**
+     * 物模型转换
+     *
+     * @param payload 云函数解析后的数据
+     * @return 解析为物模型对应属性数据
+     */
+    public Object modConvert(ProductVo productVo, Object payload) {
+        log.info("物模型数据转换:{}", payload);
+        String mod = modApi.queryMod(productVo.getId());
+        if (StringUtils.isNotBlank(mod)) {
+            ModDto modDto = JSONObject.parseObject(mod, ModDto.class);
+            return Optional.ofNullable(modDto)
+                    .map(ModDto::getProperties)
+                    .map(properties -> {
+                        if (payload instanceof String tmp) {
+                            JSONObject jsonObject = JSONObject.parseObject(tmp);
+                            return change(properties, jsonObject);
+                        }
+                        if (payload instanceof JSONObject jsonObject) {
+                            return change(properties, jsonObject);
+                        }
+                        return new JSONObject();
+                    }).orElse(new JSONObject());
+        }
+        return null;
+    }
+
+    /**
+     * 过滤物模型中的属性,仅保留物模型中的属性字段
+     *
+     * @param properties 物模型属性
+     * @param jsonObject 上报的json数据
+     * @return
+     */
+    private JSONObject change(List<Property> properties, JSONObject jsonObject) {
+        if (CollUtil.isEmpty(properties)) {
+            return jsonObject;
+        }
+        //物模型中需要保留的属性字段
+        List<String> key = properties.stream().map(Property::getIdentifier).toList();
+        //上报数据中,所有的字段
+        Set<String> keyAll = jsonObject.keySet();
+
+        // 仅保留需要的属性字段
+        List<String> collect = keyAll.stream().filter(one -> !key.contains(one)).toList();
+
+        // 使用 removeAll 方法一次性移除所有需要删除的字段
+        collect.forEach(jsonObject.keySet()::remove);
+        return jsonObject;
+    }
+
+
+}

+ 1 - 1
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/service/mqtt/FuncPerEnum.java

@@ -1,6 +1,6 @@
 package com.middle.platform.data.biz.service.mqtt;
 
-import com.middle.platform.data.biz.constant.TopicConstant;
+import com.middle.platform.data.api.constant.TopicConstant;
 import com.middle.platform.data.biz.service.mqtt.strategy.AttrReportStrategy;
 import com.middle.platform.data.biz.service.mqtt.strategy.EventReportStrategy;
 import lombok.AllArgsConstructor;

+ 1 - 1
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/service/mqtt/MqttStrategyFactory.java

@@ -15,7 +15,7 @@ public class MqttStrategyFactory {
     /**
      * 通过topic名称获取对应解析策略
      *
-     * @param topic mqtt主题
+     * @param topic mqtt主题 如:/iot/VGSogVDr1StQ/+/att
      * @return
      */
     public MqttTopicStrategy getByTopic(String topic) {

+ 32 - 22
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/service/mqtt/MqttTopicInit.java

@@ -1,29 +1,39 @@
 package com.middle.platform.data.biz.service.mqtt;
 
+import com.middle.platform.data.biz.service.mqtt.impl.DynamicTopic;
+import com.middle.platform.manage.api.feign.ProductApi;
+import com.middle.platform.manage.api.pojo.TopicVo;
+import com.middle.platform.redis.constant.CacheConstant;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Component
+@Slf4j
 public class MqttTopicInit {
-    private String topic;
-    private String name;
+    @Resource
+    private ProductApi productApi;
+    @Resource
+    private DynamicTopic dynamicTopic;
+    @Resource
+    private RedisTemplate<String, Object> redisTemplate;
+
+    public void init() {
+        List<TopicVo> topicVos = productApi.productTopic();
 
+        if (!CollectionUtils.isEmpty(topicVos)) {
+            log.info("初始化订阅:{}", topicVos);
+            Map<String, String> map = topicVos.stream().collect(Collectors.toMap(a -> String.format(CacheConstant.TOPIC_CACHE, a.getUrl()), b -> b.getFunc() + String.valueOf(b.getPermission()), (a, b) -> a));
+            redisTemplate.opsForValue().multiSet(map);
+            dynamicTopic.addTopic(topicVos.stream().map(TopicVo::getUrl).collect(Collectors.toList()));
+        }
+    }
 
-//
-//    public static String strategy(String topic) {
-//        for (MqttTopicEnum value : MqttTopicEnum.values()) {
-//            if (StringUtils.equals(value.getTopic(), topic)) {
-//                String beanName = value.getName();
-//                char[] chars = beanName.toCharArray();
-//                chars[0] += 32;
-//                return String.valueOf(chars);
-//            }
-//        }
-//        return null;
-//    }
-//
-//    public static String[] getTopics() {
-//        List<String> res = new ArrayList<>();
-//        for (MqttTopicEnum value : MqttTopicEnum.values()) {
-//            res.add(value.topic);
-//        }
-//        return res.toArray(String[]::new);
-//    }
 
 }

+ 7 - 1
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/service/mqtt/MqttTopicStrategy.java

@@ -1,6 +1,12 @@
 package com.middle.platform.data.biz.service.mqtt;
 
 public interface MqttTopicStrategy {
-    void dealMsg(Object msg);
+    /**
+     * 处理消息
+     *
+     * @param topic topic
+     * @param msg   消息
+     */
+    void dealMsg(String topic, Object msg);
 
 }

+ 11 - 0
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/service/mqtt/impl/DynamicTopic.java

@@ -4,6 +4,8 @@ import jakarta.annotation.Resource;
 import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
 import org.springframework.stereotype.Component;
 
+import java.util.List;
+
 /**
  * @author xucaiqin
  * @date 2023-12-22 13:52:20
@@ -31,4 +33,13 @@ public class DynamicTopic {
     public void removeTopic(String topic) {
         mqttPahoMessageDrivenChannelAdapter.removeTopic(topic);
     }
+
+    /**
+     * 批量订阅topic
+     *
+     * @param topic
+     */
+    public void addTopic(List<String> topic) {
+        mqttPahoMessageDrivenChannelAdapter.addTopic(topic.toArray(String[]::new));
+    }
 }

+ 29 - 3
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/service/mqtt/strategy/AttrReportStrategy.java

@@ -1,19 +1,45 @@
 package com.middle.platform.data.biz.service.mqtt.strategy;
 
+import cn.hutool.core.util.IdUtil;
+import com.middle.platform.data.biz.service.DataService;
+import com.middle.platform.data.biz.service.ProductAnalyse;
 import com.middle.platform.data.biz.service.mqtt.MqttTopicStrategy;
+import com.middle.platform.data.biz.utils.MqttTopicUtil;
+import com.middle.platform.manage.api.pojo.ProductVo;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
+import java.util.Objects;
+
 /**
  * 属性上报
  */
 @Service
 @Slf4j
+@RequiredArgsConstructor
 public class AttrReportStrategy implements MqttTopicStrategy {
+    private final ProductAnalyse productAnalyse;
+    private final DataService dataService;
 
     @Override
-    public void dealMsg(Object msg) {
-        log.debug("属性上报数据:{}", msg);
-
+    public void dealMsg(String topic, Object msg) {
+        log.info("属性[{}]上报数据:{}", topic, msg);
+        String deviceSn = MqttTopicUtil.getDeviceSn(topic);
+        String productKey = MqttTopicUtil.getProductKey(topic);
+        //获取产品信息
+        ProductVo productVo = productAnalyse.getProduct(productKey, deviceSn);
+        if (Objects.isNull(productVo)) {
+            return;
+        }
+        String msgId = IdUtil.fastSimpleUUID();
+        //1.源数据处理
+        dataService.rawData(msgId, productVo, msg);
+        //2.云函数解析
+        Object cloudData = productAnalyse.dataConvert(productVo, msg);
+        //3.物模型解析
+        Object modData = productAnalyse.modConvert(productVo, cloudData);
+        //4.存储解析后的数据
+        dataService.analyzeData(msgId, productVo, modData);
     }
 }

+ 1 - 1
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/service/mqtt/strategy/EventReportStrategy.java

@@ -12,7 +12,7 @@ import org.springframework.stereotype.Service;
 public class EventReportStrategy implements MqttTopicStrategy {
 
     @Override
-    public void dealMsg(Object msg) {
+    public void dealMsg(String guid,Object msg) {
         log.debug("属性上报数据:{}", msg);
 
     }

+ 22 - 0
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/service/runner/TopicRunner.java

@@ -0,0 +1,22 @@
+package com.middle.platform.data.biz.service.runner;
+
+import com.middle.platform.data.biz.service.mqtt.MqttTopicInit;
+import jakarta.annotation.Resource;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-23 15:59:53
+ */
+@Component
+public class TopicRunner implements ApplicationRunner {
+    @Resource
+    private MqttTopicInit mqttTopicInit;
+
+    @Override
+    public void run(ApplicationArguments args) throws Exception {
+        mqttTopicInit.init();
+    }
+}

+ 50 - 0
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/utils/MqttTopicUtil.java

@@ -0,0 +1,50 @@
+package com.middle.platform.data.biz.utils;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Optional;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-24 15:18:14
+ */
+public class MqttTopicUtil {
+    public static String getProductKey(String input) {
+        String pattern = "/iot/(.*?)/.*";
+        Pattern regex = Pattern.compile(pattern);
+        Matcher matcher = regex.matcher(input);
+
+        if (matcher.find()) {
+            // 提取匹配到的数据
+            return matcher.group(1);
+        }
+        return null;
+    }
+
+    /**
+     * 设备上报的sn
+     *
+     * @param input
+     * @return
+     */
+    public static String getDeviceSn(String input) {
+        String pattern = "/iot/[^/]+/([^/]+)/.*";
+        Pattern regex = Pattern.compile(pattern);
+        Matcher matcher = regex.matcher(input);
+
+        if (matcher.find()) {
+            // 提取匹配到的数据
+            return matcher.group(1);
+        }
+        return null;
+    }
+
+    public static String replaceTopic(String topic) {
+        return Optional.ofNullable(topic).map(t -> {
+            String s = StringUtils.startsWith(t, "/") ? "(/[^/]+/[^/]+)/[^/]+" : "([^/]+/[^/]+)/[^/]+";
+            return t.replaceFirst(s, "$1/+");
+        }).orElse(topic);
+    }
+}

+ 28 - 0
iot-module/iot-module-data/iot-module-data-biz/src/main/java/com/middle/platform/data/biz/utils/TsUtil.java

@@ -0,0 +1,28 @@
+package com.middle.platform.data.biz.utils;
+
+import java.util.Date;
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-25 14:31:39
+ */
+public class TsUtil {
+    private static final ThreadLocal<Long> threadLocal = new ThreadLocal<>();
+
+    /**
+     * td用ts作为主键id时,批量插入时间相同只会写入一条数据的解决方法
+     *
+     * @return
+     */
+    public static Long getAndIncrement() {
+        if (Objects.isNull(threadLocal.get())) {
+            long time = new Date().getTime();
+            threadLocal.set(time);
+            return time;
+        }
+        Optional.ofNullable(threadLocal.get()).ifPresent(g -> threadLocal.set(g + 1));
+        return threadLocal.get();
+    }
+}

+ 4 - 1
iot-module/iot-module-data/iot-module-data-biz/src/main/resources/bootstrap.yaml

@@ -18,5 +18,8 @@ spring:
       write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
       write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
       fail-on-empty-beans: false # 允许序列化无属性的 Bean
-
+logging:
+  level:
+    root: info
+    com.middle.platform: debug
 

+ 3 - 1
iot-module/iot-module-data/iot-module-data-biz/src/main/resources/logback-spring.xml

@@ -11,7 +11,9 @@
 
     <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义后,可以使“${}”来使用变量。 -->
     <property name="log.path" value="logs"/>
-    <springProperty scope="context" name="LOG_HOME" source="spring.application.name" defaultValue="iot-data"/>
+    <property name="LOG_HOME" value="iot-data"/>
+
+<!--    <springProperty scope="context" name="LOG_HOME" source="spring.application.name" defaultValue="iot-data"/>-->
     <!--0. 日志格式和颜色渲染 -->
     <!-- 彩色日志依赖的渲染类 -->
     <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>

+ 0 - 5
iot-module/iot-module-data/iot-module-data-biz/src/main/resources/mapper/ProductMapper.xml

@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.middle.platform.data.biz.mapper.ProductMapper">
-
-</mapper>

+ 43 - 0
iot-module/iot-module-data/iot-module-data-biz/src/main/resources/mapper/TaosMapper.xml

@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.middle.platform.data.biz.mapper.TaosMapper">
+    <update id="createProduct">
+        CREATE STABLE IF NOT EXISTS product_${code} (ts TIMESTAMP, line NCHAR(32),val NCHAR(32),msg_id
+        NCHAR(64),reserve NCHAR(64),origin_time TIMESTAMP) TAGS (guid NCHAR(32))
+    </update>
+    <update id="createDeviceTable">
+        CREATE TABLE IF NOT EXISTS device_${code}_${guid} using product_${code} TAGS (#{guid})
+    </update>
+
+    <insert id="insert">
+        INSERT INTO device_${code}_${guid} (ts, line, val, msg_id,reserve, origin_time)
+        VALUES (#{ts}, #{line}, #{val}, #{msgId}, #{reserve}, #{originTime})
+    </insert>
+    <insert id="batchInsert">
+        INSERT INTO device_${code}_${guid} (ts, line, val, msg_id, reserve, origin_time) VALUES
+        <foreach collection='list' item='item' index='index' separator=','>
+            (#{item.ts}, #{item.line}, #{item.val}, #{item.msgId}, #{item.reserve}, #{item.originTime})
+        </foreach>
+    </insert>
+
+    <!--源数据-->
+    <select id="createOriginal" >
+        create STABLE IF NOT EXISTS original_${code} (ts TIMESTAMP, raw_str varchar(10000),msg_id NCHAR(64)) tags (guid varchar(64));
+    </select>
+
+    <select id="createOriginalTable" >
+        CREATE TABLE IF NOT EXISTS original_${code}_${guid} using original_${code} TAGS (#{guid})
+    </select>
+
+    <insert id="insertOriginal">
+        INSERT INTO original_${code}_${guid} (ts, raw_str,msg_id)
+        VALUES (#{ts}, #{rawStr}, #{msgId})
+    </insert>
+
+    <select id="batchInsertOriginal" resultType="int">
+        INSERT INTO original_${code}_${guid} (ts, raw_str,msg_id) VALUES
+        <foreach collection='list' item='item' index='index' separator=',' >
+            (#{item.ts}, #{item.rawStr}, #{item.msgId})
+        </foreach>
+    </select>
+</mapper>

+ 10 - 1
iot-module/iot-module-manage/iot-module-manage-api/pom.xml

@@ -17,5 +17,14 @@
         <maven.compiler.target>17</maven.compiler.target>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     </properties>
-
+    <dependencies>
+        <dependency>
+            <groupId>com.middle.platform</groupId>
+            <artifactId>iot-starter-feign</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.middle.platform</groupId>
+            <artifactId>iot-common</artifactId>
+        </dependency>
+    </dependencies>
 </project>

+ 0 - 8
iot-module/iot-module-manage/iot-module-manage-api/src/main/java/com/middle/platform/manage/api/Test.java

@@ -1,8 +0,0 @@
-package com.middle.platform.manage.api;
-
-/**
- * @author xucaiqin
- * @date 2023-12-17 10:50:04
- */
-public class Test {
-}

+ 11 - 0
iot-module/iot-module-manage/iot-module-manage-api/src/main/java/com/middle/platform/manage/api/enums/DataFormatConstant.java

@@ -0,0 +1,11 @@
+package com.middle.platform.manage.api.enums;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-23 14:24:44
+ */
+public interface DataFormatConstant {
+    Integer json = 1;
+
+    Integer xml = 2;
+}

+ 29 - 0
iot-module/iot-module-manage/iot-module-manage-api/src/main/java/com/middle/platform/manage/api/feign/CloudApi.java

@@ -0,0 +1,29 @@
+package com.middle.platform.manage.api.feign;
+
+
+import com.middle.platform.common.constant.RpcConstants;
+import com.middle.platform.manage.api.enums.ApiConstants;
+import com.middle.platform.manage.api.pojo.IotCloudVo;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-17 11:09:05
+ */
+@FeignClient(name = ApiConstants.NAME, contextId = "cloudApi")
+public interface CloudApi {
+    String prefix = RpcConstants.RPC_API_PREFIX + "/cloud";
+
+    /**
+     * 通过topic获取云函数
+     *
+     * @param productId
+     * @return
+     */
+    @GetMapping(prefix + "/get")
+    IotCloudVo queryCloud(@RequestParam("productId") Long productId);
+
+
+}

+ 20 - 0
iot-module/iot-module-manage/iot-module-manage-api/src/main/java/com/middle/platform/manage/api/feign/ModApi.java

@@ -0,0 +1,20 @@
+package com.middle.platform.manage.api.feign;
+
+import com.middle.platform.common.constant.RpcConstants;
+import com.middle.platform.manage.api.enums.ApiConstants;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-17 11:09:05
+ */
+@FeignClient(name = ApiConstants.NAME, contextId = "modApi")
+public interface ModApi {
+    String prefix = RpcConstants.RPC_API_PREFIX + "/mod";
+
+    @GetMapping(prefix + "/get")
+    String queryMod(@RequestParam("productId") Long productId);
+
+}

+ 38 - 0
iot-module/iot-module-manage/iot-module-manage-api/src/main/java/com/middle/platform/manage/api/feign/ProductApi.java

@@ -0,0 +1,38 @@
+package com.middle.platform.manage.api.feign;
+
+import com.middle.platform.common.constant.RpcConstants;
+import com.middle.platform.manage.api.enums.ApiConstants;
+import com.middle.platform.manage.api.pojo.ProductVo;
+import com.middle.platform.manage.api.pojo.TopicVo;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import java.util.List;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-17 11:09:05
+ */
+@FeignClient(name = ApiConstants.NAME, contextId = "productApi")
+public interface ProductApi {
+    String prefix = RpcConstants.RPC_API_PREFIX + "/product";
+
+    /**
+     * 查询产品
+     *
+     * @param productKey
+     * @return
+     */
+    @GetMapping(prefix + "/get")
+    ProductVo queryProduct(@RequestParam("productKey") String productKey,@RequestParam("deviceSn")String deviceSn);
+
+    /**
+     * 获取所有产品的mqtt,需要订阅的topic
+     *
+     * @return 需要订阅的topic
+     */
+    @GetMapping(prefix + "/productTopic")
+    List<TopicVo> productTopic();
+
+}

+ 26 - 0
iot-module/iot-module-manage/iot-module-manage-api/src/main/java/com/middle/platform/manage/api/pojo/IotCloudVo.java

@@ -0,0 +1,26 @@
+package com.middle.platform.manage.api.pojo;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 云函数表
+ *
+ * @author xucaiqin
+ * @date 2023-12-19 13:43:38
+ */
+@Getter
+@Setter
+public class IotCloudVo  {
+    private Long id;
+
+    /**
+     * 脚本语言 1-js 2-php
+     */
+    private Integer lang;
+
+    /**
+     * 云函数
+     */
+    private String cloudText;
+}

+ 31 - 0
iot-module/iot-module-manage/iot-module-manage-api/src/main/java/com/middle/platform/manage/api/pojo/ProductVo.java

@@ -0,0 +1,31 @@
+package com.middle.platform.manage.api.pojo;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-23 14:04:27
+ */
+@Getter
+@Setter
+public class ProductVo implements Serializable {
+    @Serial
+    private static final long serialVersionUID = -8359264859254253425L;
+    /**
+     * 产品id
+     */
+    private Long id;
+    /**
+     * 产品编码
+     */
+    private String code;
+    /**
+     * 设备guid
+     */
+    private String guid;
+    private Integer dataFormat;
+}

+ 21 - 0
iot-module/iot-module-manage/iot-module-manage-api/src/main/java/com/middle/platform/manage/api/pojo/TopicVo.java

@@ -0,0 +1,21 @@
+package com.middle.platform.manage.api.pojo;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-23 14:04:27
+ */
+@Getter
+@Setter
+public class TopicVo implements Serializable {
+    @Serial
+    private static final long serialVersionUID = -8359264859254253425L;
+    private String url;
+    private Integer func;
+    private Integer permission;
+}

+ 22 - 0
iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/api/CloudApiImpl.java

@@ -0,0 +1,22 @@
+package com.middle.platform.manage.biz.api;
+
+import com.middle.platform.manage.api.feign.CloudApi;
+import com.middle.platform.manage.api.pojo.IotCloudVo;
+import com.middle.platform.manage.biz.service.IotCloudService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-23 13:41:30
+ */
+@RestController
+@RequiredArgsConstructor
+public class CloudApiImpl implements CloudApi {
+    private final IotCloudService iotCloudService;
+
+    @Override
+    public IotCloudVo queryCloud(Long productId) {
+        return iotCloudService.cacheCloud(productId);
+    }
+}

+ 21 - 0
iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/api/ModApiImpl.java

@@ -0,0 +1,21 @@
+package com.middle.platform.manage.biz.api;
+
+import com.middle.platform.manage.api.feign.ModApi;
+import com.middle.platform.manage.biz.service.IotModService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-23 13:42:39
+ */
+@RestController
+@RequiredArgsConstructor
+public class ModApiImpl implements ModApi {
+    private final IotModService iotModService;
+
+    @Override
+    public String queryMod(Long productId) {
+         return iotModService.cacheMod(productId);
+    }
+}

+ 30 - 0
iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/api/ProductApiImpl.java

@@ -0,0 +1,30 @@
+package com.middle.platform.manage.biz.api;
+
+import com.middle.platform.manage.api.feign.ProductApi;
+import com.middle.platform.manage.api.pojo.ProductVo;
+import com.middle.platform.manage.api.pojo.TopicVo;
+import com.middle.platform.manage.biz.service.IotProductService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-23 14:12:44
+ */
+@RequiredArgsConstructor
+@RestController
+public class ProductApiImpl implements ProductApi {
+    private final IotProductService iotProductService;
+
+    @Override
+    public List<TopicVo> productTopic() {
+        return iotProductService.queryList();
+    }
+
+    @Override
+    public ProductVo queryProduct(String productKey, String deviceSn) {
+        return iotProductService.cacheProduct(productKey, deviceSn);
+    }
+}

+ 2 - 1
iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/config/FeignConfig.java

@@ -1,6 +1,7 @@
 package com.middle.platform.manage.biz.config;
 
 import com.middle.platform.data.api.feign.DynamicTopicApi;
+import com.middle.platform.data.api.feign.TdApi;
 import com.middle.platform.system.api.feign.UserApi;
 import org.springframework.cloud.openfeign.EnableFeignClients;
 import org.springframework.context.annotation.Configuration;
@@ -12,6 +13,6 @@ import org.springframework.context.annotation.Configuration;
  * @date 2023-12-19 11:00:25
  */
 @Configuration
-@EnableFeignClients(clients = {UserApi.class, DynamicTopicApi.class})
+@EnableFeignClients(clients = {UserApi.class, DynamicTopicApi.class, TdApi.class})
 public class FeignConfig {
 }

+ 2 - 2
iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/constant/UrlInit.java

@@ -5,8 +5,8 @@ package com.middle.platform.manage.biz.constant;
  * @date 2023-12-21 09:25:19
  */
 public enum UrlInit {
-    ATTR_UP("/product/%s/${deviceName}/property/post", "设备属性上报", 1, 1),
-    ATTR_DOWN("/product/%s/${deviceName}/property/post_reply", "云端响应属性上报", 2, 2),
+    ATTR_UP("/iot/%s/+/property/post", "设备属性上报", 1, 1),
+    ATTR_DOWN("/iot/%s/+/property/post_reply", "云端响应属性上报", 2, 2),
     ;
     private final String prefix;
     private final String desc;

+ 10 - 0
iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/constant/UrlType.java

@@ -0,0 +1,10 @@
+package com.middle.platform.manage.biz.constant;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-21 09:23:36
+ */
+public interface UrlType {
+    Integer MQTT = 1;
+    Integer HTTP = 2;
+}

+ 35 - 1
iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/controller/IotDeviceController.java

@@ -7,6 +7,7 @@ import com.middle.platform.manage.biz.domain.req.IotDeviceFlag;
 import com.middle.platform.manage.biz.domain.req.IotDevicePara;
 import com.middle.platform.manage.biz.domain.vo.DeviceImportExcelVo;
 import com.middle.platform.manage.biz.service.IotDeviceService;
+import jakarta.validation.constraints.NotNull;
 import lombok.RequiredArgsConstructor;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
@@ -50,6 +51,28 @@ public class IotDeviceController {
         return Result.ok(iotDeviceService.save(iotDevicePara));
     }
 
+    /**
+     * 设备详情
+     *
+     * @param id 设备id
+     * @return
+     */
+    @GetMapping("/detail")
+    public Result<Object> detail(@NotNull(message = "id不能为空") @Validated Long id) {
+        return Result.ok(iotDeviceService.detail(id));
+    }
+
+    /**
+     * 设备物模型数据详情
+     *
+     * @param id 设备id
+     * @return
+     */
+    @GetMapping("/modDetail")
+    public Result<Object> modDetail(@NotNull(message = "id不能为空") @Validated Long id) {
+        return Result.ok(iotDeviceService.detail(id));
+    }
+
     /**
      * 导入设备
      *
@@ -79,8 +102,19 @@ public class IotDeviceController {
      * @param iotDeviceFlag 启用禁用设备
      * @return
      */
-    @DeleteMapping("/enable")
+    @PostMapping("/enable")
     public Result<Object> enable(@RequestBody IotDeviceFlag iotDeviceFlag) {
         return Result.ok(iotDeviceService.enable(iotDeviceFlag), "操作成功");
     }
+
+    /**
+     * 设备统计
+     *
+     * @param productId
+     * @return 设备总数、当前在线
+     */
+    @GetMapping("/count")
+    public Result<Object> count(Long productId) {
+        return Result.ok(iotDeviceService.count(productId), "查询成功");
+    }
 }

+ 15 - 3
iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/controller/IotProductController.java

@@ -6,6 +6,7 @@ import com.middle.platform.manage.biz.service.IotCloudService;
 import com.middle.platform.manage.biz.service.IotModService;
 import com.middle.platform.manage.biz.service.IotProductService;
 import com.middle.platform.manage.biz.service.IotUrlService;
+import jakarta.annotation.Resource;
 import jakarta.validation.Valid;
 import jakarta.validation.constraints.NotBlank;
 import jakarta.validation.constraints.NotNull;
@@ -21,11 +22,22 @@ import org.springframework.web.bind.annotation.*;
 @RequiredArgsConstructor
 @Validated
 public class IotProductController {
-    private final IotProductService iotProductService;
+    @Resource
+    private IotProductService iotProductService;
     private final IotModService iotModService;
     private final IotCloudService iotCloudService;
     private final IotUrlService iotUrlService;
 
+    /**
+     * 产品下拉选(设备筛选)
+     *
+     * @return
+     */
+    @GetMapping("/list")
+    public Result<Object> list() {
+        return Result.ok(iotProductService.list(), "查询成功");
+    }
+
     /**
      * 分页查询产品数据
      */
@@ -60,7 +72,7 @@ public class IotProductController {
      * @return
      */
     @GetMapping("/detail")
-    public Result<Object> detail(@RequestParam("id") @NotBlank(message = "id不能为空") Long id) {
+    public Result<Object> detail(@RequestParam("id") @NotNull(message = "id不能为空") Long id) {
         return Result.ok(iotProductService.detail(id), "查询成功");
     }
 
@@ -73,7 +85,7 @@ public class IotProductController {
      * @return
      */
     @GetMapping("/getMod")
-    public Result<Object> getMod(@RequestParam("productId") @NotBlank(message = "id不能为空") Long productId) {
+    public Result<Object> getMod(@RequestParam("productId") @NotNull(message = "id不能为空") Long productId) {
         return Result.ok(iotModService.queryMod(productId), "查询成功");
     }
 

+ 1 - 0
iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/domain/req/DevicePage.java

@@ -11,4 +11,5 @@ import lombok.Setter;
 @Getter
 @Setter
 public class DevicePage extends BasePara {
+    private Long productId;
 }

+ 1 - 32
iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/domain/req/IotDevicePara.java

@@ -15,7 +15,7 @@ import java.time.LocalDateTime;
  */
 @Getter
 @Setter
-public class IotDevicePara{
+public class IotDevicePara {
 
 
 
@@ -40,37 +40,6 @@ public class IotDevicePara{
      */
     private String subtitle;
 
-    /**
-     * 经度
-     */
-    private BigDecimal lon;
-
-    /**
-     * 纬度
-     */
-    private BigDecimal lat;
-
-    /**
-     * 所属区域
-     */
-    private String address;
-
-    /**
-     * 最后在线时间
-     */
-    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private LocalDateTime onlineTime;
-
-    /**
-     * 设备状态 1-在线 0-离线
-     */
-    private Integer status;
-
-    /**
-     * 启用状态 1-启用 0-禁用
-     */
-    private Integer enableFlag;
-
     /**
      * 备注
      */

+ 1 - 0
iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/domain/req/IotUrlPara.java

@@ -17,6 +17,7 @@ public class IotUrlPara {
     /**
      * 产品id
      */
+    @NotNull(message = "产品id不能为空")
     private Long productId;
 
     /**

+ 4 - 0
iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/domain/req/ProductPage.java

@@ -11,4 +11,8 @@ import lombok.Setter;
 @Getter
 @Setter
 public class ProductPage extends BasePara {
+    /**
+     * 产品id
+     */
+    private Long productId;
 }

+ 54 - 1
iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/domain/vo/IotDeviceDetailVo.java

@@ -17,6 +17,9 @@ import java.time.LocalDateTime;
 @Getter
 @Setter
 public class IotDeviceDetailVo extends BaseVO {
+    /**
+     * 设备id
+     */
     private Long id;
 
     /**
@@ -62,7 +65,7 @@ public class IotDeviceDetailVo extends BaseVO {
     /**
      * 最后在线时间
      */
-    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
     private LocalDateTime onlineTime;
 
     /**
@@ -79,4 +82,54 @@ public class IotDeviceDetailVo extends BaseVO {
      * 备注
      */
     private String remark;
+
+
+
+    private String productCode;
+    private String productName;
+    /**
+     * 密匙(未知作用)
+     */
+    private String secret;
+
+    /**
+     * 节点类型:1网关、2子设备
+     */
+    private Integer nodeType;
+    private String nodeTypeLabel;
+
+    /**
+     * 联网类型
+     */
+    private Integer networkType;
+    private String networkTypeLabel;
+
+    /**
+     * 上报协议
+     */
+    private Integer reportProtocol;
+    private String reportProtocolLabel;
+    /**
+     * 设备厂商
+     */
+    private Integer vendors;
+    private String vendorsLabel;
+
+    /**
+     * 数据格式
+     */
+    private Integer dataFormat;
+    private String dataFormatLabel;
+
+    /**
+     * 认证方式
+     */
+    private Integer authType;
+    private String authTypeLabel;
+
+    /**
+     * 产品标签
+     */
+    private String tag;
+
 }

+ 5 - 1
iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/domain/vo/IotDeviceVo.java

@@ -23,6 +23,10 @@ public class IotDeviceVo extends BaseVO {
      * 所属产品
      */
     private Long productId;
+    /**
+     * 产品名称
+     */
+    private String productName;
 
     /**
      * 设备名称
@@ -62,7 +66,7 @@ public class IotDeviceVo extends BaseVO {
     /**
      * 最后在线时间
      */
-    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
     private LocalDateTime onlineTime;
 
     /**

+ 82 - 0
iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/domain/vo/IotProductDetailVo.java

@@ -0,0 +1,82 @@
+package com.middle.platform.manage.biz.domain.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.middle.platform.mybatis.core.dataobject.BaseVO;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * 产品
+ *
+ * @author xucaiqin
+ * @date 2023-12-19 13:43:38
+ */
+@Getter
+@Setter
+public class IotProductDetailVo extends BaseVO {
+    private Long id;
+
+    /**
+     * 所属产品
+     */
+    private Long productId;
+
+    /**
+     * 设备名称
+     */
+    private String name;
+
+    /**
+     * 设备sn码
+     */
+    private String sn;
+
+    /**
+     * 设备guid
+     */
+    private String guid;
+
+    /**
+     * 备注名称
+     */
+    private String subtitle;
+
+    /**
+     * 经度
+     */
+    private BigDecimal lon;
+
+    /**
+     * 纬度
+     */
+    private BigDecimal lat;
+
+    /**
+     * 所属区域
+     */
+    private String address;
+
+    /**
+     * 最后在线时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime onlineTime;
+
+    /**
+     * 设备状态 1-在线 0-离线
+     */
+    private Integer status;
+
+    /**
+     * 启用状态 1-启用 0-禁用
+     */
+    private Integer enableFlag;
+
+    /**
+     * 备注
+     */
+    private String remark;
+}

+ 27 - 0
iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/domain/vo/IotProductDownVo.java

@@ -0,0 +1,27 @@
+package com.middle.platform.manage.biz.domain.vo;
+
+import com.middle.platform.mybatis.core.dataobject.BaseVO;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 产品表
+ *
+ * @author xucaiqin
+ * @date 2023-12-19 13:43:38
+ */
+@Getter
+@Setter
+public class IotProductDownVo {
+    private Long id;
+
+    /**
+     * 产品编码
+     */
+    private String code;
+
+    /**
+     * 产品名称
+     */
+    private String name;
+}

+ 13 - 4
iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/mapper/IotCloudMapper.java

@@ -1,13 +1,22 @@
 package com.middle.platform.manage.biz.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.middle.platform.manage.api.pojo.IotCloudVo;
 import com.middle.platform.manage.biz.entity.IotCloud;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
 
 /**
-* @date 2023-12-19 13:43:38
-* @author xucaiqin
-*/
+ * @author xucaiqin
+ * @date 2023-12-19 13:43:38
+ */
 @Mapper
 public interface IotCloudMapper extends BaseMapper<IotCloud> {
-}
+    /**
+     * 查询指定产品的云函数
+     *
+     * @param productId
+     * @return
+     */
+    IotCloudVo selectCloud(@Param("productId") Long productId);
+}

+ 13 - 0
iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/mapper/IotDeviceMapper.java

@@ -3,12 +3,15 @@ package com.middle.platform.manage.biz.mapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.middle.platform.manage.biz.domain.req.DevicePage;
 import com.middle.platform.manage.biz.domain.req.TypeStatisticsReq;
+import com.middle.platform.manage.biz.domain.vo.IotDeviceDetailVo;
 import com.middle.platform.manage.biz.domain.vo.IotDeviceVo;
 import com.middle.platform.manage.biz.domain.vo.TypeStatisticsVo;
 import com.middle.platform.manage.biz.entity.IotDevice;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * @author xucaiqin
@@ -37,4 +40,14 @@ public interface IotDeviceMapper extends BaseMapper<IotDevice> {
     int queryOnlineEquipment();
 
     List<TypeStatisticsVo> queryTypeStatistics(TypeStatisticsReq typeStatisticsReq);
+
+    Map<String, String> count(@Param("productId") Long productId);
+
+    /**
+     * 设备详情
+     *
+     * @param id
+     * @return
+     */
+    IotDeviceDetailVo detail(@Param("id") Long id);
 }

+ 16 - 0
iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/mapper/IotProductMapper.java

@@ -1,10 +1,14 @@
 package com.middle.platform.manage.biz.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.middle.platform.manage.api.pojo.ProductVo;
+import com.middle.platform.manage.api.pojo.TopicVo;
 import com.middle.platform.manage.biz.domain.req.ProductPage;
+import com.middle.platform.manage.biz.domain.vo.IotProductDownVo;
 import com.middle.platform.manage.biz.domain.vo.IotProductVo;
 import com.middle.platform.manage.biz.entity.IotProduct;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
 
@@ -25,4 +29,16 @@ public interface IotProductMapper extends BaseMapper<IotProduct> {
 
     int queryTotalNumberOfProducts();
 
+
+    List<IotProductDownVo> list();
+
+    ProductVo selectProduct(@Param("productKey") String productKey,@Param("deviceSn")String deviceSn);
+
+    /**
+     * 根据类型查询对应的地址
+     *
+     * @param type 地址类型 1-mqtt 2-http 3-coap
+     * @return
+     */
+    List<TopicVo> queryProductTopic(@Param("type") Integer type);
 }

+ 22 - 0
iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/service/IotCloudService.java

@@ -5,13 +5,18 @@ import com.middle.platform.common.constant.Global;
 import com.middle.platform.common.exception.BusinessException;
 import com.middle.platform.manage.biz.domain.req.IotCloudPara;
 import com.middle.platform.manage.biz.domain.req.IotCloudTest;
+import com.middle.platform.manage.api.pojo.IotCloudVo;
 import com.middle.platform.manage.biz.entity.IotCloud;
 import com.middle.platform.manage.biz.mapper.IotCloudMapper;
+import com.middle.platform.redis.constant.CacheConstant;
+import jakarta.annotation.Resource;
 import lombok.RequiredArgsConstructor;
 import org.apache.commons.lang3.StringUtils;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 
 import java.util.Objects;
+import java.util.Optional;
 
 /**
  * @author xucaiqin
@@ -21,6 +26,8 @@ import java.util.Objects;
 @RequiredArgsConstructor
 public class IotCloudService {
     private final IotCloudMapper iotCloudMapper;
+    @Resource
+    private RedisTemplate<String, Object> redisTemplate;
 
     /**
      * 新增或修改云函数
@@ -93,6 +100,21 @@ public class IotCloudService {
      */
     public void removeProduct(Long id) {
         iotCloudMapper.delete(new LambdaQueryWrapper<IotCloud>().eq(IotCloud::getProductId, id).eq(IotCloud::getDelFlag, Global.UN_DEL));
+    }
 
+    /**
+     * 查询指定产品的云函数
+     *
+     * @param productId
+     * @return
+     */
+    public IotCloudVo cacheCloud(Long productId) {
+        IotCloudVo cloud = (IotCloudVo) redisTemplate.opsForValue().get(String.format(CacheConstant.CLOUD_CACHE, productId));
+        if (Objects.nonNull(cloud)) {
+            return cloud;
+        }
+        IotCloudVo iotCloudVo = iotCloudMapper.selectCloud(productId);
+        Optional.ofNullable(iotCloudVo).ifPresent(iotCloud -> redisTemplate.opsForValue().set(String.format(CacheConstant.CLOUD_CACHE, productId), iotCloud));
+        return iotCloudVo;
     }
 }

+ 53 - 2
iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/service/IotDeviceService.java

@@ -1,20 +1,29 @@
 package com.middle.platform.manage.biz.service;
 
 import cn.hutool.core.util.IdUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import com.middle.platform.common.constant.Global;
 import com.middle.platform.common.exception.BusinessException;
 import com.middle.platform.common.utils.PageRes;
 import com.middle.platform.manage.biz.domain.req.DevicePage;
 import com.middle.platform.manage.biz.domain.req.IotDeviceFlag;
 import com.middle.platform.manage.biz.domain.req.IotDevicePara;
+import com.middle.platform.manage.biz.domain.vo.IotDeviceDetailVo;
 import com.middle.platform.manage.biz.domain.vo.IotDeviceVo;
 import com.middle.platform.manage.biz.entity.IotDevice;
 import com.middle.platform.manage.biz.mapper.IotDeviceMapper;
+import com.middle.platform.system.api.enums.DictType;
+import com.middle.platform.system.api.feign.DictApi;
+import com.middle.platform.system.api.feign.UserApi;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
 
+import java.time.LocalDateTime;
 import java.util.List;
 import java.util.Objects;
+import java.util.Optional;
 
 /**
  * @author xucaiqin
@@ -24,6 +33,8 @@ import java.util.Objects;
 @RequiredArgsConstructor
 public class IotDeviceService {
     private final IotDeviceMapper iotDeviceMapper;
+    private final DictApi dictApi;
+    private final UserApi userApi;
 
     /**
      * 设备分页查询
@@ -34,7 +45,12 @@ public class IotDeviceService {
     public Object pageQuery(DevicePage devicePage) {
         PageHelper.startPage(devicePage.getPage(), devicePage.getPageSize());
         List<IotDeviceVo> iotProductVos = iotDeviceMapper.pageQuery(devicePage);
-        return new PageRes<>(iotProductVos);
+        PageInfo<IotDeviceVo> pageInfo = new PageInfo<>(iotProductVos);
+        iotProductVos.forEach(a -> {
+            Optional.ofNullable(userApi.queryUser(a.getCreateBy())).ifPresent(userCache -> a.setCreateByLabel(userCache.getName()));
+            Optional.ofNullable(userApi.queryUser(a.getUpdateBy())).ifPresent(userCache -> a.setUpdateByLabel(userCache.getName()));
+        });
+        return new PageRes<>(pageInfo, iotProductVos);
     }
 
     /**
@@ -64,7 +80,10 @@ public class IotDeviceService {
      * @return
      */
     public Object remove(Long id) {
-        iotDeviceMapper.deleteById(id);
+        IotDevice iotDevice = new IotDevice();
+        iotDevice.setDeleteTime(LocalDateTime.now());
+        iotDevice.setDelFlag(Global.DEL);
+        iotDeviceMapper.update(iotDevice, new LambdaQueryWrapper<IotDevice>().eq(IotDevice::getId, id).eq(IotDevice::getDelFlag, Global.UN_DEL));
         return true;
     }
 
@@ -83,4 +102,36 @@ public class IotDeviceService {
         iotDeviceMapper.updateById(iotDevice);
         return true;
     }
+
+    /**
+     * 设备详情
+     *
+     * @param id
+     * @return
+     */
+    public IotDeviceDetailVo detail(Long id) {
+        IotDeviceDetailVo detail = iotDeviceMapper.detail(id);
+        if (Objects.isNull(detail)) {
+            throw new BusinessException("设备不存在");
+        }
+        Optional.ofNullable(userApi.queryUser(detail.getCreateBy())).ifPresent(userCache -> detail.setCreateByLabel(userCache.getName()));
+        Optional.ofNullable(userApi.queryUser(detail.getUpdateBy())).ifPresent(userCache -> detail.setUpdateByLabel(userCache.getName()));
+        Optional.ofNullable(dictApi.query(DictType.AUTH_TYPE, String.valueOf(detail.getAuthType()))).ifPresent(cache -> detail.setAuthTypeLabel(cache.getLabel()));
+        Optional.ofNullable(dictApi.query(DictType.NODE_TYPE, String.valueOf(detail.getNodeType()))).ifPresent(cache -> detail.setNodeTypeLabel(cache.getLabel()));
+        Optional.ofNullable(dictApi.query(DictType.NETWORK_TYPE, String.valueOf(detail.getNetworkType()))).ifPresent(cache -> detail.setNetworkTypeLabel(cache.getLabel()));
+        Optional.ofNullable(dictApi.query(DictType.REPORT_PROTOCOL_TYPE, String.valueOf(detail.getReportProtocol()))).ifPresent(cache -> detail.setReportProtocolLabel(cache.getLabel()));
+        Optional.ofNullable(dictApi.query(DictType.VENDORS_TYPE, String.valueOf(detail.getVendors()))).ifPresent(cache -> detail.setVendorsLabel(cache.getLabel()));
+        Optional.ofNullable(dictApi.query(DictType.DATA_FORMAT_TYPE, String.valueOf(detail.getDataFormat()))).ifPresent(cache -> detail.setDataFormatLabel(cache.getLabel()));
+        return detail;
+    }
+
+    /**
+     * 统计设备
+     *
+     * @param productId
+     * @return
+     */
+    public Object count(Long productId) {
+        return iotDeviceMapper.count(productId);
+    }
 }

+ 24 - 0
iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/service/IotModService.java

@@ -5,10 +5,15 @@ import com.middle.platform.common.constant.Global;
 import com.middle.platform.manage.biz.domain.req.IotModPara;
 import com.middle.platform.manage.biz.entity.IotMod;
 import com.middle.platform.manage.biz.mapper.IotModMapper;
+import com.middle.platform.redis.constant.CacheConstant;
+import jakarta.annotation.Resource;
 import lombok.RequiredArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 
 import java.util.Objects;
+import java.util.Optional;
 
 /**
  * @author xucaiqin
@@ -18,6 +23,8 @@ import java.util.Objects;
 @RequiredArgsConstructor
 public class IotModService {
     private final IotModMapper iotModMapper;
+    @Resource
+    private RedisTemplate<String, Object> redisTemplate;
 
     /**
      * 保存物模型数据
@@ -54,6 +61,7 @@ public class IotModService {
     public Object queryMod(Long productId) {
         return query(productId);
     }
+
     /**
      * 通过产品id删除关联的物模型
      *
@@ -62,4 +70,20 @@ public class IotModService {
     public void removeProduct(Long id) {
         iotModMapper.delete(new LambdaQueryWrapper<IotMod>().eq(IotMod::getProductId, id).eq(IotMod::getDelFlag, Global.UN_DEL));
     }
+
+    /**
+     * 查询物模型json数据
+     *
+     * @param productId
+     * @return
+     */
+    public String cacheMod(Long productId) {
+        String tslJson = (String) redisTemplate.opsForValue().get(String.format(CacheConstant.MOD_CACHE, productId));
+        if (StringUtils.isNotBlank(tslJson)) {
+            return tslJson;
+        }
+        IotMod query = query(productId);
+        Optional.ofNullable(query).ifPresent(m -> redisTemplate.opsForValue().set(String.format(CacheConstant.MOD_CACHE, productId), m.getTslJson()));
+        return Objects.nonNull(query) ? query.getTslJson() : null;
+    }
 }

+ 68 - 8
iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/service/IotProductService.java

@@ -5,24 +5,30 @@ import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import com.middle.platform.common.exception.BusinessException;
 import com.middle.platform.common.utils.PageRes;
-import com.middle.platform.data.api.feign.DynamicTopicApi;
+import com.middle.platform.data.api.feign.TdApi;
+import com.middle.platform.manage.api.pojo.ProductVo;
+import com.middle.platform.manage.api.pojo.TopicVo;
+import com.middle.platform.manage.biz.constant.UrlType;
 import com.middle.platform.manage.biz.domain.req.IotProductPara;
 import com.middle.platform.manage.biz.domain.req.ProductPage;
-import com.middle.platform.manage.biz.domain.vo.IotDeviceDetailVo;
+import com.middle.platform.manage.biz.domain.vo.IotProductDetailVo;
 import com.middle.platform.manage.biz.domain.vo.IotProductVo;
-import com.middle.platform.manage.biz.entity.IotDevice;
 import com.middle.platform.manage.biz.entity.IotProduct;
 import com.middle.platform.manage.biz.mapper.IotDeviceMapper;
 import com.middle.platform.manage.biz.mapper.IotProductMapper;
+import com.middle.platform.redis.constant.CacheConstant;
 import com.middle.platform.system.api.enums.DictType;
 import com.middle.platform.system.api.feign.DictApi;
 import com.middle.platform.system.api.feign.UserApi;
+import jakarta.annotation.Resource;
 import lombok.RequiredArgsConstructor;
 import org.springframework.beans.BeanUtils;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.util.List;
+import java.util.Objects;
 import java.util.Optional;
 
 /**
@@ -34,12 +40,16 @@ import java.util.Optional;
 public class IotProductService {
     private final IotProductMapper iotProductMapper;
     private final IotDeviceMapper iotDeviceMapper;
-    private final IotUrlService iotUrlService;
+    @Resource
+    private IotUrlService iotUrlService;
     private final IotModService iotModService;
     private final IotCloudService iotCloudService;
+    private final TdApi tdApi;
 
     private final UserApi userApi;
     private final DictApi dictApi;
+    @Resource
+    private RedisTemplate<String, Object> redisTemplate;
 
     /**
      * 分页查询产品数据
@@ -89,6 +99,8 @@ public class IotProductService {
         iotProductMapper.insert(iotProduct);
         /*保存默认topic*/
         iotUrlService.save(iotProduct);
+        /*创建产品*/
+        tdApi.createProduct(iotProduct.getCode());
         return null;
     }
 
@@ -125,9 +137,57 @@ public class IotProductService {
      * @return
      */
     public Object detail(Long id) {
-        IotDevice iotDevice = iotDeviceMapper.selectById(id);
-        IotDeviceDetailVo iotDeviceDetailVo = new IotDeviceDetailVo();
-        BeanUtils.copyProperties(iotDevice, iotDeviceDetailVo);
-        return iotDeviceDetailVo;
+        IotProduct iotProduct = iotProductMapper.selectById(id);
+        if (Objects.isNull(iotProduct)) {
+            throw new BusinessException("当前产品不存在");
+        }
+        IotProductDetailVo iotProductDetailVo = new IotProductDetailVo();
+        BeanUtils.copyProperties(iotProduct, iotProductDetailVo);
+        return iotProductDetailVo;
+    }
+
+    /**
+     * 根据id查询产品信息
+     *
+     * @param productId 产品id
+     * @return
+     */
+    public IotProduct query(Long productId) {
+        return iotProductMapper.selectById(productId);
+    }
+
+    /**
+     * 下拉列表
+     *
+     * @return
+     */
+    public Object list() {
+        return iotProductMapper.list();
+    }
+
+    /**
+     * 查询产品的缓存
+     *
+     * @param productKey 产品key
+     * @param deviceSn   设备sn
+     * @return
+     */
+    public ProductVo cacheProduct(String productKey, String deviceSn) {
+        ProductVo productVo = (ProductVo) redisTemplate.opsForValue().get(String.format(CacheConstant.PRODUCT_CACHE, productKey, deviceSn));
+        if (Objects.nonNull(productVo)) {
+            return productVo;
+        }
+        ProductVo productVoC = iotProductMapper.selectProduct(productKey, deviceSn);
+        Optional.ofNullable(productVoC).ifPresent(product -> redisTemplate.opsForValue().set(String.format(CacheConstant.PRODUCT_CACHE, productKey, deviceSn), product));
+        return productVoC;
+    }
+
+    /**
+     * 通过产品关联的通信地址
+     *
+     * @return
+     */
+    public List<TopicVo> queryList() {
+        return iotProductMapper.queryProductTopic(UrlType.MQTT);
     }
 }

+ 98 - 6
iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/service/IotUrlService.java

@@ -3,17 +3,25 @@ package com.middle.platform.manage.biz.service;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.middle.platform.common.constant.Global;
 import com.middle.platform.common.exception.BusinessException;
+import com.middle.platform.data.api.constant.TopicType;
 import com.middle.platform.data.api.feign.DynamicTopicApi;
+import com.middle.platform.data.api.pojo.TopicDto;
 import com.middle.platform.manage.biz.constant.UrlCategory;
 import com.middle.platform.manage.biz.constant.UrlInit;
 import com.middle.platform.manage.biz.constant.UrlProtocol;
+import com.middle.platform.manage.biz.constant.UrlType;
 import com.middle.platform.manage.biz.domain.req.IotUrlPara;
 import com.middle.platform.manage.biz.entity.IotProduct;
 import com.middle.platform.manage.biz.entity.IotUrl;
 import com.middle.platform.manage.biz.mapper.IotUrlMapper;
+import com.middle.platform.redis.service.CacheService;
+import jakarta.annotation.Resource;
 import lombok.RequiredArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
+import java.time.LocalDateTime;
 import java.util.Objects;
 
 /**
@@ -24,7 +32,60 @@ import java.util.Objects;
 @RequiredArgsConstructor
 public class IotUrlService {
     private final IotUrlMapper iotUrlMapper;
+    @Resource
+    private IotProductService iotProductService;
     private final DynamicTopicApi dynamicTopicApi;
+    private final CacheService cacheService;
+    private String topicPrefix = "/iot/%s/+/";
+
+    /**
+     * 校验topic
+     *
+     * @param iotUrlPara
+     */
+    private void checkTopic(IotUrlPara iotUrlPara) {
+        //校验前缀是否为 /iot/{productKey}/*/
+        IotProduct query = iotProductService.query(iotUrlPara.getProductId());
+        if (Objects.isNull(query)) {
+            throw new BusinessException("产品不存在");
+        }
+        //产品key
+        String code = query.getCode();
+        if (!StringUtils.startsWith(iotUrlPara.getUrl(), String.format(topicPrefix, code))) {
+            throw new BusinessException("topic必须以+" + String.format(topicPrefix, code) + "为前缀");
+        }
+        //todo topic合规校验
+
+    }
+
+    /**
+     * 订阅地址,添加缓存
+     *
+     * @param url  topic地址
+     * @param func func+permission
+     */
+    private void subUrl(String url, String func) {
+        ThreadTask.addJob(() -> {
+            //订阅topic
+            dynamicTopicApi.saveTopic(new TopicDto(url, 0));
+            //写入 CacheConstant.TOPIC_CACHE缓存
+            cacheService.setTopic(url, func);
+        });
+    }
+
+    /**
+     * 取消订阅的topic,并删除缓存的topic
+     *
+     * @param url
+     */
+    private void removeUrl(String url) {
+        ThreadTask.addJob(() -> {
+            dynamicTopicApi.removeTopic(new TopicDto(url, 0));
+            //删除原topic
+            cacheService.delTopic(url);
+        });
+
+    }
 
     /**
      * 新增topic
@@ -32,10 +93,10 @@ public class IotUrlService {
      * @param iotUrlPara
      * @return
      */
+    @Transactional(rollbackFor = Exception.class)
     public Object saveUrl(IotUrlPara iotUrlPara) {
-        if (Objects.isNull(iotUrlPara.getProductId())) {
-            throw new BusinessException("产品id不能为空");
-        }
+        //topi规则校验
+        checkTopic(iotUrlPara);
         IotUrl iotUrl = new IotUrl();
         iotUrl.setProductId(iotUrlPara.getProductId());
         iotUrl.setCategory(iotUrlPara.getCategory());
@@ -46,20 +107,31 @@ public class IotUrlService {
         iotUrl.setRemark(iotUrlPara.getRemark());
         iotUrlMapper.insert(iotUrl);
         //新增订阅的topic
-//        dynamicTopicApi
+        if (Objects.equals(iotUrlPara.getType(), UrlType.MQTT)
+                && (Objects.equals(iotUrlPara.getPermission(), TopicType.PUB) || Objects.equals(iotUrlPara.getPermission(), TopicType.BOTH))) {
+            subUrl(iotUrl.getUrl(), iotUrl.getFunc() + String.valueOf(iotUrl.getPermission()));
+        }
         return true;
     }
 
+
     /**
      * 修改topic
      *
      * @param iotUrlPara
      * @return
      */
+    @Transactional(rollbackFor = Exception.class)
     public Object update(IotUrlPara iotUrlPara) {
         if (Objects.isNull(iotUrlPara.getId())) {
             throw new BusinessException("id不能为空");
         }
+        checkTopic(iotUrlPara);
+        IotUrl iotUrlCheck = iotUrlMapper.selectById(iotUrlPara.getId());
+        if (Objects.isNull(iotUrlCheck)) {
+            throw new BusinessException("设备不存在");
+        }
+
         IotUrl iotUrl = new IotUrl();
         iotUrl.setId(iotUrlPara.getId());
         iotUrl.setCategory(iotUrlPara.getCategory());
@@ -69,6 +141,11 @@ public class IotUrlService {
         iotUrl.setType(iotUrlPara.getType());
         iotUrl.setRemark(iotUrlPara.getRemark());
         iotUrlMapper.updateById(iotUrl);
+        //取消订阅原topic 订阅topic
+        if (Objects.equals(iotUrlPara.getType(), UrlType.MQTT) && (Objects.equals(iotUrlPara.getPermission(), TopicType.PUB) || Objects.equals(iotUrlPara.getPermission(), TopicType.BOTH))) {
+            removeUrl(iotUrlCheck.getUrl());
+            subUrl(iotUrl.getUrl(), iotUrl.getFunc() + String.valueOf(iotUrl.getPermission()));
+        }
         return true;
     }
 
@@ -79,7 +156,18 @@ public class IotUrlService {
      * @return
      */
     public Object remove(Long id) {
-        iotUrlMapper.deleteById(id);
+        IotUrl iotUrlCheck = iotUrlMapper.selectById(id);
+        if (Objects.isNull(iotUrlCheck)) {
+            return true;
+        }
+        IotUrl iotUrl = new IotUrl();
+        iotUrl.setDeleteTime(LocalDateTime.now());
+        iotUrl.setDelFlag(Global.DEL);
+        iotUrlMapper.update(iotUrl, new LambdaQueryWrapper<IotUrl>().eq(IotUrl::getId, id).eq(IotUrl::getDelFlag, Global.UN_DEL));
+        //取消订阅
+        if (Objects.equals(iotUrlCheck.getType(), UrlType.MQTT) && (Objects.equals(iotUrlCheck.getPermission(), TopicType.PUB) || Objects.equals(iotUrlCheck.getPermission(), TopicType.BOTH))) {
+            removeUrl(iotUrlCheck.getUrl());
+        }
         return true;
     }
 
@@ -91,7 +179,7 @@ public class IotUrlService {
      * @return
      */
     public Object getUrl(Long productId, Integer type) {
-        return iotUrlMapper.selectList(new LambdaQueryWrapper<IotUrl>().eq(IotUrl::getProductId, productId).eq(IotUrl::getType, type));
+        return iotUrlMapper.selectList(new LambdaQueryWrapper<IotUrl>().eq(IotUrl::getProductId, productId).eq(IotUrl::getType, type).eq(IotUrl::getDelFlag, Global.UN_DEL));
     }
 
 
@@ -112,9 +200,13 @@ public class IotUrlService {
                 iotUrl.setType(iotProduct.getReportProtocol());
                 iotUrl.setRemark(value.getDesc());
                 iotUrlMapper.insert(iotUrl);
+                subUrl(iotUrl.getUrl(), iotUrl.getFunc() + String.valueOf(iotUrl.getPermission()));
             }
         }
+        //http
+        if (Objects.equals(iotProduct.getReportProtocol(), UrlProtocol.HTTP)) {
 
+        }
     }
 
     /**

+ 25 - 0
iot-module/iot-module-manage/iot-module-manage-biz/src/main/java/com/middle/platform/manage/biz/service/ThreadTask.java

@@ -0,0 +1,25 @@
+package com.middle.platform.manage.biz.service;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-25 09:03:26
+ */
+public class ThreadTask {
+
+    private ThreadTask() {
+    }
+
+    public static class Task {
+        private final static ThreadPoolExecutor THREAD_POOL_EXECUTOR =
+                new ThreadPoolExecutor(1, 2, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(12));
+
+    }
+
+    public static void addJob(Runnable runnable) {
+        Task.THREAD_POOL_EXECUTOR.execute(runnable);
+    }
+}

+ 2 - 3
iot-module/iot-module-manage/iot-module-manage-biz/src/main/resources/bootstrap.yaml

@@ -18,7 +18,6 @@ spring:
       write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
       write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
       fail-on-empty-beans: false # 允许序列化无属性的 Bean
-#  main:
-#    allow-bean-definition-overriding: true
-
+  main:
+    allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。
 

+ 2 - 1
iot-module/iot-module-manage/iot-module-manage-biz/src/main/resources/logback-spring.xml

@@ -11,7 +11,8 @@
 
     <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义后,可以使“${}”来使用变量。 -->
     <property name="log.path" value="logs"/>
-    <springProperty scope="context" name="LOG_HOME" source="spring.application.name" defaultValue="iot-manage"/>
+    <property name="LOG_HOME" value="iot-manage"/>
+<!--    <springProperty scope="context" name="LOG_HOME" source="spring.application.name" defaultValue="iot-manage"/>-->
     <!--0. 日志格式和颜色渲染 -->
     <!-- 彩色日志依赖的渲染类 -->
     <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>

+ 16 - 2
iot-module/iot-module-manage/iot-module-manage-biz/src/main/resources/mapper/IotCloudMapper.xml

@@ -17,7 +17,21 @@
   </resultMap>
   <sql id="Base_Column_List">
     <!--@mbg.generated-->
-    id, product_id, lang, cloud_text, create_by, create_time, update_by, update_time, 
+    id, product_id, lang, cloud_text, create_by, create_time, update_by, update_time,
     delete_time, del_flag
   </sql>
-</mapper>
+
+  <select id="selectCloud" resultType="com.middle.platform.manage.api.pojo.IotCloudVo">
+      select ic.id,
+             ic.cloud_text,
+             ic.lang
+      from iot_cloud ic
+      <where>
+          <if test="productId != null">
+              and ic.product_id = #{productId,jdbcType=BIGINT}
+          </if>
+          and ic.del_flag = 0
+          limit 1
+      </where>
+  </select>
+</mapper>

+ 67 - 9
iot-module/iot-module-manage/iot-module-manage-biz/src/main/resources/mapper/IotDeviceMapper.xml

@@ -55,15 +55,15 @@
         </where>
     </select>
 
-    <select id="pageQuery" resultType="com.middle.platform.manage.biz.domain.vo.IotDeviceVo">
-        select *
-        from iot_device id
-        <where>
-            <if test="keywords != null and keywords != ''">
-                and id.name like concat('%', #{keywords,jdbcType=VARCHAR}, '%')
-            </if>
-        </where>
-    </select>
+<!--    <select id="pageQuery" resultType="com.middle.platform.manage.biz.domain.vo.IotDeviceVo">-->
+<!--        select *-->
+<!--        from iot_device id-->
+<!--        <where>-->
+<!--            <if test="keywords != null and keywords != ''">-->
+<!--                and id.name like concat('%', #{keywords,jdbcType=VARCHAR}, '%')-->
+<!--            </if>-->
+<!--        </where>-->
+<!--    </select>-->
 
     <select id="queryTotalNumberOfDevices" resultType="int">
         select count(id) as num
@@ -101,4 +101,62 @@
             </if>
         </where>
     </select>
+  <select id="pageQuery" resultType="com.middle.platform.manage.biz.domain.vo.IotDeviceVo">
+      select id.*, ip.name as productName
+      from iot_device id
+               inner join iot_product ip on id.product_id = ip.id and ip.del_flag = 0
+      <where>
+          <if test="keywords != null and keywords != ''">
+              and id.name like concat('%', #{keywords,jdbcType=VARCHAR}, '%')
+          </if>
+        <if test="productId != null">
+            and id.product_id = #{productId,jdbcType=BIGINT}
+        </if>
+          and id.del_flag = 0
+      </where>
+  </select>
+
+  <select id="count" resultType="java.util.Map">
+      select count(case when id.status = 1 then 1 end) online,
+             count(case when id.status = 0 then 1 end) offline
+      from iot_device id
+      <where>
+          <if test="productId != null">
+              and id.product_id = #{productId,jdbcType=BIGINT}
+          </if>
+          and id.del_flag = 0
+      </where>
+  </select>
+  <select id="detail" resultType="com.middle.platform.manage.biz.domain.vo.IotDeviceDetailVo">
+      select id.id,
+             id.name,
+             id.sn,
+             id.guid,
+             id.subtitle,
+             id.lat,
+             id.lon,
+             id.address,
+             id.online_time,
+             id.status,
+             id.enable_flag,
+             id.remark,
+             id.create_time,
+             id.create_by,
+             id.update_time,
+             id.update_by,
+             ip.code            productCode,
+             ip.name            productName,
+             ip.secret,
+             ip.node_type       nodeType,
+             ip.network_type    networkType,
+             ip.report_protocol reportProtocol,
+             ip.data_format     dataFormat,
+             ip.auth_type       authType,
+             ip.vendors,
+             ip.tag
+      from iot_device id
+               inner join iot_product ip on id.product_id = ip.id and ip.del_flag = 0
+      where id.id = #{id,jdbcType=BIGINT}
+        and id.del_flag = 0
+  </select>
 </mapper>

+ 39 - 0
iot-module/iot-module-manage/iot-module-manage-biz/src/main/resources/mapper/IotProductMapper.xml

@@ -65,4 +65,43 @@
             del_flag = 0
         </where>
     </select>
+
+    <select id="list" resultType="com.middle.platform.manage.biz.domain.vo.IotProductDownVo">
+        select ip.id, ip.name, ip.code
+        from iot_product ip
+        <where>
+            and ip.del_flag = 0
+        </where>
+    </select>
+
+    <select id="selectProduct" resultType="com.middle.platform.manage.api.pojo.ProductVo">
+        select ip.id,
+               ip.code,
+               ip.data_format,
+               id.guid
+        from iot_product ip
+                 inner join iot_device id on ip.id = id.product_id and id.del_flag = 0
+        <where>
+            <if test="productKey != null and productKey != ''">
+                and ip.code = #{productKey,jdbcType=VARCHAR}
+            </if>
+            <if test="deviceSn != null and deviceSn != ''">
+                and id.sn = #{deviceSn,jdbcType=VARCHAR}
+            </if>
+            and ip.del_flag = 0
+        </where>
+    </select>
+
+    <select id="queryProductTopic" resultType="com.middle.platform.manage.api.pojo.TopicVo">
+        select iu.url, iu.permission, iu.func
+        from iot_product ip
+                 inner join iot_url iu on ip.id = iu.product_id and iu.del_flag = 0
+        <where>
+            <if test="type != null">
+                and iu.type = #{type,jdbcType=INTEGER}
+            </if>
+            and iu.permission in (1, 3)
+            and ip.del_flag = 0
+        </where>
+    </select>
 </mapper>

+ 2 - 1
iot-module/iot-module-system/iot-module-system-biz/src/main/resources/logback-spring.xml

@@ -10,7 +10,8 @@
     <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
     <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义后,可以使“${}”来使用变量。 -->
     <property name="log.path" value="logs"/>
-    <springProperty scope="context" name="LOG_HOME" source="spring.application.name" defaultValue="iot-system"/>
+    <property name="LOG_HOME" value="iot-system"/>
+<!--    <springProperty scope="context" name="LOG_HOME" source="spring.application.name" defaultValue="iot-system"/>-->
     <!--0. 日志格式和颜色渲染 -->
     <!-- 彩色日志依赖的渲染类 -->
     <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>