Commit baa779a271ec94017060c0f1da033c87e64d1343
1 parent
b800d274
feat(iot): 新增产品 TDengine 表结构同步接口
Showing
6 changed files
with
51 additions
and
4 deletions
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.http
0 → 100644
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java
| @@ -141,6 +141,14 @@ public class IotProductController { | @@ -141,6 +141,14 @@ public class IotProductController { | ||
| 141 | result.getData().getList()); | 141 | result.getData().getList()); |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | + @PostMapping("/sync-property-table") | ||
| 145 | + @Operation(summary = "同步产品属性表结构到 TDengine") | ||
| 146 | + @PreAuthorize("@ss.hasPermission('iot:product:update')") | ||
| 147 | + public CommonResult<Boolean> syncProductPropertyTable() { | ||
| 148 | + productService.syncProductPropertyTable(); | ||
| 149 | + return success(true); | ||
| 150 | + } | ||
| 151 | + | ||
| 144 | @GetMapping("/simple-list") | 152 | @GetMapping("/simple-list") |
| 145 | @Operation(summary = "获取产品的精简信息列表", description = "主要用于前端的下拉选项") | 153 | @Operation(summary = "获取产品的精简信息列表", description = "主要用于前端的下拉选项") |
| 146 | @Parameter(name = "deviceType", description = "设备类型", example = "1") | 154 | @Parameter(name = "deviceType", description = "设备类型", example = "1") |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java
| @@ -38,6 +38,10 @@ public interface IotProductMapper extends BaseMapperX<IotProductDO> { | @@ -38,6 +38,10 @@ public interface IotProductMapper extends BaseMapperX<IotProductDO> { | ||
| 38 | .apply("LOWER(product_key) = {0}", productKey.toLowerCase())); | 38 | .apply("LOWER(product_key) = {0}", productKey.toLowerCase())); |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | + default List<IotProductDO> selectListByStatus(Integer status) { | ||
| 42 | + return selectList(IotProductDO::getStatus, status); | ||
| 43 | + } | ||
| 44 | + | ||
| 41 | default Long selectCountByCreateTime(@Nullable LocalDateTime createTime) { | 45 | default Long selectCountByCreateTime(@Nullable LocalDateTime createTime) { |
| 42 | return selectCount(new LambdaQueryWrapperX<IotProductDO>() | 46 | return selectCount(new LambdaQueryWrapperX<IotProductDO>() |
| 43 | .geIfPresent(IotProductDO::getCreateTime, createTime)); | 47 | .geIfPresent(IotProductDO::getCreateTime, createTime)); |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java
| @@ -149,4 +149,11 @@ public interface IotProductService { | @@ -149,4 +149,11 @@ public interface IotProductService { | ||
| 149 | */ | 149 | */ |
| 150 | void validateProductsExist(Collection<Long> ids); | 150 | void validateProductsExist(Collection<Long> ids); |
| 151 | 151 | ||
| 152 | + /** | ||
| 153 | + * 同步产品的 TDengine 表结构 | ||
| 154 | + * | ||
| 155 | + * 目的:当 MySQL 和 TDengine 不同步时,强制将已发布产品的表结构同步到 TDengine 中 | ||
| 156 | + */ | ||
| 157 | + void syncProductPropertyTable(); | ||
| 158 | + | ||
| 152 | } | 159 | } |
| 153 | \ No newline at end of file | 160 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java
| @@ -15,6 +15,7 @@ import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; | @@ -15,6 +15,7 @@ import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; | ||
| 15 | import cn.iocoder.yudao.module.iot.service.device.property.IotDevicePropertyService; | 15 | import cn.iocoder.yudao.module.iot.service.device.property.IotDevicePropertyService; |
| 16 | import com.baomidou.dynamic.datasource.annotation.DSTransactional; | 16 | import com.baomidou.dynamic.datasource.annotation.DSTransactional; |
| 17 | import jakarta.annotation.Resource; | 17 | import jakarta.annotation.Resource; |
| 18 | +import lombok.extern.slf4j.Slf4j; | ||
| 18 | import org.springframework.cache.annotation.CacheEvict; | 19 | import org.springframework.cache.annotation.CacheEvict; |
| 19 | import org.springframework.cache.annotation.Cacheable; | 20 | import org.springframework.cache.annotation.Cacheable; |
| 20 | import org.springframework.context.annotation.Lazy; | 21 | import org.springframework.context.annotation.Lazy; |
| @@ -34,6 +35,7 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; | @@ -34,6 +35,7 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; | ||
| 34 | * | 35 | * |
| 35 | * @author ahh | 36 | * @author ahh |
| 36 | */ | 37 | */ |
| 38 | +@Slf4j | ||
| 37 | @Service | 39 | @Service |
| 38 | @Validated | 40 | @Validated |
| 39 | public class IotProductServiceImpl implements IotProductService { | 41 | public class IotProductServiceImpl implements IotProductService { |
| @@ -179,6 +181,27 @@ public class IotProductServiceImpl implements IotProductService { | @@ -179,6 +181,27 @@ public class IotProductServiceImpl implements IotProductService { | ||
| 179 | } | 181 | } |
| 180 | 182 | ||
| 181 | @Override | 183 | @Override |
| 184 | + public void syncProductPropertyTable() { | ||
| 185 | + // 1. 获取所有已发布的产品 | ||
| 186 | + List<IotProductDO> products = productMapper.selectListByStatus( | ||
| 187 | + IotProductStatusEnum.PUBLISHED.getStatus()); | ||
| 188 | + log.info("[syncProductPropertyTable][开始同步,已发布产品数量({})]", products.size()); | ||
| 189 | + | ||
| 190 | + // 2. 遍历同步 TDengine 表结构(创建产品超级表数据模型) | ||
| 191 | + int successCount = 0; | ||
| 192 | + for (IotProductDO product : products) { | ||
| 193 | + try { | ||
| 194 | + devicePropertyDataService.defineDevicePropertyData(product.getId()); | ||
| 195 | + successCount++; | ||
| 196 | + log.info("[syncProductPropertyTable][产品({}/{}) 同步成功]", product.getId(), product.getName()); | ||
| 197 | + } catch (Exception e) { | ||
| 198 | + log.error("[syncProductPropertyTable][产品({}/{}) 同步失败]", product.getId(), product.getName(), e); | ||
| 199 | + } | ||
| 200 | + } | ||
| 201 | + log.info("[syncProductPropertyTable][同步完成,成功({}/{})个]", successCount, products.size()); | ||
| 202 | + } | ||
| 203 | + | ||
| 204 | + @Override | ||
| 182 | public void validateProductsExist(Collection<Long> ids) { | 205 | public void validateProductsExist(Collection<Long> ids) { |
| 183 | if (CollUtil.isEmpty(ids)) { | 206 | if (CollUtil.isEmpty(ids)) { |
| 184 | return; | 207 | return; |
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/enums/IotModbusModeEnum.java
| @@ -7,7 +7,7 @@ import lombok.RequiredArgsConstructor; | @@ -7,7 +7,7 @@ import lombok.RequiredArgsConstructor; | ||
| 7 | import java.util.Arrays; | 7 | import java.util.Arrays; |
| 8 | 8 | ||
| 9 | /** | 9 | /** |
| 10 | - * IoT Modbus 模式枚举 | 10 | + * IoT Modbus 工作模式枚举 |
| 11 | * | 11 | * |
| 12 | * @author 芋道源码 | 12 | * @author 芋道源码 |
| 13 | */ | 13 | */ |
| @@ -16,18 +16,18 @@ import java.util.Arrays; | @@ -16,18 +16,18 @@ import java.util.Arrays; | ||
| 16 | public enum IotModbusModeEnum implements ArrayValuable<Integer> { | 16 | public enum IotModbusModeEnum implements ArrayValuable<Integer> { |
| 17 | 17 | ||
| 18 | POLLING(1, "云端轮询"), | 18 | POLLING(1, "云端轮询"), |
| 19 | - ACTIVE_REPORT(2, "主动上报"); | 19 | + ACTIVE_REPORT(2, "边缘采集"); |
| 20 | 20 | ||
| 21 | public static final Integer[] ARRAYS = Arrays.stream(values()) | 21 | public static final Integer[] ARRAYS = Arrays.stream(values()) |
| 22 | .map(IotModbusModeEnum::getMode) | 22 | .map(IotModbusModeEnum::getMode) |
| 23 | .toArray(Integer[]::new); | 23 | .toArray(Integer[]::new); |
| 24 | 24 | ||
| 25 | /** | 25 | /** |
| 26 | - * 模式 | 26 | + * 工作模式 |
| 27 | */ | 27 | */ |
| 28 | private final Integer mode; | 28 | private final Integer mode; |
| 29 | /** | 29 | /** |
| 30 | - * 名称 | 30 | + * 模式名称 |
| 31 | */ | 31 | */ |
| 32 | private final String name; | 32 | private final String name; |
| 33 | 33 |