Commit 8089f3a319efb919fce809b8e144c3fcc0694b4f
1 parent
f4ad3e9d
【功能优化】IoT:
1. DeviceDataApi => IotDeviceUpstreamApi,并新建 upstream 包 2. ThingModelMessage => IotDeviceMessage 设备消息 3. 基于 spring event 异步消费 IotDeviceMessage,并实现 IotDeviceLogMessageConsumer 记录日志
Showing
42 changed files
with
538 additions
and
680 deletions
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java
| @@ -13,7 +13,7 @@ import java.util.Set; | @@ -13,7 +13,7 @@ import java.util.Set; | ||
| 13 | /** | 13 | /** |
| 14 | * 基于 MyBatis Plus 多租户的功能,实现 DB 层面的多租户的功能 | 14 | * 基于 MyBatis Plus 多租户的功能,实现 DB 层面的多租户的功能 |
| 15 | * | 15 | * |
| 16 | - * @author | 16 | + * @author 芋道源码 |
| 17 | */ | 17 | */ |
| 18 | public class TenantDatabaseInterceptor implements TenantLineHandler { | 18 | public class TenantDatabaseInterceptor implements TenantLineHandler { |
| 19 | 19 |
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/util/TenantUtils.java
| @@ -45,6 +45,7 @@ public class TenantUtils { | @@ -45,6 +45,7 @@ public class TenantUtils { | ||
| 45 | * | 45 | * |
| 46 | * @param tenantId 租户编号 | 46 | * @param tenantId 租户编号 |
| 47 | * @param callable 逻辑 | 47 | * @param callable 逻辑 |
| 48 | + * @return 结果 | ||
| 48 | */ | 49 | */ |
| 49 | public static <V> V execute(Long tenantId, Callable<V> callable) { | 50 | public static <V> V execute(Long tenantId, Callable<V> callable) { |
| 50 | Long oldTenantId = TenantContextHolder.getTenantId(); | 51 | Long oldTenantId = TenantContextHolder.getTenantId(); |
| @@ -79,6 +80,25 @@ public class TenantUtils { | @@ -79,6 +80,25 @@ public class TenantUtils { | ||
| 79 | } | 80 | } |
| 80 | 81 | ||
| 81 | /** | 82 | /** |
| 83 | + * 忽略租户,执行对应的逻辑 | ||
| 84 | + * | ||
| 85 | + * @param callable 逻辑 | ||
| 86 | + * @return 结果 | ||
| 87 | + */ | ||
| 88 | + public static <V> V executeIgnore(Callable<V> callable) { | ||
| 89 | + Boolean oldIgnore = TenantContextHolder.isIgnore(); | ||
| 90 | + try { | ||
| 91 | + TenantContextHolder.setIgnore(true); | ||
| 92 | + // 执行逻辑 | ||
| 93 | + return callable.call(); | ||
| 94 | + } catch (Exception e) { | ||
| 95 | + throw new RuntimeException(e); | ||
| 96 | + } finally { | ||
| 97 | + TenantContextHolder.setIgnore(oldIgnore); | ||
| 98 | + } | ||
| 99 | + } | ||
| 100 | + | ||
| 101 | + /** | ||
| 82 | * 将多租户编号,添加到 header 中 | 102 | * 将多租户编号,添加到 header 中 |
| 83 | * | 103 | * |
| 84 | * @param headers HTTP 请求 headers | 104 | * @param headers HTTP 请求 headers |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java renamed to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java
| @@ -5,49 +5,44 @@ import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO; | @@ -5,49 +5,44 @@ import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO; | ||
| 5 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; | 5 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; |
| 6 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO; | 6 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO; |
| 7 | import cn.iocoder.yudao.module.iot.enums.ApiConstants; | 7 | import cn.iocoder.yudao.module.iot.enums.ApiConstants; |
| 8 | -import jakarta.annotation.security.PermitAll; | ||
| 9 | import jakarta.validation.Valid; | 8 | import jakarta.validation.Valid; |
| 10 | import org.springframework.web.bind.annotation.PostMapping; | 9 | import org.springframework.web.bind.annotation.PostMapping; |
| 11 | import org.springframework.web.bind.annotation.PutMapping; | 10 | import org.springframework.web.bind.annotation.PutMapping; |
| 12 | import org.springframework.web.bind.annotation.RequestBody; | 11 | import org.springframework.web.bind.annotation.RequestBody; |
| 13 | 12 | ||
| 14 | -// TODO 芋艿:名字可能看情况改下 | ||
| 15 | /** | 13 | /** |
| 16 | - * 设备数据 API | 14 | + * 设备数据 Upstream 上行 API |
| 15 | + * | ||
| 16 | + * 目的:设备 -> 插件 -> 服务端 | ||
| 17 | * | 17 | * |
| 18 | * @author haohao | 18 | * @author haohao |
| 19 | */ | 19 | */ |
| 20 | -public interface DeviceDataApi { | 20 | +public interface IotDeviceUpstreamApi { |
| 21 | 21 | ||
| 22 | - // TODO @芋艿:可能会调整 | ||
| 23 | - String PREFIX = ApiConstants.PREFIX + "/device-data"; | 22 | + String PREFIX = ApiConstants.PREFIX + "/device/upstream"; |
| 24 | 23 | ||
| 25 | /** | 24 | /** |
| 26 | * 更新设备状态 | 25 | * 更新设备状态 |
| 27 | * | 26 | * |
| 28 | - * @param updateReqDTO 更新请求 | 27 | + * @param updateReqDTO 更新设备状态 DTO |
| 29 | */ | 28 | */ |
| 30 | @PutMapping(PREFIX + "/update-status") | 29 | @PutMapping(PREFIX + "/update-status") |
| 31 | - @PermitAll // TODO 芋艿:后续看看怎么优化下 | ||
| 32 | CommonResult<Boolean> updateDeviceStatus(@Valid @RequestBody IotDeviceStatusUpdateReqDTO updateReqDTO); | 30 | CommonResult<Boolean> updateDeviceStatus(@Valid @RequestBody IotDeviceStatusUpdateReqDTO updateReqDTO); |
| 33 | 31 | ||
| 34 | /** | 32 | /** |
| 35 | - * 上报设备事件数据 | ||
| 36 | - * | ||
| 37 | - * @param reportReqDTO 设备事件 | ||
| 38 | - */ | ||
| 39 | - @PostMapping(PREFIX + "/report-event") | ||
| 40 | - @PermitAll // TODO 芋艿:后续看看怎么优化下 | ||
| 41 | - CommonResult<Boolean> reportDeviceEventData(@Valid @RequestBody IotDeviceEventReportReqDTO reportReqDTO); | ||
| 42 | - | ||
| 43 | - /** | ||
| 44 | * 上报设备属性数据 | 33 | * 上报设备属性数据 |
| 45 | * | 34 | * |
| 46 | - * @param reportReqDTO 设备数据 | 35 | + * @param reportReqDTO 上报设备属性数据 DTO |
| 47 | */ | 36 | */ |
| 48 | @PostMapping(PREFIX + "/report-property") | 37 | @PostMapping(PREFIX + "/report-property") |
| 49 | - @PermitAll // TODO 芋艿:后续看看怎么优化下 | ||
| 50 | CommonResult<Boolean> reportDevicePropertyData(@Valid @RequestBody IotDevicePropertyReportReqDTO reportReqDTO); | 38 | CommonResult<Boolean> reportDevicePropertyData(@Valid @RequestBody IotDevicePropertyReportReqDTO reportReqDTO); |
| 51 | 39 | ||
| 40 | + /** | ||
| 41 | + * 上报设备事件数据 | ||
| 42 | + * | ||
| 43 | + * @param reportReqDTO 设备事件 | ||
| 44 | + */ | ||
| 45 | + @PostMapping(PREFIX + "/report-event") | ||
| 46 | + CommonResult<Boolean> reportDeviceEventData(@Valid @RequestBody IotDeviceEventReportReqDTO reportReqDTO); | ||
| 52 | 47 | ||
| 53 | } | 48 | } |
| 54 | \ No newline at end of file | 49 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceEventReportReqDTO.java
| 1 | package cn.iocoder.yudao.module.iot.api.device.dto; | 1 | package cn.iocoder.yudao.module.iot.api.device.dto; |
| 2 | 2 | ||
| 3 | import jakarta.validation.constraints.NotEmpty; | 3 | import jakarta.validation.constraints.NotEmpty; |
| 4 | -import lombok.AllArgsConstructor; | ||
| 5 | -import lombok.Builder; | ||
| 6 | import lombok.Data; | 4 | import lombok.Data; |
| 7 | import lombok.NoArgsConstructor; | 5 | import lombok.NoArgsConstructor; |
| 6 | +import lombok.experimental.SuperBuilder; | ||
| 8 | 7 | ||
| 9 | import java.util.Map; | 8 | import java.util.Map; |
| 10 | 9 | ||
| @@ -12,24 +11,9 @@ import java.util.Map; | @@ -12,24 +11,9 @@ import java.util.Map; | ||
| 12 | * IoT 设备【事件】数据上报 Request DTO | 11 | * IoT 设备【事件】数据上报 Request DTO |
| 13 | */ | 12 | */ |
| 14 | @Data | 13 | @Data |
| 14 | +@SuperBuilder | ||
| 15 | @NoArgsConstructor | 15 | @NoArgsConstructor |
| 16 | -@AllArgsConstructor | ||
| 17 | -@Builder | ||
| 18 | -public class IotDeviceEventReportReqDTO { | ||
| 19 | - | ||
| 20 | - // TODO 芋艿:要不要 id | ||
| 21 | - // TODO 芋艿:要不要 time | ||
| 22 | - | ||
| 23 | - /** | ||
| 24 | - * 产品标识 | ||
| 25 | - */ | ||
| 26 | - @NotEmpty(message = "产品标识不能为空") | ||
| 27 | - private String productKey; | ||
| 28 | - /** | ||
| 29 | - * 设备名称 | ||
| 30 | - */ | ||
| 31 | - @NotEmpty(message = "设备名称不能为空") | ||
| 32 | - private String deviceName; | 16 | +public class IotDeviceEventReportReqDTO extends IotDeviceUpstreamAbstractReqDTO { |
| 33 | 17 | ||
| 34 | /** | 18 | /** |
| 35 | * 事件标识 | 19 | * 事件标识 |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDevicePropertyReportReqDTO.java
| 1 | package cn.iocoder.yudao.module.iot.api.device.dto; | 1 | package cn.iocoder.yudao.module.iot.api.device.dto; |
| 2 | 2 | ||
| 3 | import jakarta.validation.constraints.NotEmpty; | 3 | import jakarta.validation.constraints.NotEmpty; |
| 4 | -import lombok.AllArgsConstructor; | ||
| 5 | -import lombok.Builder; | ||
| 6 | import lombok.Data; | 4 | import lombok.Data; |
| 7 | import lombok.NoArgsConstructor; | 5 | import lombok.NoArgsConstructor; |
| 6 | +import lombok.experimental.SuperBuilder; | ||
| 8 | 7 | ||
| 9 | import java.util.Map; | 8 | import java.util.Map; |
| 10 | 9 | ||
| @@ -12,28 +11,14 @@ import java.util.Map; | @@ -12,28 +11,14 @@ import java.util.Map; | ||
| 12 | * IoT 设备【属性】数据上报 Request DTO | 11 | * IoT 设备【属性】数据上报 Request DTO |
| 13 | */ | 12 | */ |
| 14 | @Data | 13 | @Data |
| 14 | +@SuperBuilder | ||
| 15 | @NoArgsConstructor | 15 | @NoArgsConstructor |
| 16 | -@AllArgsConstructor | ||
| 17 | -@Builder | ||
| 18 | -public class IotDevicePropertyReportReqDTO { | 16 | +public class IotDevicePropertyReportReqDTO extends IotDeviceUpstreamAbstractReqDTO { |
| 19 | 17 | ||
| 20 | - // TODO 芋艿:要不要 id | ||
| 21 | - // TODO 芋艿:要不要 time | ||
| 22 | - | ||
| 23 | - /** | ||
| 24 | - * 产品标识 | ||
| 25 | - */ | ||
| 26 | - @NotEmpty(message = "产品标识不能为空") | ||
| 27 | - private String productKey; | ||
| 28 | - /** | ||
| 29 | - * 设备名称 | ||
| 30 | - */ | ||
| 31 | - @NotEmpty(message = "设备名称不能为空") | ||
| 32 | - private String deviceName; | ||
| 33 | /** | 18 | /** |
| 34 | * 属性参数 | 19 | * 属性参数 |
| 35 | */ | 20 | */ |
| 36 | @NotEmpty(message = "属性参数不能为空") | 21 | @NotEmpty(message = "属性参数不能为空") |
| 37 | - private Map<String, Object> params; | 22 | + private Map<String, Object> properties; |
| 38 | 23 | ||
| 39 | } | 24 | } |
| 40 | \ No newline at end of file | 25 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceStatusUpdateReqDTO.java
| @@ -3,33 +3,18 @@ package cn.iocoder.yudao.module.iot.api.device.dto; | @@ -3,33 +3,18 @@ package cn.iocoder.yudao.module.iot.api.device.dto; | ||
| 3 | import cn.iocoder.yudao.framework.common.validation.InEnum; | 3 | import cn.iocoder.yudao.framework.common.validation.InEnum; |
| 4 | import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; | 4 | import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; |
| 5 | import jakarta.validation.constraints.NotEmpty; | 5 | import jakarta.validation.constraints.NotEmpty; |
| 6 | -import lombok.AllArgsConstructor; | ||
| 7 | -import lombok.Builder; | ||
| 8 | import lombok.Data; | 6 | import lombok.Data; |
| 9 | import lombok.NoArgsConstructor; | 7 | import lombok.NoArgsConstructor; |
| 8 | +import lombok.experimental.SuperBuilder; | ||
| 10 | 9 | ||
| 11 | /** | 10 | /** |
| 12 | * IoT 设备状态更新 Request DTO | 11 | * IoT 设备状态更新 Request DTO |
| 13 | */ | 12 | */ |
| 14 | @Data | 13 | @Data |
| 14 | +@SuperBuilder | ||
| 15 | @NoArgsConstructor | 15 | @NoArgsConstructor |
| 16 | -@AllArgsConstructor | ||
| 17 | -@Builder | ||
| 18 | -public class IotDeviceStatusUpdateReqDTO { | 16 | +public class IotDeviceStatusUpdateReqDTO extends IotDeviceUpstreamAbstractReqDTO { |
| 19 | 17 | ||
| 20 | - // TODO 芋艿:要不要 id | ||
| 21 | - // TODO 芋艿:要不要 time | ||
| 22 | - | ||
| 23 | - /** | ||
| 24 | - * 产品标识 | ||
| 25 | - */ | ||
| 26 | - @NotEmpty(message = "产品标识不能为空") | ||
| 27 | - private String productKey; | ||
| 28 | - /** | ||
| 29 | - * 设备名称 | ||
| 30 | - */ | ||
| 31 | - @NotEmpty(message = "设备名称不能为空") | ||
| 32 | - private String deviceName; | ||
| 33 | /** | 18 | /** |
| 34 | * 设备状态 | 19 | * 设备状态 |
| 35 | */ | 20 | */ |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceUpstreamAbstractReqDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.api.device.dto; | ||
| 2 | + | ||
| 3 | +import jakarta.validation.constraints.NotEmpty; | ||
| 4 | +import lombok.Data; | ||
| 5 | +import lombok.NoArgsConstructor; | ||
| 6 | +import lombok.experimental.SuperBuilder; | ||
| 7 | + | ||
| 8 | +import java.time.LocalDateTime; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * IoT 设备上行的抽象 Request DTO | ||
| 12 | + * | ||
| 13 | + * @author 芋道源码 | ||
| 14 | + */ | ||
| 15 | +@Data | ||
| 16 | +@SuperBuilder | ||
| 17 | +@NoArgsConstructor | ||
| 18 | +public abstract class IotDeviceUpstreamAbstractReqDTO { | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 请求编号 | ||
| 22 | + */ | ||
| 23 | + private String requestId; | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * 插件标识 | ||
| 27 | + */ | ||
| 28 | + private String pluginKey; | ||
| 29 | + | ||
| 30 | + /** | ||
| 31 | + * 产品标识 | ||
| 32 | + */ | ||
| 33 | + @NotEmpty(message = "产品标识不能为空") | ||
| 34 | + private String productKey; | ||
| 35 | + /** | ||
| 36 | + * 设备名称 | ||
| 37 | + */ | ||
| 38 | + @NotEmpty(message = "设备名称不能为空") | ||
| 39 | + private String deviceName; | ||
| 40 | + | ||
| 41 | + /** | ||
| 42 | + * 上报时间 | ||
| 43 | + */ | ||
| 44 | + private LocalDateTime reportTime; | ||
| 45 | + | ||
| 46 | +} |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.enums.device; | ||
| 2 | + | ||
| 3 | +import lombok.Getter; | ||
| 4 | +import lombok.RequiredArgsConstructor; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * IoT 设备消息标识符枚举 | ||
| 8 | + */ | ||
| 9 | +@Getter | ||
| 10 | +@RequiredArgsConstructor | ||
| 11 | +public enum IotDeviceMessageIdentifierEnum { | ||
| 12 | + | ||
| 13 | + PROPERTY_GET("get"), | ||
| 14 | + PROPERTY_SET("set"), | ||
| 15 | + PROPERTY_REPORT("report"); | ||
| 16 | + | ||
| 17 | + /** | ||
| 18 | + * 标志符 | ||
| 19 | + */ | ||
| 20 | + private final String identifier; | ||
| 21 | + | ||
| 22 | +} |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.enums.device; | ||
| 2 | + | ||
| 3 | +import lombok.Getter; | ||
| 4 | +import lombok.RequiredArgsConstructor; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * IoT 设备消息类型枚举 | ||
| 8 | + */ | ||
| 9 | +@Getter | ||
| 10 | +@RequiredArgsConstructor | ||
| 11 | +public enum IotDeviceMessageTypeEnum { | ||
| 12 | + | ||
| 13 | + STATE("state"), // 设备状态 | ||
| 14 | + PROPERTY("property"), // 设备属性 | ||
| 15 | + EVENT("event"); // 设备事件 | ||
| 16 | + | ||
| 17 | + /** | ||
| 18 | + * 属性 | ||
| 19 | + */ | ||
| 20 | + private final String type; | ||
| 21 | + | ||
| 22 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java
| @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; | @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 4 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO; | 4 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO; |
| 5 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; | 5 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; |
| 6 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO; | 6 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO; |
| 7 | -import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; | 7 | +import cn.iocoder.yudao.module.iot.service.device.upstream.IotDeviceUpstreamService; |
| 8 | import org.springframework.validation.annotation.Validated; | 8 | import org.springframework.validation.annotation.Validated; |
| 9 | import org.springframework.web.bind.annotation.RestController; | 9 | import org.springframework.web.bind.annotation.RestController; |
| 10 | 10 | ||
| @@ -13,28 +13,30 @@ import javax.annotation.Resource; | @@ -13,28 +13,30 @@ import javax.annotation.Resource; | ||
| 13 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 13 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 14 | 14 | ||
| 15 | /** | 15 | /** |
| 16 | - * 设备数据 API 实现类 | 16 | + * * 设备数据 Upstream 上行 API 实现类 |
| 17 | */ | 17 | */ |
| 18 | @RestController | 18 | @RestController |
| 19 | @Validated | 19 | @Validated |
| 20 | -public class DeviceDataApiImpl implements DeviceDataApi { | 20 | +public class IoTDeviceUpstreamApiImpl implements IotDeviceUpstreamApi { |
| 21 | 21 | ||
| 22 | @Resource | 22 | @Resource |
| 23 | - private IotDevicePropertyDataService deviceDataService; | 23 | + private IotDeviceUpstreamService deviceUpstreamService; |
| 24 | 24 | ||
| 25 | @Override | 25 | @Override |
| 26 | public CommonResult<Boolean> updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) { | 26 | public CommonResult<Boolean> updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) { |
| 27 | + deviceUpstreamService.updateDeviceStatus(updateReqDTO); | ||
| 27 | return success(true); | 28 | return success(true); |
| 28 | } | 29 | } |
| 29 | 30 | ||
| 30 | @Override | 31 | @Override |
| 31 | - public CommonResult<Boolean> reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) { | 32 | + public CommonResult<Boolean> reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) { |
| 33 | + deviceUpstreamService.reportDevicePropertyData(reportReqDTO); | ||
| 32 | return success(true); | 34 | return success(true); |
| 33 | } | 35 | } |
| 34 | 36 | ||
| 35 | @Override | 37 | @Override |
| 36 | - public CommonResult<Boolean> reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) { | ||
| 37 | - deviceDataService.saveDeviceData(reportReqDTO); | 38 | + public CommonResult<Boolean> reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) { |
| 39 | + deviceUpstreamService.reportDeviceEventData(reportReqDTO); | ||
| 38 | return success(true); | 40 | return success(true); |
| 39 | } | 41 | } |
| 40 | 42 |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java
| @@ -6,8 +6,8 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | @@ -6,8 +6,8 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 6 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.*; | 6 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.*; |
| 7 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; | 7 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; |
| 8 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; | 8 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; |
| 9 | -import cn.iocoder.yudao.module.iot.service.device.IotDeviceLogDataService; | ||
| 10 | -import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; | 9 | +import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService; |
| 10 | +import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; | ||
| 11 | import io.swagger.v3.oas.annotations.Operation; | 11 | import io.swagger.v3.oas.annotations.Operation; |
| 12 | import io.swagger.v3.oas.annotations.tags.Tag; | 12 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 13 | import jakarta.annotation.Resource; | 13 | import jakarta.annotation.Resource; |
| @@ -27,13 +27,13 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | @@ -27,13 +27,13 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||
| 27 | public class IotDeviceDataController { | 27 | public class IotDeviceDataController { |
| 28 | 28 | ||
| 29 | @Resource | 29 | @Resource |
| 30 | - private IotDevicePropertyDataService deviceDataService; | 30 | + private IotDevicePropertyService deviceDataService; |
| 31 | 31 | ||
| 32 | @Resource | 32 | @Resource |
| 33 | - private IotDeviceLogDataService iotDeviceLogDataService; | 33 | + private IotDeviceLogService iotDeviceLogDataService; |
| 34 | 34 | ||
| 35 | @Resource // TODO @super:service 之间,不用空行;原因是,这样更简洁;空行,主要是为了“间隔”,提升可读性 | 35 | @Resource // TODO @super:service 之间,不用空行;原因是,这样更简洁;空行,主要是为了“间隔”,提升可读性 |
| 36 | - private IotDeviceLogDataService deviceLogDataService; | 36 | + private IotDeviceLogService deviceLogDataService; |
| 37 | 37 | ||
| 38 | // TODO @浩浩:这里的 /latest-list,包括方法名。 | 38 | // TODO @浩浩:这里的 /latest-list,包括方法名。 |
| 39 | @GetMapping("/latest") | 39 | @GetMapping("/latest") |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java
| @@ -36,6 +36,8 @@ public class IotDeviceDO extends BaseDO { | @@ -36,6 +36,8 @@ public class IotDeviceDO extends BaseDO { | ||
| 36 | private Long id; | 36 | private Long id; |
| 37 | /** | 37 | /** |
| 38 | * 设备唯一标识符,全局唯一,用于识别设备 | 38 | * 设备唯一标识符,全局唯一,用于识别设备 |
| 39 | + * | ||
| 40 | + * 类似阿里云 <a href="https://help.aliyun.com/zh/iot/developer-reference/api-querydeviceinfo">QueryDeviceInfo</a> 的 IotInstanceId | ||
| 39 | */ | 41 | */ |
| 40 | private String deviceKey; | 42 | private String deviceKey; |
| 41 | /** | 43 | /** |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceLogDO.java
| 1 | package cn.iocoder.yudao.module.iot.dal.dataobject.device; | 1 | package cn.iocoder.yudao.module.iot.dal.dataobject.device; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.util.IdUtil; | ||
| 3 | import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; | 4 | import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; |
| 5 | +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; | ||
| 6 | +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; | ||
| 7 | +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; | ||
| 4 | import lombok.AllArgsConstructor; | 8 | import lombok.AllArgsConstructor; |
| 5 | import lombok.Builder; | 9 | import lombok.Builder; |
| 6 | import lombok.Data; | 10 | import lombok.Data; |
| @@ -19,37 +23,51 @@ import lombok.NoArgsConstructor; | @@ -19,37 +23,51 @@ import lombok.NoArgsConstructor; | ||
| 19 | @AllArgsConstructor | 23 | @AllArgsConstructor |
| 20 | public class IotDeviceLogDO { | 24 | public class IotDeviceLogDO { |
| 21 | 25 | ||
| 22 | - // TODO @芋艿:消息 ID 的生成逻辑 | ||
| 23 | /** | 26 | /** |
| 24 | - * 消息 ID | 27 | + * 日志编号 |
| 28 | + * | ||
| 29 | + * 通过 {@link IdUtil#fastSimpleUUID()} 生成 | ||
| 25 | */ | 30 | */ |
| 26 | private String id; | 31 | private String id; |
| 27 | 32 | ||
| 28 | /** | 33 | /** |
| 34 | + * 请求编号 | ||
| 35 | + * | ||
| 36 | + * 对应 {@link IotDeviceMessage#getRequestId()} 字段 | ||
| 37 | + */ | ||
| 38 | + private String requestId; | ||
| 39 | + | ||
| 40 | + /** | ||
| 29 | * 产品标识 | 41 | * 产品标识 |
| 30 | * <p> | 42 | * <p> |
| 31 | * 关联 {@link IotProductDO#getProductKey()} | 43 | * 关联 {@link IotProductDO#getProductKey()} |
| 32 | */ | 44 | */ |
| 33 | private String productKey; | 45 | private String productKey; |
| 34 | - | 46 | + /** |
| 47 | + * 设备名称 | ||
| 48 | + * | ||
| 49 | + * 关联 {@link IotDeviceDO#getDeviceName()} | ||
| 50 | + */ | ||
| 51 | + private String deviceName; | ||
| 35 | /** | 52 | /** |
| 36 | * 设备标识 | 53 | * 设备标识 |
| 37 | * <p> | 54 | * <p> |
| 38 | * 关联 {@link IotDeviceDO#getDeviceKey()}} | 55 | * 关联 {@link IotDeviceDO#getDeviceKey()}} |
| 39 | */ | 56 | */ |
| 40 | - private String deviceKey; | 57 | + private String deviceKey; // 非存储字段,用于 TDengine 的 TAG |
| 41 | 58 | ||
| 42 | - // TODO @super:枚举类 | ||
| 43 | /** | 59 | /** |
| 44 | * 日志类型 | 60 | * 日志类型 |
| 61 | + * | ||
| 62 | + * 枚举 {@link IotDeviceMessageTypeEnum} | ||
| 45 | */ | 63 | */ |
| 46 | private String type; | 64 | private String type; |
| 47 | - | ||
| 48 | - // TODO @super:枚举类 | ||
| 49 | /** | 65 | /** |
| 50 | - * 标识符:用于标识具体的属性、事件或服务 | 66 | + * 标识符 |
| 67 | + * | ||
| 68 | + * 枚举 {@link IotDeviceMessageIdentifierEnum} | ||
| 51 | */ | 69 | */ |
| 52 | - private String subType; | 70 | + private String identifier; |
| 53 | 71 | ||
| 54 | /** | 72 | /** |
| 55 | * 数据内容 | 73 | * 数据内容 |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java
| @@ -22,21 +22,13 @@ public interface IotDeviceLogDataMapper { | @@ -22,21 +22,13 @@ public interface IotDeviceLogDataMapper { | ||
| 22 | */ | 22 | */ |
| 23 | void createDeviceLogSTable(); | 23 | void createDeviceLogSTable(); |
| 24 | 24 | ||
| 25 | - // TODO @super:单个参数,不用加 @Param | ||
| 26 | - // TODO @芋艿:在瞅瞅 | ||
| 27 | - //讨论:艿菇这里有些特殊情况,我也学习了一下这块知识: | ||
| 28 | - // 如果使用的是Java 8及以上版本,并且编译器保留了参数名(通过编译器选项-parameters启用),则可以去掉@Param注解。MyBatis会自动使用参数的实际名称 | ||
| 29 | - // 但在TDengine中 @Param去掉后TDengine会报错,以下是大模型的回答: | ||
| 30 | - // 不用加 @Param在普通的 MySQL 场景下是正确的 - 对于 MyBatis,当方法只有一个参数时,确实可以不用添加 @Param 注解。 | ||
| 31 | - //但是在 TDengine 的场景下,情况不同: | ||
| 32 | - //TDengine 的特殊性: | ||
| 33 | - //TDengine 使用特殊的 SQL 语法 | ||
| 34 | - //需要处理超级表(STable)和子表的概念 | ||
| 35 | - //参数绑定的方式与普通 MySQL 不同 | ||
| 36 | - //为什么这里必须要 @Param: | ||
| 37 | - //XML 中使用了 ${log.deviceKey} 这样的参数引用方式 | ||
| 38 | - //需要在 SQL 中动态构建表名(device_log_${log.deviceKey}) | ||
| 39 | - //没有 @Param("log") 的话,MyBatis 无法正确解析参数 | 25 | + /** |
| 26 | + * 查询设备日志表是否存在 | ||
| 27 | + * | ||
| 28 | + * @return 存在则返回表名;不存在则返回 null | ||
| 29 | + */ | ||
| 30 | + String showDeviceLogSTable(); | ||
| 31 | + | ||
| 40 | /** | 32 | /** |
| 41 | * 插入设备日志数据 | 33 | * 插入设备日志数据 |
| 42 | * | 34 | * |
| @@ -44,7 +36,7 @@ public interface IotDeviceLogDataMapper { | @@ -44,7 +36,7 @@ public interface IotDeviceLogDataMapper { | ||
| 44 | * | 36 | * |
| 45 | * @param log 设备日志数据 | 37 | * @param log 设备日志数据 |
| 46 | */ | 38 | */ |
| 47 | - void insert(@Param("log") IotDeviceLogDO log); | 39 | + void insert(IotDeviceLogDO log); |
| 48 | 40 | ||
| 49 | /** | 41 | /** |
| 50 | * 获得设备日志分页 | 42 | * 获得设备日志分页 |
| @@ -62,12 +54,4 @@ public interface IotDeviceLogDataMapper { | @@ -62,12 +54,4 @@ public interface IotDeviceLogDataMapper { | ||
| 62 | */ | 54 | */ |
| 63 | Long selectCount(@Param("reqVO") IotDeviceLogPageReqVO reqVO); | 55 | Long selectCount(@Param("reqVO") IotDeviceLogPageReqVO reqVO); |
| 64 | 56 | ||
| 65 | - // TODO @芋艿:这个方法名,后续看看叫啥好 | ||
| 66 | - /** | ||
| 67 | - * 查询设备日志表是否存在 | ||
| 68 | - * | ||
| 69 | - * @return 不存在返回 null | ||
| 70 | - */ | ||
| 71 | - Object checkDeviceLogSTableExists(); | ||
| 72 | - | ||
| 73 | } | 57 | } |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java
| 1 | package cn.iocoder.yudao.module.iot.emq.service; | 1 | package cn.iocoder.yudao.module.iot.emq.service; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; | 3 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; |
| 4 | -import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; | 4 | +import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; |
| 5 | import jakarta.annotation.Resource; | 5 | import jakarta.annotation.Resource; |
| 6 | import lombok.extern.slf4j.Slf4j; | 6 | import lombok.extern.slf4j.Slf4j; |
| 7 | import org.eclipse.paho.client.mqttv3.MqttClient; | 7 | import org.eclipse.paho.client.mqttv3.MqttClient; |
| @@ -20,7 +20,7 @@ import org.springframework.scheduling.annotation.Async; | @@ -20,7 +20,7 @@ import org.springframework.scheduling.annotation.Async; | ||
| 20 | public class EmqxServiceImpl implements EmqxService { | 20 | public class EmqxServiceImpl implements EmqxService { |
| 21 | 21 | ||
| 22 | @Resource | 22 | @Resource |
| 23 | - private IotDevicePropertyDataService iotDeviceDataService; | 23 | + private IotDevicePropertyService iotDeviceDataService; |
| 24 | 24 | ||
| 25 | // TODO 多线程处理消息 | 25 | // TODO 多线程处理消息 |
| 26 | @Override | 26 | @Override |
| @@ -35,8 +35,8 @@ public class EmqxServiceImpl implements EmqxService { | @@ -35,8 +35,8 @@ public class EmqxServiceImpl implements EmqxService { | ||
| 35 | String deviceName = topic.split("/")[3]; | 35 | String deviceName = topic.split("/")[3]; |
| 36 | String message = new String(mqttMessage.getPayload()); | 36 | String message = new String(mqttMessage.getPayload()); |
| 37 | IotDevicePropertyReportReqDTO createDTO = IotDevicePropertyReportReqDTO.builder() | 37 | IotDevicePropertyReportReqDTO createDTO = IotDevicePropertyReportReqDTO.builder() |
| 38 | - .productKey(productKey) | ||
| 39 | - .deviceName(deviceName) | 38 | +// .productKey(productKey) |
| 39 | +// .deviceName(deviceName) | ||
| 40 | // .properties(message) // TODO 芋艿:临时去掉,看看 | 40 | // .properties(message) // TODO 芋艿:临时去掉,看看 |
| 41 | .build(); | 41 | .build(); |
| 42 | iotDeviceDataService.saveDeviceData(createDTO); | 42 | iotDeviceDataService.saveDeviceData(createDTO); |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/aspect/TaosAspect.java
| @@ -9,6 +9,7 @@ import org.springframework.stereotype.Component; | @@ -9,6 +9,7 @@ import org.springframework.stereotype.Component; | ||
| 9 | import java.sql.Timestamp; | 9 | import java.sql.Timestamp; |
| 10 | import java.util.Map; | 10 | import java.util.Map; |
| 11 | 11 | ||
| 12 | +// TODO @haohao:这个还需要的么? | ||
| 12 | /** | 13 | /** |
| 13 | * TaosAspect 是一个处理 Taos 数据库返回值的切面。 | 14 | * TaosAspect 是一个处理 Taos 数据库返回值的切面。 |
| 14 | */ | 15 | */ |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/security/config/SecurityConfiguration.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.framework.security.config; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer; | ||
| 4 | +import cn.iocoder.yudao.module.iot.enums.ApiConstants; | ||
| 5 | +import org.springframework.context.annotation.Bean; | ||
| 6 | +import org.springframework.context.annotation.Configuration; | ||
| 7 | +import org.springframework.security.config.annotation.web.builders.HttpSecurity; | ||
| 8 | +import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * IoT 模块的 Security 配置 | ||
| 12 | + */ | ||
| 13 | +@Configuration(proxyBeanMethods = false, value = "iotSecurityConfiguration") | ||
| 14 | +public class SecurityConfiguration { | ||
| 15 | + | ||
| 16 | + @Bean("iotAuthorizeRequestsCustomizer") | ||
| 17 | + public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() { | ||
| 18 | + return new AuthorizeRequestsCustomizer() { | ||
| 19 | + | ||
| 20 | + @Override | ||
| 21 | + public void customize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) { | ||
| 22 | + // RPC 服务的安全配置 | ||
| 23 | + registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll(); | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + }; | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/package-info.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/security/core/package-info.java
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitConfiguration.java
| 1 | package cn.iocoder.yudao.module.iot.framework.tdengine.config; | 1 | package cn.iocoder.yudao.module.iot.framework.tdengine.config; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.yudao.module.iot.service.device.IotDeviceLogDataService; | 3 | +import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService; |
| 4 | import lombok.RequiredArgsConstructor; | 4 | import lombok.RequiredArgsConstructor; |
| 5 | import lombok.extern.slf4j.Slf4j; | 5 | import lombok.extern.slf4j.Slf4j; |
| 6 | import org.springframework.boot.ApplicationArguments; | 6 | import org.springframework.boot.ApplicationArguments; |
| @@ -17,7 +17,7 @@ import org.springframework.context.annotation.Configuration; | @@ -17,7 +17,7 @@ import org.springframework.context.annotation.Configuration; | ||
| 17 | @RequiredArgsConstructor | 17 | @RequiredArgsConstructor |
| 18 | public class TDengineTableInitConfiguration implements ApplicationRunner { | 18 | public class TDengineTableInitConfiguration implements ApplicationRunner { |
| 19 | 19 | ||
| 20 | - private final IotDeviceLogDataService deviceLogService; | 20 | + private final IotDeviceLogService deviceLogService; |
| 21 | 21 | ||
| 22 | @Override | 22 | @Override |
| 23 | public void run(ApplicationArguments args) { | 23 | public void run(ApplicationArguments args) { |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/PluginInstancesJob.java
| @@ -8,6 +8,7 @@ import org.springframework.stereotype.Component; | @@ -8,6 +8,7 @@ import org.springframework.stereotype.Component; | ||
| 8 | import javax.annotation.Resource; | 8 | import javax.annotation.Resource; |
| 9 | import java.util.concurrent.TimeUnit; | 9 | import java.util.concurrent.TimeUnit; |
| 10 | 10 | ||
| 11 | +// TODO 芋艿:后续再看看 | ||
| 11 | /** | 12 | /** |
| 12 | * 插件实例 Job | 13 | * 插件实例 Job |
| 13 | * | 14 | * |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceLogMessageConsumer.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.mq.consumer.device; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; | ||
| 4 | +import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService; | ||
| 5 | +import jakarta.annotation.Resource; | ||
| 6 | +import lombok.extern.slf4j.Slf4j; | ||
| 7 | +import org.springframework.context.event.EventListener; | ||
| 8 | +import org.springframework.scheduling.annotation.Async; | ||
| 9 | +import org.springframework.stereotype.Component; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * 针对 {@link IotDeviceMessage} 的消费者,记录设备日志 | ||
| 13 | + * | ||
| 14 | + * @author 芋道源码 | ||
| 15 | + */ | ||
| 16 | +@Component | ||
| 17 | +@Slf4j | ||
| 18 | +public class IotDeviceLogMessageConsumer { | ||
| 19 | + | ||
| 20 | + @Resource | ||
| 21 | + private IotDeviceLogService deviceLogService; | ||
| 22 | + | ||
| 23 | + @EventListener | ||
| 24 | + @Async | ||
| 25 | + public void onMessage(IotDeviceMessage message) { | ||
| 26 | + log.info("[onMessage][消息内容({})]", message); | ||
| 27 | + deviceLogService.createDeviceLog(message); | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/deviceconsumer/DeviceConsumer.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageConsumer.java
| 1 | -package cn.iocoder.yudao.module.iot.mq.consumer.deviceconsumer; | 1 | +package cn.iocoder.yudao.module.iot.mq.consumer.device; |
| 2 | 2 | ||
| 3 | - | ||
| 4 | -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; | ||
| 5 | -import cn.iocoder.yudao.module.iot.service.device.IotDeviceLogDataService; | ||
| 6 | -import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; | 3 | +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; |
| 4 | +import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; | ||
| 7 | import lombok.extern.slf4j.Slf4j; | 5 | import lombok.extern.slf4j.Slf4j; |
| 8 | import org.springframework.context.event.EventListener; | 6 | import org.springframework.context.event.EventListener; |
| 9 | import org.springframework.scheduling.annotation.Async; | 7 | import org.springframework.scheduling.annotation.Async; |
| @@ -12,30 +10,25 @@ import org.springframework.stereotype.Component; | @@ -12,30 +10,25 @@ import org.springframework.stereotype.Component; | ||
| 12 | import javax.annotation.Resource; | 10 | import javax.annotation.Resource; |
| 13 | 11 | ||
| 14 | /** | 12 | /** |
| 15 | - * 针对 {@link ThingModelMessage} 的消费者 | 13 | + * 针对 {@link IotDeviceMessage} 的消费者,记录设备属性 |
| 16 | * | 14 | * |
| 17 | * @author alwayssuper | 15 | * @author alwayssuper |
| 18 | */ | 16 | */ |
| 19 | @Component | 17 | @Component |
| 20 | @Slf4j | 18 | @Slf4j |
| 21 | -public class DeviceConsumer { | 19 | +public class IotDevicePropertyMessageConsumer { |
| 22 | 20 | ||
| 23 | @Resource | 21 | @Resource |
| 24 | - private IotDeviceLogDataService deviceLogDataService; | ||
| 25 | - @Resource | ||
| 26 | - private IotDevicePropertyDataService deviceDataService; | 22 | + private IotDevicePropertyService deviceDataService; |
| 27 | 23 | ||
| 28 | - // TODO @芋艿:这块先用ThingModelMessage,后续看看用啥替代 | ||
| 29 | @EventListener | 24 | @EventListener |
| 30 | @Async | 25 | @Async |
| 31 | - public void onMessage(ThingModelMessage message) { | 26 | + public void onMessage(IotDeviceMessage message) { |
| 32 | log.info("[onMessage][消息内容({})]", message); | 27 | log.info("[onMessage][消息内容({})]", message); |
| 33 | - //TODO:数据插入这块整体写的比较混乱,整体借鉴了浩浩哥之前写的逻辑,目前是通过模拟设备科插入数据了,但之前的逻辑有大量弃用的部分,后续看看怎么完善 | ||
| 34 | 28 | ||
| 35 | - // 设备数据记录 | ||
| 36 | - deviceDataService.saveDeviceDataTest(message); | ||
| 37 | // 设备日志记录 | 29 | // 设备日志记录 |
| 38 | - deviceLogDataService.saveDeviceLog(message); | 30 | + // TODO @芋艿:重新写下 |
| 31 | +// deviceLogDataService.createDeviceLog(message); | ||
| 39 | } | 32 | } |
| 40 | 33 | ||
| 41 | } | 34 | } |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/package-info.java
0 → 100644
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessage.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/IotDeviceMessage.java
| 1 | -package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; | 1 | +package cn.iocoder.yudao.module.iot.mq.message; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; | ||
| 4 | +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; | ||
| 3 | import lombok.AllArgsConstructor; | 5 | import lombok.AllArgsConstructor; |
| 4 | import lombok.Builder; | 6 | import lombok.Builder; |
| 5 | import lombok.Data; | 7 | import lombok.Data; |
| 6 | import lombok.NoArgsConstructor; | 8 | import lombok.NoArgsConstructor; |
| 7 | 9 | ||
| 8 | -import java.util.HashMap; | ||
| 9 | -import java.util.Map; | 10 | +import java.time.LocalDateTime; |
| 10 | 11 | ||
| 11 | /** | 12 | /** |
| 12 | - * 物模型消息 | 13 | + * 设备消息 |
| 13 | */ | 14 | */ |
| 14 | @Data | 15 | @Data |
| 15 | @NoArgsConstructor | 16 | @NoArgsConstructor |
| 16 | @AllArgsConstructor | 17 | @AllArgsConstructor |
| 17 | @Builder | 18 | @Builder |
| 18 | -public class ThingModelMessage { | 19 | +public class IotDeviceMessage { |
| 19 | 20 | ||
| 20 | /** | 21 | /** |
| 21 | - * 消息ID | 22 | + * 请求编号 |
| 22 | */ | 23 | */ |
| 23 | - private String id; | 24 | + private String requestId; |
| 24 | 25 | ||
| 25 | /** | 26 | /** |
| 26 | - * 扩展功能的参数 | 27 | + * 设备信息 |
| 27 | */ | 28 | */ |
| 28 | - private Object sys; | ||
| 29 | - | 29 | + private String productKey; |
| 30 | /** | 30 | /** |
| 31 | - * 请求方法 例如:thing.event.property.post | 31 | + * 设备名称 |
| 32 | */ | 32 | */ |
| 33 | - private String method; | ||
| 34 | - | 33 | + private String deviceName; |
| 35 | /** | 34 | /** |
| 36 | - * 请求参数 | 35 | + * 设备标识 |
| 37 | */ | 36 | */ |
| 38 | - private Object params; | 37 | + private String deviceKey; |
| 39 | 38 | ||
| 40 | /** | 39 | /** |
| 41 | - * 属性上报时间戳 | 40 | + * 消息类型 |
| 41 | + * | ||
| 42 | + * 枚举 {@link IotDeviceMessageTypeEnum} | ||
| 42 | */ | 43 | */ |
| 43 | - private Long time; | ||
| 44 | - | 44 | + private String type; |
| 45 | /** | 45 | /** |
| 46 | - * 设备信息 | 46 | + * 标识符 |
| 47 | + * | ||
| 48 | + * 枚举 {@link IotDeviceMessageIdentifierEnum} | ||
| 47 | */ | 49 | */ |
| 48 | - private String productKey; | 50 | + private String identifier; |
| 49 | 51 | ||
| 50 | /** | 52 | /** |
| 51 | - * 设备名称 | 53 | + * 请求参数 |
| 54 | + * | ||
| 55 | + * 例如说:属性上报的 properties、事件上报的 params | ||
| 52 | */ | 56 | */ |
| 53 | - private String deviceName; | 57 | + private Object data; |
| 54 | 58 | ||
| 55 | /** | 59 | /** |
| 56 | - * 设备 key | 60 | + * 上报时间 |
| 57 | */ | 61 | */ |
| 58 | - private String deviceKey; | 62 | + private LocalDateTime reportTime; |
| 63 | + | ||
| 64 | + // TODO @芋艿 code; | ||
| 59 | 65 | ||
| 60 | - /** | ||
| 61 | - * 转换为 Map 类型 | ||
| 62 | - */ | ||
| 63 | - public Map<String, Object> dataToMap() { | ||
| 64 | - Map<String, Object> mapData = new HashMap<>(); | ||
| 65 | - if (params instanceof Map) { | ||
| 66 | - ((Map<?, ?>) params).forEach((key, value) -> mapData.put(key.toString(), value)); | ||
| 67 | - } | ||
| 68 | - return mapData; | ||
| 69 | - } | ||
| 70 | } | 66 | } |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/device/IotDeviceProducer.java
| 1 | -package cn.iocoder.yudao.module.iot.mq.producer.simulatesend; | 1 | +package cn.iocoder.yudao.module.iot.mq.producer.device; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; | 3 | +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; |
| 4 | import jakarta.annotation.Resource; | 4 | import jakarta.annotation.Resource; |
| 5 | import lombok.extern.slf4j.Slf4j; | 5 | import lombok.extern.slf4j.Slf4j; |
| 6 | import org.springframework.context.ApplicationContext; | 6 | import org.springframework.context.ApplicationContext; |
| 7 | import org.springframework.stereotype.Component; | 7 | import org.springframework.stereotype.Component; |
| 8 | 8 | ||
| 9 | -// TODO @芋艿:@alwayssuper:是不是还没用起来哈?Producer 最好属于某个模块; | ||
| 10 | /** | 9 | /** |
| 11 | - * SimulateSend 模拟设备上报的 Producer | 10 | + * Iot 设备相关消息的 Producer |
| 12 | * | 11 | * |
| 13 | * @author alwayssuper | 12 | * @author alwayssuper |
| 14 | * @since 2024/12/17 16:35 | 13 | * @since 2024/12/17 16:35 |
| 15 | */ | 14 | */ |
| 16 | @Slf4j | 15 | @Slf4j |
| 17 | @Component | 16 | @Component |
| 18 | -public class SimulateSendProducer { | 17 | +public class IotDeviceProducer { |
| 19 | 18 | ||
| 20 | @Resource | 19 | @Resource |
| 21 | private ApplicationContext applicationContext; | 20 | private ApplicationContext applicationContext; |
| 22 | 21 | ||
| 23 | /** | 22 | /** |
| 24 | - * 发送 {@link ThingModelMessage} 消息 | 23 | + * 发送 {@link IotDeviceMessage} 消息 |
| 25 | * | 24 | * |
| 26 | * @param thingModelMessage 物模型消息 | 25 | * @param thingModelMessage 物模型消息 |
| 27 | */ | 26 | */ |
| 28 | - public void sendSimulateMessage(ThingModelMessage thingModelMessage) { | 27 | + public void sendDeviceMessage(IotDeviceMessage thingModelMessage) { |
| 29 | applicationContext.publishEvent(thingModelMessage); | 28 | applicationContext.publishEvent(thingModelMessage); |
| 30 | } | 29 | } |
| 31 | 30 |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/package-info.java
0 → 100644
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java
| 1 | -package cn.iocoder.yudao.module.iot.service.device; | 1 | +package cn.iocoder.yudao.module.iot.service.device.data; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; | ||
| 5 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO; | 4 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO; |
| 6 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; | 5 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; |
| 7 | -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; | 6 | +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; |
| 8 | 7 | ||
| 9 | /** | 8 | /** |
| 10 | * IoT 设备日志数据 Service 接口 | 9 | * IoT 设备日志数据 Service 接口 |
| 11 | * | 10 | * |
| 12 | * @author alwayssuper | 11 | * @author alwayssuper |
| 13 | */ | 12 | */ |
| 14 | -public interface IotDeviceLogDataService { | 13 | +public interface IotDeviceLogService { |
| 15 | 14 | ||
| 16 | /** | 15 | /** |
| 17 | * 初始化 TDengine 超级表 | 16 | * 初始化 TDengine 超级表 |
| @@ -23,11 +22,9 @@ public interface IotDeviceLogDataService { | @@ -23,11 +22,9 @@ public interface IotDeviceLogDataService { | ||
| 23 | /** | 22 | /** |
| 24 | * 插入设备日志 | 23 | * 插入设备日志 |
| 25 | * | 24 | * |
| 26 | - * 当该设备第一次插入日志时,自动创建该设备的设备日志子表 | ||
| 27 | - * | ||
| 28 | - * @param simulatorReqVO 设备日志模拟数据 | 25 | + * @param message 设备数据 |
| 29 | */ | 26 | */ |
| 30 | - void createDeviceLog(IotDeviceDataSimulatorSaveReqVO simulatorReqVO); | 27 | + void createDeviceLog(IotDeviceMessage message); |
| 31 | 28 | ||
| 32 | /** | 29 | /** |
| 33 | * 获得设备日志分页 | 30 | * 获得设备日志分页 |
| @@ -37,11 +34,4 @@ public interface IotDeviceLogDataService { | @@ -37,11 +34,4 @@ public interface IotDeviceLogDataService { | ||
| 37 | */ | 34 | */ |
| 38 | PageResult<IotDeviceLogDO> getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO); | 35 | PageResult<IotDeviceLogDO> getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO); |
| 39 | 36 | ||
| 40 | - /** | ||
| 41 | - * 插入设备日志 | ||
| 42 | - * | ||
| 43 | - * @param message 设备数据 | ||
| 44 | - */ | ||
| 45 | - void saveDeviceLog(ThingModelMessage message); | ||
| 46 | - | ||
| 47 | } | 37 | } |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java
| 1 | -package cn.iocoder.yudao.module.iot.service.device; | 1 | +package cn.iocoder.yudao.module.iot.service.device.data; |
| 2 | 2 | ||
| 3 | -import cn.hutool.json.JSONUtil; | 3 | +import cn.hutool.core.util.IdUtil; |
| 4 | +import cn.hutool.core.util.StrUtil; | ||
| 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | ||
| 5 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 7 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 6 | -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; | ||
| 7 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO; | 8 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO; |
| 8 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; | 9 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; |
| 9 | -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; | ||
| 10 | import cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceLogDataMapper; | 10 | import cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceLogDataMapper; |
| 11 | +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; | ||
| 11 | import jakarta.annotation.Resource; | 12 | import jakarta.annotation.Resource; |
| 12 | import lombok.extern.slf4j.Slf4j; | 13 | import lombok.extern.slf4j.Slf4j; |
| 13 | import org.springframework.stereotype.Service; | 14 | import org.springframework.stereotype.Service; |
| @@ -16,40 +17,36 @@ import org.springframework.validation.annotation.Validated; | @@ -16,40 +17,36 @@ import org.springframework.validation.annotation.Validated; | ||
| 16 | import java.util.List; | 17 | import java.util.List; |
| 17 | 18 | ||
| 18 | /** | 19 | /** |
| 19 | - * IoT 设备日志数据 Service 实现了 | 20 | + * IoT 设备日志数据 Service 实现类 |
| 20 | * | 21 | * |
| 21 | * @author alwayssuper | 22 | * @author alwayssuper |
| 22 | */ | 23 | */ |
| 23 | @Service | 24 | @Service |
| 24 | @Slf4j | 25 | @Slf4j |
| 25 | @Validated | 26 | @Validated |
| 26 | -public class IotDeviceLogDataServiceImpl implements IotDeviceLogDataService{ | 27 | +public class IotDeviceLogServiceImpl implements IotDeviceLogService { |
| 27 | 28 | ||
| 28 | @Resource | 29 | @Resource |
| 29 | private IotDeviceLogDataMapper deviceLogDataMapper; | 30 | private IotDeviceLogDataMapper deviceLogDataMapper; |
| 30 | 31 | ||
| 31 | @Override | 32 | @Override |
| 32 | public void defineDeviceLog() { | 33 | public void defineDeviceLog() { |
| 33 | - if (deviceLogDataMapper.checkDeviceLogSTableExists() != null) { | ||
| 34 | - log.info("[defineDeviceLog][设备日志超级表已存在,跳过创建]"); | 34 | + if (StrUtil.isNotEmpty(deviceLogDataMapper.showDeviceLogSTable())) { |
| 35 | + log.info("[defineDeviceLog][设备日志超级表已存在,创建跳过]"); | ||
| 35 | return; | 36 | return; |
| 36 | } | 37 | } |
| 37 | 38 | ||
| 38 | - log.info("[defineDeviceLog][设备日志超级表不存在,开始创建]"); | 39 | + log.info("[defineDeviceLog][设备日志超级表不存在,创建开始...]"); |
| 39 | deviceLogDataMapper.createDeviceLogSTable(); | 40 | deviceLogDataMapper.createDeviceLogSTable(); |
| 40 | - log.info("[defineDeviceLog][设备日志超级表不存在,创建完成]"); | 41 | + log.info("[defineDeviceLog][设备日志超级表不存在,创建成功]"); |
| 41 | } | 42 | } |
| 42 | 43 | ||
| 43 | @Override | 44 | @Override |
| 44 | - public void createDeviceLog(IotDeviceDataSimulatorSaveReqVO simulatorReqVO) { | ||
| 45 | - // 1. 转换请求对象为 DO | ||
| 46 | - IotDeviceLogDO iotDeviceLogDO = BeanUtils.toBean(simulatorReqVO, IotDeviceLogDO.class); | ||
| 47 | - | ||
| 48 | - // 2. 处理时间字段 | ||
| 49 | -// iotDeviceLogDO.setTs(currentTime); // TODO @super:TS在SQL中直接NOW 咱们的TS数据获取是走哪一种;走 now() | ||
| 50 | - | ||
| 51 | - // 3. 插入数据 | ||
| 52 | - deviceLogDataMapper.insert(iotDeviceLogDO); | 45 | + public void createDeviceLog(IotDeviceMessage message) { |
| 46 | + IotDeviceLogDO log = BeanUtils.toBean(message, IotDeviceLogDO.class) | ||
| 47 | + .setId(IdUtil.fastSimpleUUID()) | ||
| 48 | + .setContent(JsonUtils.toJsonString(message.getData())); | ||
| 49 | + deviceLogDataMapper.insert(log); | ||
| 53 | } | 50 | } |
| 54 | 51 | ||
| 55 | @Override | 52 | @Override |
| @@ -60,18 +57,4 @@ public class IotDeviceLogDataServiceImpl implements IotDeviceLogDataService{ | @@ -60,18 +57,4 @@ public class IotDeviceLogDataServiceImpl implements IotDeviceLogDataService{ | ||
| 60 | return new PageResult<>(list, total); | 57 | return new PageResult<>(list, total); |
| 61 | } | 58 | } |
| 62 | 59 | ||
| 63 | - @Override | ||
| 64 | - public void saveDeviceLog(ThingModelMessage message) { | ||
| 65 | - IotDeviceLogDO log = IotDeviceLogDO.builder() | ||
| 66 | - .id(message.getId()) | ||
| 67 | - .deviceKey(message.getDeviceKey()) | ||
| 68 | - .productKey(message.getProductKey()) | ||
| 69 | - .type(message.getMethod()) // 消息类型,使用method作为类型 TODO 芋艿:在看看 | ||
| 70 | - .subType("property") // TODO 芋艿:这块先写死,后续优化 | ||
| 71 | - .content(JSONUtil.toJsonStr(message)) // TODO 芋艿:后续优化 | ||
| 72 | - .reportTime(message.getTime()) // 上报时间 TODO 芋艿:在想想时间 | ||
| 73 | - .build(); | ||
| 74 | - deviceLogDataMapper.insert(log); | ||
| 75 | - } | ||
| 76 | - | ||
| 77 | } | 60 | } |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java
| 1 | -package cn.iocoder.yudao.module.iot.service.device; | 1 | +package cn.iocoder.yudao.module.iot.service.device.data; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; | 4 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; |
| 5 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; | 5 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; |
| 6 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; | 6 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; |
| 7 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; | 7 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; |
| 8 | -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; | ||
| 9 | import jakarta.validation.Valid; | 8 | import jakarta.validation.Valid; |
| 10 | 9 | ||
| 11 | import java.util.List; | 10 | import java.util.List; |
| @@ -16,7 +15,7 @@ import java.util.Map; | @@ -16,7 +15,7 @@ import java.util.Map; | ||
| 16 | * | 15 | * |
| 17 | * @author 芋道源码 | 16 | * @author 芋道源码 |
| 18 | */ | 17 | */ |
| 19 | -public interface IotDevicePropertyDataService { | 18 | +public interface IotDevicePropertyService { |
| 20 | 19 | ||
| 21 | /** | 20 | /** |
| 22 | * 定义设备属性数据的结构 | 21 | * 定义设备属性数据的结构 |
| @@ -33,13 +32,6 @@ public interface IotDevicePropertyDataService { | @@ -33,13 +32,6 @@ public interface IotDevicePropertyDataService { | ||
| 33 | void saveDeviceData(IotDevicePropertyReportReqDTO createDTO); | 32 | void saveDeviceData(IotDevicePropertyReportReqDTO createDTO); |
| 34 | 33 | ||
| 35 | /** | 34 | /** |
| 36 | - * 保存设备数据 | ||
| 37 | - * | ||
| 38 | - * @param thingModelMessage 设备数据 | ||
| 39 | - */ | ||
| 40 | - void saveDeviceDataTest(ThingModelMessage thingModelMessage); | ||
| 41 | - | ||
| 42 | - /** | ||
| 43 | * 模拟设备 | 35 | * 模拟设备 |
| 44 | * | 36 | * |
| 45 | * @param simulatorReqVO 设备数据 | 37 | * @param simulatorReqVO 设备数据 |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java
| 1 | -package cn.iocoder.yudao.module.iot.service.device; | 1 | +package cn.iocoder.yudao.module.iot.service.device.data; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | import cn.hutool.core.date.DateUtil; | 4 | import cn.hutool.core.date.DateUtil; |
| 5 | import cn.hutool.core.map.MapUtil; | 5 | import cn.hutool.core.map.MapUtil; |
| 6 | -import cn.hutool.core.util.IdUtil; | ||
| 7 | import cn.hutool.core.util.StrUtil; | 6 | import cn.hutool.core.util.StrUtil; |
| 8 | import cn.hutool.json.JSONObject; | 7 | import cn.hutool.json.JSONObject; |
| 9 | import cn.hutool.json.JSONUtil; | 8 | import cn.hutool.json.JSONUtil; |
| @@ -16,18 +15,15 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | @@ -16,18 +15,15 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | ||
| 16 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; | 15 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; |
| 17 | import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; | 16 | import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; |
| 18 | import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; | 17 | import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; |
| 19 | -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; | ||
| 20 | import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; | 18 | import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; |
| 21 | import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; | 19 | import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; |
| 22 | import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper; | 20 | import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper; |
| 23 | -import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; | ||
| 24 | import cn.iocoder.yudao.module.iot.enums.IotConstants; | 21 | import cn.iocoder.yudao.module.iot.enums.IotConstants; |
| 25 | import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum; | 22 | import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum; |
| 26 | import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; | 23 | import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; |
| 27 | import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField; | 24 | import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField; |
| 28 | -import cn.iocoder.yudao.module.iot.mq.producer.simulatesend.SimulateSendProducer; | 25 | +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; |
| 29 | import cn.iocoder.yudao.module.iot.service.product.IotProductService; | 26 | import cn.iocoder.yudao.module.iot.service.product.IotProductService; |
| 30 | -import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService; | ||
| 31 | import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; | 27 | import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; |
| 32 | import jakarta.annotation.Resource; | 28 | import jakarta.annotation.Resource; |
| 33 | import jakarta.validation.Valid; | 29 | import jakarta.validation.Valid; |
| @@ -53,7 +49,7 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_DATA_C | @@ -53,7 +49,7 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_DATA_C | ||
| 53 | */ | 49 | */ |
| 54 | @Service | 50 | @Service |
| 55 | @Slf4j | 51 | @Slf4j |
| 56 | -public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataService { | 52 | +public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { |
| 57 | 53 | ||
| 58 | /** | 54 | /** |
| 59 | * 物模型的数据类型,与 TDengine 数据类型的映射关系 | 55 | * 物模型的数据类型,与 TDengine 数据类型的映射关系 |
| @@ -76,25 +72,16 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe | @@ -76,25 +72,16 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe | ||
| 76 | @Resource | 72 | @Resource |
| 77 | private IotDeviceService deviceService; | 73 | private IotDeviceService deviceService; |
| 78 | @Resource | 74 | @Resource |
| 79 | - private IotThingModelMessageService thingModelMessageService; | ||
| 80 | - @Resource | ||
| 81 | private IotThingModelService thingModelService; | 75 | private IotThingModelService thingModelService; |
| 82 | @Resource | 76 | @Resource |
| 83 | private IotProductService productService; | 77 | private IotProductService productService; |
| 84 | 78 | ||
| 85 | @Resource | 79 | @Resource |
| 86 | - private SimulateSendProducer simulateSendProducer; | ||
| 87 | - | ||
| 88 | - @Resource | ||
| 89 | - private TdEngineDMLMapper tdEngineDMLMapper; | ||
| 90 | - | ||
| 91 | - @Resource | ||
| 92 | private DeviceDataRedisDAO deviceDataRedisDAO; | 80 | private DeviceDataRedisDAO deviceDataRedisDAO; |
| 93 | 81 | ||
| 94 | @Resource | 82 | @Resource |
| 95 | private IotDevicePropertyDataMapper devicePropertyDataMapper; | 83 | private IotDevicePropertyDataMapper devicePropertyDataMapper; |
| 96 | 84 | ||
| 97 | - | ||
| 98 | @Override | 85 | @Override |
| 99 | public void defineDevicePropertyData(Long productId) { | 86 | public void defineDevicePropertyData(Long productId) { |
| 100 | // 1.1 查询产品和物模型 | 87 | // 1.1 查询产品和物模型 |
| @@ -144,28 +131,8 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe | @@ -144,28 +131,8 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe | ||
| 144 | // 1. 根据产品 key 和设备名称,获得设备信息 | 131 | // 1. 根据产品 key 和设备名称,获得设备信息 |
| 145 | IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceName(createDTO.getProductKey(), createDTO.getDeviceName()); | 132 | IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceName(createDTO.getProductKey(), createDTO.getDeviceName()); |
| 146 | // 2. 解析消息,保存数据 | 133 | // 2. 解析消息,保存数据 |
| 147 | - JSONObject jsonObject = new JSONObject(createDTO.getParams()); | 134 | + JSONObject jsonObject = new JSONObject(createDTO.getProperties()); |
| 148 | log.info("[saveDeviceData][productKey({}) deviceName({}) data({})]", createDTO.getProductKey(), createDTO.getDeviceName(), jsonObject); | 135 | log.info("[saveDeviceData][productKey({}) deviceName({}) data({})]", createDTO.getProductKey(), createDTO.getDeviceName(), jsonObject); |
| 149 | - ThingModelMessage thingModelMessage = ThingModelMessage.builder() | ||
| 150 | - .id(jsonObject.getStr("id")) | ||
| 151 | - .sys(jsonObject.get("sys")) | ||
| 152 | - .method(jsonObject.getStr("method")) | ||
| 153 | - .params(jsonObject.get("params")) | ||
| 154 | - .time(jsonObject.getLong("time") == null ? System.currentTimeMillis() : jsonObject.getLong("time")) | ||
| 155 | - .productKey(createDTO.getProductKey()) | ||
| 156 | - .deviceName(createDTO.getDeviceName()) | ||
| 157 | - .deviceKey(device.getDeviceKey()) | ||
| 158 | - .build(); | ||
| 159 | - thingModelMessageService.saveThingModelMessage(device, thingModelMessage); | ||
| 160 | - } | ||
| 161 | - | ||
| 162 | - //TODO @芋艿:后续捋一捋这块逻辑,先借鉴一下目前的代码 | ||
| 163 | - @Override | ||
| 164 | - public void saveDeviceDataTest(ThingModelMessage thingModelMessage) { | ||
| 165 | - // 1. 根据产品 key 和设备名称,获得设备信息 | ||
| 166 | - IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceName(thingModelMessage.getProductKey(), thingModelMessage.getDeviceName()); | ||
| 167 | - // 2. 保存数据 | ||
| 168 | - thingModelMessageService.saveThingModelMessage(device, thingModelMessage); | ||
| 169 | } | 136 | } |
| 170 | 137 | ||
| 171 | //TODO @芋艿:copy 了 saveDeviceData 的逻辑,后续看看这块怎么优化 | 138 | //TODO @芋艿:copy 了 saveDeviceData 的逻辑,后续看看这块怎么优化 |
| @@ -182,20 +149,17 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe | @@ -182,20 +149,17 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe | ||
| 182 | throw exception(DEVICE_DATA_CONTENT_JSON_PARSE_ERROR); | 149 | throw exception(DEVICE_DATA_CONTENT_JSON_PARSE_ERROR); |
| 183 | } | 150 | } |
| 184 | 151 | ||
| 152 | + // TODO @芋艿:后续优化 | ||
| 185 | // 3. 构建物模型消息 | 153 | // 3. 构建物模型消息 |
| 186 | - ThingModelMessage thingModelMessage = ThingModelMessage.builder() | ||
| 187 | - .id(IdUtil.fastSimpleUUID()) // TODO:后续优化 | ||
| 188 | - .sys(null)// TODO:这块先写死,后续优化 | ||
| 189 | - .method("thing.event.property.post") // TODO:这块先写死,后续优化 | ||
| 190 | - .params(contentJson) // 将 content 作为 params | ||
| 191 | - .time(simulatorReqVO.getReportTime()) // 使用上报时间 | ||
| 192 | - .productKey(simulatorReqVO.getProductKey()) | ||
| 193 | - .deviceName(device.getDeviceName()) | ||
| 194 | - .deviceKey(device.getDeviceKey()) | ||
| 195 | - .build(); | 154 | +// IotDeviceMessage thingModelMessage = IotDeviceMessage.builder() |
| 155 | +// .params(contentJson) // 将 content 作为 params | ||
| 156 | +// .time(simulatorReqVO.getReportTime()) // 使用上报时间 | ||
| 157 | +// .productKey(simulatorReqVO.getProductKey()) | ||
| 158 | +// .deviceName(device.getDeviceName()) | ||
| 159 | +// .build(); | ||
| 196 | 160 | ||
| 197 | // 4. 发送模拟消息 | 161 | // 4. 发送模拟消息 |
| 198 | - simulateSendProducer.sendSimulateMessage(thingModelMessage); | 162 | +// simulateSendProducer.sendDeviceMessage(thingModelMessage); |
| 199 | } | 163 | } |
| 200 | 164 | ||
| 201 | @Override | 165 | @Override |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.service.device.upstream; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO; | ||
| 4 | +import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; | ||
| 5 | +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * 设备上行 Service 接口 | ||
| 9 | + * | ||
| 10 | + * 目的:设备 -> 插件 -> 服务端 | ||
| 11 | + * | ||
| 12 | + * @author 芋道源码 | ||
| 13 | + */ | ||
| 14 | +public interface IotDeviceUpstreamService { | ||
| 15 | + | ||
| 16 | + /** | ||
| 17 | + * 更新设备状态 | ||
| 18 | + * | ||
| 19 | + * @param updateReqDTO 更新设备状态 DTO | ||
| 20 | + */ | ||
| 21 | + void updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO); | ||
| 22 | + | ||
| 23 | + /** | ||
| 24 | + * 上报设备属性数据 | ||
| 25 | + * | ||
| 26 | + * @param reportReqDTO 上报设备属性数据 DTO | ||
| 27 | + */ | ||
| 28 | + void reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO); | ||
| 29 | + | ||
| 30 | + /** | ||
| 31 | + * 上报设备事件数据 | ||
| 32 | + * | ||
| 33 | + * @param reportReqDTO 设备事件 | ||
| 34 | + */ | ||
| 35 | + void reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO); | ||
| 36 | + | ||
| 37 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.service.device.upstream; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.util.IdUtil; | ||
| 4 | +import cn.hutool.core.util.StrUtil; | ||
| 5 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 6 | +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; | ||
| 7 | +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO; | ||
| 8 | +import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; | ||
| 9 | +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO; | ||
| 10 | +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceUpstreamAbstractReqDTO; | ||
| 11 | +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | ||
| 12 | +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; | ||
| 13 | +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; | ||
| 14 | +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; | ||
| 15 | +import cn.iocoder.yudao.module.iot.mq.producer.device.IotDeviceProducer; | ||
| 16 | +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; | ||
| 17 | +import jakarta.annotation.Resource; | ||
| 18 | +import lombok.extern.slf4j.Slf4j; | ||
| 19 | +import org.springframework.stereotype.Service; | ||
| 20 | +import org.springframework.validation.annotation.Validated; | ||
| 21 | + | ||
| 22 | +import java.time.LocalDateTime; | ||
| 23 | + | ||
| 24 | +/** | ||
| 25 | + * 设备上行 Service 实现类 | ||
| 26 | + * | ||
| 27 | + * @author 芋道源码 | ||
| 28 | + */ | ||
| 29 | +@Service | ||
| 30 | +@Validated | ||
| 31 | +@Slf4j | ||
| 32 | +public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { | ||
| 33 | + | ||
| 34 | + @Resource | ||
| 35 | + private IotDeviceService deviceService; | ||
| 36 | + | ||
| 37 | + @Resource | ||
| 38 | + private IotDeviceProducer deviceProducer; | ||
| 39 | + | ||
| 40 | + @Override | ||
| 41 | + public void updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) { | ||
| 42 | + log.info("[updateDeviceStatus][更新设备状态: {}]", updateReqDTO); | ||
| 43 | + // TODO 芋艿:插件状态 | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + @Override | ||
| 47 | + public void reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) { | ||
| 48 | + // 1.1 获得设备 | ||
| 49 | + log.info("[reportDevicePropertyData][上报设备属性数据: {}]", reportReqDTO); | ||
| 50 | + IotDeviceDO device = getDevice(reportReqDTO); | ||
| 51 | + if (device == null) { | ||
| 52 | + log.error("[reportDevicePropertyData][设备({}/{})不存在]", | ||
| 53 | + reportReqDTO.getProductKey(), reportReqDTO.getDeviceName()); | ||
| 54 | + return; | ||
| 55 | + } | ||
| 56 | + // 1.2 记录设备的最后时间 | ||
| 57 | + updateDeviceLastTime(device, reportReqDTO); | ||
| 58 | + | ||
| 59 | + // 2. 发送设备消息 | ||
| 60 | + IotDeviceMessage message = BeanUtils.toBean(reportReqDTO, IotDeviceMessage.class) | ||
| 61 | + .setType(IotDeviceMessageTypeEnum.PROPERTY.getType()) | ||
| 62 | + .setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_REPORT.getIdentifier()) | ||
| 63 | + .setData(reportReqDTO.getProperties()); | ||
| 64 | + sendDeviceMessage(message, device); | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + @Override | ||
| 68 | + public void reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) { | ||
| 69 | + log.info("[reportDeviceEventData][上报设备事件数据: {}]", reportReqDTO); | ||
| 70 | + | ||
| 71 | + // TODO 芋艿:待实现 | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + private IotDeviceDO getDevice(IotDeviceUpstreamAbstractReqDTO reqDTO) { | ||
| 75 | + return TenantUtils.executeIgnore(() -> // 需要忽略租户,因为请求时,未带租户编号 | ||
| 76 | + deviceService.getDeviceByProductKeyAndDeviceName(reqDTO.getProductKey(), reqDTO.getDeviceName())); | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + private void updateDeviceLastTime(IotDeviceDO deviceDO, IotDeviceUpstreamAbstractReqDTO reqDTO) { | ||
| 80 | + // TODO 芋艿:插件状态 | ||
| 81 | + // TODO 芋艿:操作时间 | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + private void sendDeviceMessage(IotDeviceMessage message, IotDeviceDO device) { | ||
| 85 | + // 1. 完善消息 | ||
| 86 | + message.setDeviceKey(device.getDeviceKey()); | ||
| 87 | + if (StrUtil.isEmpty(message.getRequestId())) { | ||
| 88 | + message.setRequestId(IdUtil.fastSimpleUUID()); | ||
| 89 | + } | ||
| 90 | + if (message.getReportTime() == null) { | ||
| 91 | + message.setReportTime(LocalDateTime.now()); | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + // 2. 发送消息 | ||
| 95 | + try { | ||
| 96 | + deviceProducer.sendDeviceMessage(message); | ||
| 97 | + log.info("[sendDeviceMessage][message({}) 发送消息成功]", message); | ||
| 98 | + } catch (Exception e) { | ||
| 99 | + log.error("[sendDeviceMessage][message({}) 发送消息失败]", message, e); | ||
| 100 | + } | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java
| @@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProduc | @@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProduc | ||
| 8 | import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; | 8 | import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; |
| 9 | import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper; | 9 | import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper; |
| 10 | import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; | 10 | import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; |
| 11 | -import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; | 11 | +import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; |
| 12 | import com.baomidou.dynamic.datasource.annotation.DSTransactional; | 12 | import com.baomidou.dynamic.datasource.annotation.DSTransactional; |
| 13 | import jakarta.annotation.Resource; | 13 | import jakarta.annotation.Resource; |
| 14 | import org.springframework.context.annotation.Lazy; | 14 | import org.springframework.context.annotation.Lazy; |
| @@ -35,7 +35,7 @@ public class IotProductServiceImpl implements IotProductService { | @@ -35,7 +35,7 @@ public class IotProductServiceImpl implements IotProductService { | ||
| 35 | 35 | ||
| 36 | @Resource | 36 | @Resource |
| 37 | @Lazy // 延迟加载,解决循环依赖 | 37 | @Lazy // 延迟加载,解决循环依赖 |
| 38 | - private IotDevicePropertyDataService devicePropertyDataService; | 38 | + private IotDevicePropertyService devicePropertyDataService; |
| 39 | 39 | ||
| 40 | @Override | 40 | @Override |
| 41 | public Long createProduct(IotProductSaveReqVO createReqVO) { | 41 | public Long createProduct(IotProductSaveReqVO createReqVO) { |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java deleted
| 1 | -package cn.iocoder.yudao.module.iot.service.tdengine; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | ||
| 4 | -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; | ||
| 5 | - | ||
| 6 | -/** | ||
| 7 | - * 物模型消息 Service | ||
| 8 | - */ | ||
| 9 | -public interface IotThingModelMessageService { | ||
| 10 | - | ||
| 11 | - /** | ||
| 12 | - * 保存物模型消息 | ||
| 13 | - * | ||
| 14 | - * @param device 设备 | ||
| 15 | - * @param thingModelMessage 物模型消息 | ||
| 16 | - */ | ||
| 17 | - void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage); | ||
| 18 | - | ||
| 19 | - | ||
| 20 | - | ||
| 21 | -} | ||
| 22 | \ No newline at end of file | 0 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java deleted
| 1 | -package cn.iocoder.yudao.module.iot.service.tdengine; | ||
| 2 | - | ||
| 3 | -import cn.hutool.core.date.DateUtil; | ||
| 4 | -import cn.hutool.core.util.StrUtil; | ||
| 5 | -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||
| 6 | -import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; | ||
| 7 | -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO; | ||
| 8 | -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | ||
| 9 | -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; | ||
| 10 | -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; | ||
| 11 | -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; | ||
| 12 | -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; | ||
| 13 | -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; | ||
| 14 | -import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; | ||
| 15 | -import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; | ||
| 16 | -import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper; | ||
| 17 | -import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; | ||
| 18 | -import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; | ||
| 19 | -import cn.iocoder.yudao.module.iot.enums.IotConstants; | ||
| 20 | -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; | ||
| 21 | -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; | ||
| 22 | -import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; | ||
| 23 | -import cn.iocoder.yudao.module.iot.service.product.IotProductService; | ||
| 24 | -import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; | ||
| 25 | -import jakarta.annotation.Resource; | ||
| 26 | -import lombok.extern.slf4j.Slf4j; | ||
| 27 | -import org.springframework.beans.factory.annotation.Value; | ||
| 28 | -import org.springframework.stereotype.Service; | ||
| 29 | - | ||
| 30 | -import java.util.*; | ||
| 31 | -import java.util.stream.Collectors; | ||
| 32 | - | ||
| 33 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | ||
| 34 | - | ||
| 35 | -/** | ||
| 36 | - * 物模型消息 Service 实现类 | ||
| 37 | - */ | ||
| 38 | -@Slf4j | ||
| 39 | -@Service | ||
| 40 | -public class IotThingModelMessageServiceImpl implements IotThingModelMessageService { | ||
| 41 | - | ||
| 42 | - private static final String TAG_NOTE = "TAG"; | ||
| 43 | - private static final String NOTE = "note"; | ||
| 44 | - private static final String TIME = "time"; | ||
| 45 | - private static final String DEVICE_KEY = "device_key"; | ||
| 46 | - private static final String DEVICE_NAME = "device_name"; | ||
| 47 | - private static final String PRODUCT_KEY = "product_key"; | ||
| 48 | - private static final String DEVICE_TYPE = "device_type"; | ||
| 49 | - | ||
| 50 | - @Value("${spring.datasource.dynamic.datasource.tdengine.url}") | ||
| 51 | - private String url; | ||
| 52 | - | ||
| 53 | - @Resource | ||
| 54 | - private IotThingModelService iotThingModelService; | ||
| 55 | - @Resource | ||
| 56 | - private IotDeviceService iotDeviceService; | ||
| 57 | - @Resource | ||
| 58 | - private IotProductService productService; | ||
| 59 | - | ||
| 60 | - @Resource | ||
| 61 | - private TdEngineDDLMapper tdEngineDDLMapper; | ||
| 62 | - @Resource | ||
| 63 | - private TdEngineDMLMapper tdEngineDMLMapper; | ||
| 64 | - | ||
| 65 | - @Resource | ||
| 66 | - private IotDevicePropertyDataMapper iotDevicePropertyDataMapper; | ||
| 67 | - | ||
| 68 | - @Resource | ||
| 69 | - private DeviceDataRedisDAO deviceDataRedisDAO; | ||
| 70 | - | ||
| 71 | - // TODO @haohao:这个方法,可以考虑加下 1. 2. 3. 更有层次感 | ||
| 72 | - @Override | ||
| 73 | - @TenantIgnore | ||
| 74 | - public void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage) { | ||
| 75 | - // 1. 判断设备状态,如果为未激活状态,创建数据表并更新设备状态 | ||
| 76 | - if (IotDeviceStatusEnum.INACTIVE.getStatus().equals(device.getStatus())) { | ||
| 77 | - // 1.1 创建设备表 | ||
| 78 | -// createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey()); | ||
| 79 | - iotDeviceService.updateDeviceStatus(new IotDeviceStatusUpdateReqVO() | ||
| 80 | - .setId(device.getId()).setStatus(IotDeviceStatusEnum.ONLINE.getStatus())); | ||
| 81 | - } | ||
| 82 | - | ||
| 83 | - // 2. 获取设备属性并进行物模型校验,过滤非物模型属性 | ||
| 84 | - Map<String, Object> params = thingModelMessage.dataToMap(); | ||
| 85 | - List<IotThingModelDO> thingModelList = getValidThingModelList(thingModelMessage.getProductKey()); | ||
| 86 | - if (thingModelList.isEmpty()) { | ||
| 87 | - return; | ||
| 88 | - } | ||
| 89 | - | ||
| 90 | - // 3. 过滤并收集有效的属性字段,缓存设备属性 | ||
| 91 | - List<TdFieldDO> schemaFieldValues = filterAndCollectValidFields(params, thingModelList, device, thingModelMessage.getTime()); | ||
| 92 | - if (schemaFieldValues.size() == 0) { // 没有字段,无需保存 | ||
| 93 | - return; | ||
| 94 | - } | ||
| 95 | - | ||
| 96 | - // 4. 构建并保存设备属性数据 | ||
| 97 | -// tdEngineDMLMapper.insertData(TdTableDO.builder() | ||
| 98 | -// .dataBaseName(getDatabaseName()) | ||
| 99 | -// .tableName(getDeviceTableName(device.getProductKey(), device.getDeviceName())) | ||
| 100 | -// .columns(schemaFieldValues) | ||
| 101 | -// .build()); | ||
| 102 | - // TODO:复用了旧逻辑,先过渡一下 | ||
| 103 | - iotDevicePropertyDataMapper.insertDevicePropertyData(TdTableDO.builder() | ||
| 104 | - .productKey(device.getProductKey()) | ||
| 105 | - .deviceKey(device.getDeviceKey()) | ||
| 106 | - .columns(schemaFieldValues) | ||
| 107 | - .build()); | ||
| 108 | - } | ||
| 109 | - | ||
| 110 | - private List<IotThingModelDO> getValidThingModelList(String productKey) { | ||
| 111 | - return filterList(iotThingModelService.getProductThingModelListByProductKey(productKey), | ||
| 112 | - thingModel -> IotThingModelTypeEnum.PROPERTY.getType().equals(thingModel.getType())); | ||
| 113 | - } | ||
| 114 | - | ||
| 115 | -// @Override | ||
| 116 | -// @TenantIgnore | ||
| 117 | -// public void createSuperTable(Long productId) { | ||
| 118 | -// // 1. 查询产品 | ||
| 119 | -// IotProductDO product = productService.getProduct(productId); | ||
| 120 | -// // 2. 创建日志超级表 | ||
| 121 | -// tdThingModelMessageMapper.createSuperTable(product.getProductKey()); | ||
| 122 | -// | ||
| 123 | -// // 2. 获取超级表的名称和数据库名称 | ||
| 124 | -// // TODO @alwayssuper:最好 databaseName、superTableName 的处理,放到 tdThinkModelMessageMapper 里。可以考虑,弄个 default 方法 | ||
| 125 | -//// String databaseName = IotTdDatabaseUtils.getDatabaseName(url); | ||
| 126 | -//// String superTableName = IotTdDatabaseUtils.getThingModelMessageSuperTableName(product.getProductKey()); | ||
| 127 | -//// | ||
| 128 | -//// // 解析物模型,获取字段列表 | ||
| 129 | -//// List<TdFieldDO> schemaFields = List.of( | ||
| 130 | -//// TdFieldDO.builder().fieldName("time").dataType("TIMESTAMP").build(), | ||
| 131 | -//// TdFieldDO.builder().fieldName("id").dataType("NCHAR").dataLength(64).build(), | ||
| 132 | -//// TdFieldDO.builder().fieldName("sys").dataType("NCHAR").dataLength(2048).build(), | ||
| 133 | -//// TdFieldDO.builder().fieldName("method").dataType("NCHAR").dataLength(256).build(), | ||
| 134 | -//// TdFieldDO.builder().fieldName("params").dataType("NCHAR").dataLength(2048).build() | ||
| 135 | -//// ); | ||
| 136 | -//// // 设置超级表的标签 | ||
| 137 | -//// List<TdFieldDO> tagsFields = List.of( | ||
| 138 | -//// TdFieldDO.builder().fieldName("device_key").dataType("NCHAR").dataLength(64).build() | ||
| 139 | -//// ); | ||
| 140 | -//// // 3. 创建超级表 | ||
| 141 | -//// tdEngineDDLMapper.createSuperTable(new TdTableDO(databaseName, superTableName, schemaFields, tagsFields)); | ||
| 142 | -// } | ||
| 143 | - | ||
| 144 | - private List<IotThingModelDO> getValidFunctionList(String productKey) { | ||
| 145 | - return filterList(iotThingModelService.getProductThingModelListByProductKey(productKey), | ||
| 146 | - thingModel -> IotThingModelTypeEnum.PROPERTY.getType().equals(thingModel.getType())); | ||
| 147 | - } | ||
| 148 | - | ||
| 149 | - private List<TdFieldDO> filterAndCollectValidFields(Map<String, Object> params, List<IotThingModelDO> thingModelList, IotDeviceDO device, Long time) { | ||
| 150 | - // 1. 获取属性标识符集合 | ||
| 151 | - Set<String> propertyIdentifiers = convertSet(thingModelList, IotThingModelDO::getIdentifier); | ||
| 152 | - | ||
| 153 | - // 2. 构建属性标识符和属性的映射 | ||
| 154 | - Map<String, IotThingModelDO> thingModelMap = convertMap(thingModelList, IotThingModelDO::getIdentifier); | ||
| 155 | - | ||
| 156 | - // 3. 过滤并收集有效的属性字段 | ||
| 157 | - List<TdFieldDO> schemaFieldValues = new ArrayList<>(); | ||
| 158 | - //TODO:新版本是使用ts字段 | ||
| 159 | -// schemaFieldValues.add(new TdFieldDO(TIME, time)); | ||
| 160 | - params.forEach((key, val) -> { | ||
| 161 | - if (propertyIdentifiers.contains(key)) { | ||
| 162 | - schemaFieldValues.add(new TdFieldDO(key.toLowerCase(), val)); | ||
| 163 | - // 缓存设备属性 | ||
| 164 | - // TODO @haohao:这个缓存的写入,可以使用的时候 cache 么?被动读 | ||
| 165 | - setDeviceDataCache(device, thingModelMap.get(key), val, time); | ||
| 166 | - } | ||
| 167 | - }); | ||
| 168 | - return schemaFieldValues; | ||
| 169 | - } | ||
| 170 | - | ||
| 171 | - /** | ||
| 172 | - * 缓存设备属性 | ||
| 173 | - * | ||
| 174 | - * @param device 设备信息 | ||
| 175 | - * @param iotThingModelDO 物模型属性 | ||
| 176 | - * @param val 属性值 | ||
| 177 | - * @param time 时间 | ||
| 178 | - */ | ||
| 179 | - private void setDeviceDataCache(IotDeviceDO device, IotThingModelDO iotThingModelDO, Object val, Long time) { | ||
| 180 | - IotDeviceDataDO deviceData = IotDeviceDataDO.builder() | ||
| 181 | - .productKey(device.getProductKey()) | ||
| 182 | - .deviceName(device.getDeviceName()) | ||
| 183 | - .identifier(iotThingModelDO.getIdentifier()) | ||
| 184 | - .value(val != null ? val.toString() : null) | ||
| 185 | - .updateTime(DateUtil.toLocalDateTime(new Date(time))) | ||
| 186 | - .deviceId(device.getId()) | ||
| 187 | - .thingModelId(iotThingModelDO.getId()) | ||
| 188 | - .name(iotThingModelDO.getName()) | ||
| 189 | - .dataType(iotThingModelDO.getProperty().getDataType()) | ||
| 190 | - .build(); | ||
| 191 | - deviceDataRedisDAO.set(deviceData); | ||
| 192 | - } | ||
| 193 | - | ||
| 194 | - /** | ||
| 195 | - * 创建设备数据表 | ||
| 196 | - * | ||
| 197 | - * @param deviceType 设备类型 | ||
| 198 | - * @param productKey 产品 Key | ||
| 199 | - * @param deviceName 设备名称 | ||
| 200 | - * @param deviceKey 设备 Key | ||
| 201 | - */ | ||
| 202 | - private void createDeviceTable(Integer deviceType, String productKey, String deviceName, String deviceKey) { | ||
| 203 | - // 1. 获取超级表名和数据库名 | ||
| 204 | - String superTableName = getProductPropertySTableName(deviceType, productKey); | ||
| 205 | - String dataBaseName = getDatabaseName(); | ||
| 206 | - | ||
| 207 | - // 2. 获取超级表的结构信息 | ||
| 208 | - List<Map<String, Object>> maps = tdEngineDDLMapper.describeSuperTable(new TdTableDO(dataBaseName, superTableName)); | ||
| 209 | - List<TdFieldDO> tagsFieldValues = new ArrayList<>(); | ||
| 210 | - if (maps != null) { | ||
| 211 | - // 2.1 过滤出 TAG 类型的字段 | ||
| 212 | - List<Map<String, Object>> taggedNotesList = CollectionUtils.filterList(maps, map -> TAG_NOTE.equals(map.get(NOTE))); | ||
| 213 | - | ||
| 214 | - // 2.2 解析字段信息 | ||
| 215 | - tagsFieldValues = FieldParser.parse(taggedNotesList.stream() | ||
| 216 | - .map(map -> List.of(map.get("field"), map.get("type"), map.get("length"))) | ||
| 217 | - .collect(Collectors.toList())); | ||
| 218 | - | ||
| 219 | - // 2.3 设置 TAG 字段的值 | ||
| 220 | - for (TdFieldDO tagsFieldValue : tagsFieldValues) { | ||
| 221 | - switch (tagsFieldValue.getFieldName()) { | ||
| 222 | - case PRODUCT_KEY -> tagsFieldValue.setFieldValue(productKey); | ||
| 223 | - case DEVICE_KEY -> tagsFieldValue.setFieldValue(deviceKey); | ||
| 224 | - case DEVICE_NAME -> tagsFieldValue.setFieldValue(deviceName); | ||
| 225 | - case DEVICE_TYPE -> tagsFieldValue.setFieldValue(deviceType); | ||
| 226 | - } | ||
| 227 | - } | ||
| 228 | - } | ||
| 229 | - | ||
| 230 | - // 3. 创建设备数据表 | ||
| 231 | - String tableName = getDeviceTableName(productKey, deviceName); | ||
| 232 | - tdEngineDDLMapper.createTable(TdTableDO.builder().build() | ||
| 233 | - .setDataBaseName(dataBaseName) | ||
| 234 | - .setSuperTableName(superTableName) | ||
| 235 | - .setTableName(tableName) | ||
| 236 | - .setTags(tagsFieldValues)); | ||
| 237 | - } | ||
| 238 | - | ||
| 239 | - | ||
| 240 | - | ||
| 241 | - /** | ||
| 242 | - * 获取数据库名称 | ||
| 243 | - * | ||
| 244 | - * @return 数据库名称 | ||
| 245 | - */ | ||
| 246 | - private String getDatabaseName() { | ||
| 247 | - return StrUtil.subAfter(url, "/", true); | ||
| 248 | - } | ||
| 249 | - | ||
| 250 | - /** | ||
| 251 | - * 获取产品属性表名 | ||
| 252 | - * | ||
| 253 | - * @param deviceType 设备类型 | ||
| 254 | - * @param productKey 产品 Key | ||
| 255 | - * @return 产品属性表名 | ||
| 256 | - */ | ||
| 257 | - private static String getProductPropertySTableName(Integer deviceType, String productKey) { | ||
| 258 | - // TODO @haohao:枚举下,会好点哈。 | ||
| 259 | - return switch (deviceType) { | ||
| 260 | - case 1 -> String.format(IotConstants.GATEWAY_SUB_STABLE_NAME_FORMAT, productKey).toLowerCase(); | ||
| 261 | - case 2 -> String.format(IotConstants.GATEWAY_STABLE_NAME_FORMAT, productKey).toLowerCase(); | ||
| 262 | - default -> String.format(IotConstants.DEVICE_STABLE_NAME_FORMAT, productKey).toLowerCase(); | ||
| 263 | - }; | ||
| 264 | - } | ||
| 265 | - | ||
| 266 | - /** | ||
| 267 | - * 获取设备表名 | ||
| 268 | - * | ||
| 269 | - * @param productKey 产品 Key | ||
| 270 | - * @param deviceName 设备名称 | ||
| 271 | - * @return 设备表名 | ||
| 272 | - */ | ||
| 273 | - private static String getDeviceTableName(String productKey, String deviceName) { | ||
| 274 | - return String.format(IotConstants.DEVICE_TABLE_NAME_FORMAT, productKey.toLowerCase(), deviceName.toLowerCase()); | ||
| 275 | - } | ||
| 276 | - | ||
| 277 | -} | ||
| 278 | \ No newline at end of file | 0 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml
| @@ -9,8 +9,9 @@ | @@ -9,8 +9,9 @@ | ||
| 9 | ts TIMESTAMP, | 9 | ts TIMESTAMP, |
| 10 | id NCHAR(50), | 10 | id NCHAR(50), |
| 11 | product_key NCHAR(50), | 11 | product_key NCHAR(50), |
| 12 | + device_name NCHAR(50), | ||
| 12 | type NCHAR(50), | 13 | type NCHAR(50), |
| 13 | - sub_type NCHAR(50), | 14 | + identifier NCHAR(255), |
| 14 | content NCHAR(1024), | 15 | content NCHAR(1024), |
| 15 | report_time TIMESTAMP | 16 | report_time TIMESTAMP |
| 16 | ) TAGS ( | 17 | ) TAGS ( |
| @@ -18,18 +19,23 @@ | @@ -18,18 +19,23 @@ | ||
| 18 | ) | 19 | ) |
| 19 | </update> | 20 | </update> |
| 20 | 21 | ||
| 22 | + <select id="showDeviceLogSTable" resultType="String"> | ||
| 23 | + SHOW STABLES LIKE 'device_log' | ||
| 24 | + </select> | ||
| 25 | + | ||
| 21 | <insert id="insert"> | 26 | <insert id="insert"> |
| 22 | - INSERT INTO device_log_${log.deviceKey} (ts, id, product_key, type, subType, content, report_time) | 27 | + INSERT INTO device_log_${deviceKey} (ts, id, product_key, device_name, type, identifier, content, report_time) |
| 23 | USING device_log | 28 | USING device_log |
| 24 | - TAGS ('${log.deviceKey}') | 29 | + TAGS ('${deviceKey}') |
| 25 | VALUES ( | 30 | VALUES ( |
| 26 | NOW, | 31 | NOW, |
| 27 | - #{log.id}, | ||
| 28 | - #{log.productKey}, | ||
| 29 | - #{log.type}, | ||
| 30 | - #{log.subType}, | ||
| 31 | - #{log.content}, | ||
| 32 | - #{log.reportTime} | 32 | + #{id}, |
| 33 | + #{productKey}, | ||
| 34 | + #{deviceName}, | ||
| 35 | + #{type}, | ||
| 36 | + #{identifier}, | ||
| 37 | + #{content}, | ||
| 38 | + #{reportTime} | ||
| 33 | ) | 39 | ) |
| 34 | </insert> | 40 | </insert> |
| 35 | 41 | ||
| @@ -51,6 +57,7 @@ | @@ -51,6 +57,7 @@ | ||
| 51 | LIMIT #{reqVO.pageSize} OFFSET #{reqVO.pageNo} | 57 | LIMIT #{reqVO.pageSize} OFFSET #{reqVO.pageNo} |
| 52 | </select> | 58 | </select> |
| 53 | 59 | ||
| 60 | + <!-- TODO 芋艿:看看能不能复用 mybatis-plus 的 selectCount 方法 --> | ||
| 54 | <select id="selectCount" resultType="Long"> | 61 | <select id="selectCount" resultType="Long"> |
| 55 | SELECT COUNT(*) | 62 | SELECT COUNT(*) |
| 56 | FROM device_log_${reqVO.deviceKey} | 63 | FROM device_log_${reqVO.deviceKey} |
| @@ -67,12 +74,4 @@ | @@ -67,12 +74,4 @@ | ||
| 67 | </where> | 74 | </where> |
| 68 | </select> | 75 | </select> |
| 69 | 76 | ||
| 70 | - <select id="checkDeviceLogSTableExists" resultType="Object"> | ||
| 71 | - SHOW STABLES LIKE 'device_log' | ||
| 72 | - </select> | ||
| 73 | - | ||
| 74 | - <select id="checkDeviceLogTableExists" resultType="Object"> | ||
| 75 | - SHOW TABLES LIKE 'device_log_${deviceKey}' | ||
| 76 | - </select> | ||
| 77 | - | ||
| 78 | </mapper> | 77 | </mapper> |
| 79 | \ No newline at end of file | 78 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/api/DeviceDataApiClient.java
| 1 | package cn.iocoder.yudao.module.iot.plugin.common.api; | 1 | package cn.iocoder.yudao.module.iot.plugin.common.api; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; | 4 | +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; |
| 5 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO; | 5 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO; |
| 6 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; | 6 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; |
| 7 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO; | 7 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO; |
| 8 | -import lombok.RequiredArgsConstructor; | ||
| 9 | import lombok.extern.slf4j.Slf4j; | 8 | import lombok.extern.slf4j.Slf4j; |
| 10 | import org.springframework.web.client.RestTemplate; | 9 | import org.springframework.web.client.RestTemplate; |
| 11 | 10 | ||
| 12 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 11 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 13 | 12 | ||
| 14 | -/** | ||
| 15 | - * 用于通过 {@link RestTemplate} 向远程 IoT 服务发送设备数据相关的请求, | ||
| 16 | - * 包括设备状态更新、事件数据上报、属性数据上报等操作。 | ||
| 17 | - */ | 13 | +// TODO @haohao:类注释,写一下,比较好 |
| 14 | +// TODO @haohao:类名要改下 | ||
| 18 | @Slf4j | 15 | @Slf4j |
| 19 | -@RequiredArgsConstructor | ||
| 20 | -public class DeviceDataApiClient implements DeviceDataApi { | 16 | +public class DeviceDataApiClient implements IotDeviceUpstreamApi { |
| 21 | 17 | ||
| 22 | - /** | ||
| 23 | - * 用于发送 HTTP 请求的工具 | ||
| 24 | - */ | ||
| 25 | - private final RestTemplate restTemplate; | 18 | + public static final String URL_PREFIX = "/rpc-api/iot/device/upstream"; |
| 26 | 19 | ||
| 27 | - /** | ||
| 28 | - * 远程 IoT 服务的基础 URL | ||
| 29 | - * 例如:http://127.0.0.1:8080 | ||
| 30 | - */ | 20 | + private final RestTemplate restTemplate; |
| 31 | private final String deviceDataUrl; | 21 | private final String deviceDataUrl; |
| 32 | 22 | ||
| 23 | + // 可以通过构造器把 RestTemplate 和 baseUrl 注入进来 | ||
| 24 | + // TODO @haohao:可以用 lombok 简化 | ||
| 25 | + public DeviceDataApiClient(RestTemplate restTemplate, String deviceDataUrl) { | ||
| 26 | + this.restTemplate = restTemplate; | ||
| 27 | + this.deviceDataUrl = deviceDataUrl; | ||
| 28 | + } | ||
| 29 | + | ||
| 33 | // TODO @haohao:返回结果,不用 CommonResult 哈。 | 30 | // TODO @haohao:返回结果,不用 CommonResult 哈。 |
| 34 | @Override | 31 | @Override |
| 35 | public CommonResult<Boolean> updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) { | 32 | public CommonResult<Boolean> updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) { |
| 36 | - String url = deviceDataUrl + "/rpc-api/iot/device-data/update-status"; | 33 | + String url = deviceDataUrl + URL_PREFIX + "/update-status"; |
| 37 | return doPost(url, updateReqDTO, "updateDeviceStatus"); | 34 | return doPost(url, updateReqDTO, "updateDeviceStatus"); |
| 38 | } | 35 | } |
| 39 | 36 | ||
| 40 | @Override | 37 | @Override |
| 41 | public CommonResult<Boolean> reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) { | 38 | public CommonResult<Boolean> reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) { |
| 42 | - String url = deviceDataUrl + "/rpc-api/iot/device-data/report-event"; | 39 | + String url = deviceDataUrl + URL_PREFIX + "/report-event"; |
| 43 | return doPost(url, reportReqDTO, "reportDeviceEventData"); | 40 | return doPost(url, reportReqDTO, "reportDeviceEventData"); |
| 44 | } | 41 | } |
| 45 | 42 | ||
| 46 | @Override | 43 | @Override |
| 47 | public CommonResult<Boolean> reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) { | 44 | public CommonResult<Boolean> reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) { |
| 48 | - String url = deviceDataUrl + "/rpc-api/iot/device-data/report-property"; | 45 | + String url = deviceDataUrl + URL_PREFIX + "/report-property"; |
| 49 | return doPost(url, reportReqDTO, "reportDevicePropertyData"); | 46 | return doPost(url, reportReqDTO, "reportDevicePropertyData"); |
| 50 | } | 47 | } |
| 51 | 48 | ||
| 52 | - | ||
| 53 | - /** | ||
| 54 | - * 发送 GET 请求 | ||
| 55 | - * | ||
| 56 | - * @param <T> 请求体类型 | ||
| 57 | - * @param url 请求 URL | ||
| 58 | - * @param requestBody 请求体 | ||
| 59 | - * @param actionName 操作名称 | ||
| 60 | - * @return 响应结果 | ||
| 61 | - */ | ||
| 62 | - private <T> CommonResult<Boolean> doGet(String url, T requestBody, String actionName) { | ||
| 63 | - log.info("[{}] Sending request to URL: {}", actionName, url); | ||
| 64 | - try { | ||
| 65 | - CommonResult<?> response = restTemplate.getForObject(url, CommonResult.class); | ||
| 66 | - if (response != null && response.isSuccess()) { | ||
| 67 | - return success(true); | ||
| 68 | - } else { | ||
| 69 | - log.warn("[{}] Request to URL: {} failed with response: {}", actionName, url, response); | ||
| 70 | - return CommonResult.error(500, "Request failed"); | ||
| 71 | - } | ||
| 72 | - } catch (Exception e) { | ||
| 73 | - log.error("[{}] Error sending request to URL: {}", actionName, url, e); | ||
| 74 | - return CommonResult.error(400, "Request error: " + e.getMessage()); | ||
| 75 | - } | ||
| 76 | - } | ||
| 77 | - | 49 | + // TODO @haohao:未来可能有 get 类型哈 |
| 78 | /** | 50 | /** |
| 79 | - * 发送 POST 请求 | ||
| 80 | - * | ||
| 81 | - * @param <T> 请求体类型 | ||
| 82 | - * @param url 请求 URL | ||
| 83 | - * @param requestBody 请求体 | ||
| 84 | - * @param actionName 操作名称 | ||
| 85 | - * @return 响应结果 | 51 | + * 将与远程服务交互的通用逻辑抽取成一个私有方法 |
| 86 | */ | 52 | */ |
| 87 | private <T> CommonResult<Boolean> doPost(String url, T requestBody, String actionName) { | 53 | private <T> CommonResult<Boolean> doPost(String url, T requestBody, String actionName) { |
| 88 | log.info("[{}] Sending request to URL: {}", actionName, url); | 54 | log.info("[{}] Sending request to URL: {}", actionName, url); |
| 89 | try { | 55 | try { |
| 90 | - CommonResult<?> response = restTemplate.postForObject(url, requestBody, CommonResult.class); | ||
| 91 | - if (response != null && response.isSuccess()) { | ||
| 92 | - return success(true); | ||
| 93 | - } else { | ||
| 94 | - log.warn("[{}] Request to URL: {} failed with response: {}", actionName, url, response); | ||
| 95 | - return CommonResult.error(500, "Request failed"); | ||
| 96 | - } | 56 | + // 这里指定返回类型为 CommonResult<?>,根据后台服务返回的实际结构做调整 |
| 57 | + restTemplate.postForObject(url, requestBody, CommonResult.class); | ||
| 58 | + // TODO @haohao:check 结果,是否成功 | ||
| 59 | + return success(true); | ||
| 97 | } catch (Exception e) { | 60 | } catch (Exception e) { |
| 98 | log.error("[{}] Error sending request to URL: {}", actionName, url, e); | 61 | log.error("[{}] Error sending request to URL: {}", actionName, url, e); |
| 99 | return CommonResult.error(400, "Request error: " + e.getMessage()); | 62 | return CommonResult.error(400, "Request error: " + e.getMessage()); |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/YudaoDeviceDataApiAutoConfiguration.java
| 1 | package cn.iocoder.yudao.module.iot.plugin.common.config; | 1 | package cn.iocoder.yudao.module.iot.plugin.common.config; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; | 3 | +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; |
| 4 | import cn.iocoder.yudao.module.iot.plugin.common.api.DeviceDataApiClient; | 4 | import cn.iocoder.yudao.module.iot.plugin.common.api.DeviceDataApiClient; |
| 5 | import org.springframework.beans.factory.annotation.Value; | 5 | import org.springframework.beans.factory.annotation.Value; |
| 6 | import org.springframework.boot.autoconfigure.AutoConfiguration; | 6 | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| @@ -43,7 +43,7 @@ public class YudaoDeviceDataApiAutoConfiguration { | @@ -43,7 +43,7 @@ public class YudaoDeviceDataApiAutoConfiguration { | ||
| 43 | * @return DeviceDataApi 实例 | 43 | * @return DeviceDataApi 实例 |
| 44 | */ | 44 | */ |
| 45 | @Bean | 45 | @Bean |
| 46 | - public DeviceDataApi deviceDataApi(RestTemplate restTemplate) { | 46 | + public IotDeviceUpstreamApi deviceDataApi(RestTemplate restTemplate) { |
| 47 | return new DeviceDataApiClient(restTemplate, deviceDataUrl); | 47 | return new DeviceDataApiClient(restTemplate, deviceDataUrl); |
| 48 | } | 48 | } |
| 49 | 49 |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java
| 1 | package cn.iocoder.yudao.module.iot.plugin; | 1 | package cn.iocoder.yudao.module.iot.plugin; |
| 2 | 2 | ||
| 3 | import cn.hutool.extra.spring.SpringUtil; | 3 | import cn.hutool.extra.spring.SpringUtil; |
| 4 | -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; | 4 | +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; |
| 5 | import lombok.extern.slf4j.Slf4j; | 5 | import lombok.extern.slf4j.Slf4j; |
| 6 | import org.pf4j.Plugin; | 6 | import org.pf4j.Plugin; |
| 7 | import org.pf4j.PluginWrapper; | 7 | import org.pf4j.PluginWrapper; |
| @@ -27,7 +27,7 @@ public class EmqxPlugin extends Plugin { | @@ -27,7 +27,7 @@ public class EmqxPlugin extends Plugin { | ||
| 27 | executorService = Executors.newSingleThreadExecutor(); | 27 | executorService = Executors.newSingleThreadExecutor(); |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | - DeviceDataApi deviceDataApi = SpringUtil.getBean(DeviceDataApi.class); | 30 | + IotDeviceUpstreamApi deviceDataApi = SpringUtil.getBean(IotDeviceUpstreamApi.class); |
| 31 | if (deviceDataApi == null) { | 31 | if (deviceDataApi == null) { |
| 32 | log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!"); | 32 | log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!"); |
| 33 | return; | 33 | return; |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java
| @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.plugin.http.config; | @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.plugin.http.config; | ||
| 2 | 2 | ||
| 3 | import cn.hutool.core.lang.Assert; | 3 | import cn.hutool.core.lang.Assert; |
| 4 | import cn.hutool.extra.spring.SpringUtil; | 4 | import cn.hutool.extra.spring.SpringUtil; |
| 5 | -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; | 5 | +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; |
| 6 | import lombok.extern.slf4j.Slf4j; | 6 | import lombok.extern.slf4j.Slf4j; |
| 7 | import org.pf4j.PluginWrapper; | 7 | import org.pf4j.PluginWrapper; |
| 8 | import org.pf4j.spring.SpringPlugin; | 8 | import org.pf4j.spring.SpringPlugin; |
| @@ -64,7 +64,7 @@ public class HttpVertxPlugin extends SpringPlugin { | @@ -64,7 +64,7 @@ public class HttpVertxPlugin extends SpringPlugin { | ||
| 64 | protected void prepareRefresh() { | 64 | protected void prepareRefresh() { |
| 65 | // 在刷新容器前注册主程序中的 Bean | 65 | // 在刷新容器前注册主程序中的 Bean |
| 66 | ConfigurableListableBeanFactory beanFactory = this.getBeanFactory(); | 66 | ConfigurableListableBeanFactory beanFactory = this.getBeanFactory(); |
| 67 | - DeviceDataApi deviceDataApi = SpringUtil.getBean(DeviceDataApi.class); | 67 | + IotDeviceUpstreamApi deviceDataApi = SpringUtil.getBean(IotDeviceUpstreamApi.class); |
| 68 | beanFactory.registerSingleton("deviceDataApi", deviceDataApi); | 68 | beanFactory.registerSingleton("deviceDataApi", deviceDataApi); |
| 69 | super.prepareRefresh(); | 69 | super.prepareRefresh(); |
| 70 | } | 70 | } |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java
| 1 | package cn.iocoder.yudao.module.iot.plugin.http.config; | 1 | package cn.iocoder.yudao.module.iot.plugin.http.config; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; | 3 | +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; |
| 4 | import cn.iocoder.yudao.module.iot.plugin.http.service.HttpVertxHandler; | 4 | import cn.iocoder.yudao.module.iot.plugin.http.service.HttpVertxHandler; |
| 5 | import io.vertx.core.Vertx; | 5 | import io.vertx.core.Vertx; |
| 6 | import io.vertx.ext.web.Router; | 6 | import io.vertx.ext.web.Router; |
| @@ -61,7 +61,7 @@ public class HttpVertxPluginConfiguration { | @@ -61,7 +61,7 @@ public class HttpVertxPluginConfiguration { | ||
| 61 | * @return HttpVertxHandler 实例 | 61 | * @return HttpVertxHandler 实例 |
| 62 | */ | 62 | */ |
| 63 | @Bean | 63 | @Bean |
| 64 | - public HttpVertxHandler httpVertxHandler(DeviceDataApi deviceDataApi) { | 64 | + public HttpVertxHandler httpVertxHandler(IotDeviceUpstreamApi deviceDataApi) { |
| 65 | return new HttpVertxHandler(deviceDataApi); | 65 | return new HttpVertxHandler(deviceDataApi); |
| 66 | } | 66 | } |
| 67 | 67 |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/service/HttpVertxHandler.java
| @@ -2,19 +2,21 @@ package cn.iocoder.yudao.module.iot.plugin.http.service; | @@ -2,19 +2,21 @@ package cn.iocoder.yudao.module.iot.plugin.http.service; | ||
| 2 | 2 | ||
| 3 | import cn.hutool.json.JSONObject; | 3 | import cn.hutool.json.JSONObject; |
| 4 | import cn.hutool.json.JSONUtil; | 4 | import cn.hutool.json.JSONUtil; |
| 5 | -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; | 5 | +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; |
| 6 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; | 6 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; |
| 7 | import io.vertx.core.Handler; | 7 | import io.vertx.core.Handler; |
| 8 | import io.vertx.ext.web.RequestBody; | 8 | import io.vertx.ext.web.RequestBody; |
| 9 | import io.vertx.ext.web.RoutingContext; | 9 | import io.vertx.ext.web.RoutingContext; |
| 10 | import lombok.extern.slf4j.Slf4j; | 10 | import lombok.extern.slf4j.Slf4j; |
| 11 | 11 | ||
| 12 | +import java.util.Map; | ||
| 13 | + | ||
| 12 | @Slf4j | 14 | @Slf4j |
| 13 | public class HttpVertxHandler implements Handler<RoutingContext> { | 15 | public class HttpVertxHandler implements Handler<RoutingContext> { |
| 14 | 16 | ||
| 15 | - private final DeviceDataApi deviceDataApi; | 17 | + private final IotDeviceUpstreamApi deviceDataApi; |
| 16 | 18 | ||
| 17 | - public HttpVertxHandler(DeviceDataApi deviceDataApi) { | 19 | + public HttpVertxHandler(IotDeviceUpstreamApi deviceDataApi) { |
| 18 | this.deviceDataApi = deviceDataApi; | 20 | this.deviceDataApi = deviceDataApi; |
| 19 | } | 21 | } |
| 20 | 22 | ||
| @@ -23,6 +25,7 @@ public class HttpVertxHandler implements Handler<RoutingContext> { | @@ -23,6 +25,7 @@ public class HttpVertxHandler implements Handler<RoutingContext> { | ||
| 23 | String productKey = ctx.pathParam("productKey"); | 25 | String productKey = ctx.pathParam("productKey"); |
| 24 | String deviceName = ctx.pathParam("deviceName"); | 26 | String deviceName = ctx.pathParam("deviceName"); |
| 25 | 27 | ||
| 28 | + // TODO @haohao:requestBody.asJsonObject() 貌似天然就是 json 对象哈? | ||
| 26 | RequestBody requestBody = ctx.body(); | 29 | RequestBody requestBody = ctx.body(); |
| 27 | JSONObject jsonData; | 30 | JSONObject jsonData; |
| 28 | try { | 31 | try { |
| @@ -43,7 +46,7 @@ public class HttpVertxHandler implements Handler<RoutingContext> { | @@ -43,7 +46,7 @@ public class HttpVertxHandler implements Handler<RoutingContext> { | ||
| 43 | IotDevicePropertyReportReqDTO reportReqDTO = IotDevicePropertyReportReqDTO.builder() | 46 | IotDevicePropertyReportReqDTO reportReqDTO = IotDevicePropertyReportReqDTO.builder() |
| 44 | .productKey(productKey) | 47 | .productKey(productKey) |
| 45 | .deviceName(deviceName) | 48 | .deviceName(deviceName) |
| 46 | - .params(jsonData) | 49 | + .properties((Map<String, Object>) requestBody.asJsonObject().getMap().get("properties")) |
| 47 | .build(); | 50 | .build(); |
| 48 | 51 | ||
| 49 | deviceDataApi.reportDevicePropertyData(reportReqDTO); | 52 | deviceDataApi.reportDevicePropertyData(reportReqDTO); |