From d7b8cf547f4d96b49c3371fbbf4535a1c4dfab3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Tue, 5 Nov 2024 23:26:34 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E6=96=B0=E5=A2=9E=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E3=80=91=20=E8=AE=BE=E5=A4=87=E5=8E=86=E5=8F=B2=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/domain/visual/SelectVisualDto.java | 29 +++++++------ .../admin/device/IotDeviceDataController.java | 10 +++++ .../vo/deviceData/IotDeviceDataReqVO.java | 12 +++++- .../vo/deviceData/IotTimeDataRespVO.java} | 8 ++-- .../iot/dal/tdengine/TdEngineMapper.java | 7 ++- .../service/device/IotDeviceDataService.java | 10 +++++ .../device/IotDeviceDataServiceImpl.java | 43 +++++++++++++++++++ .../mapper/tdengine/TdEngineMapper.xml | 19 +++++--- 8 files changed, 112 insertions(+), 26 deletions(-) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/{dal/dataobject/tdengine/TimeData.java => controller/admin/device/vo/deviceData/IotTimeDataRespVO.java} (67%) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/visual/SelectVisualDto.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/visual/SelectVisualDto.java index 1444da9727..071c763034 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/visual/SelectVisualDto.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/visual/SelectVisualDto.java @@ -4,24 +4,24 @@ import lombok.Data; import java.util.Map; -/** - * @ClassDescription: 查询可视化所需入参对象 - * @ClassName: SelectDto - * @Author: andyz - * @Date: 2022-07-29 14:12:26 - * @Version 1.0 - */ @Data public class SelectVisualDto { -// @NotBlank(message = "invalid operation: tableName can not be empty") + /** + * 数据库名称 + */ private String dataBaseName; -// @NotBlank(message = "invalid operation: tableName can not be empty") + /** + * 表名 + */ private String tableName; -// @NotBlank(message = "invalid operation: fieldName can not be empty") //属性 + /** + * 属性 + */ private String fieldName; + /** * 查询类型,0历史数据,1实时数据,2聚合数据 */ @@ -39,10 +39,15 @@ public class SelectVisualDto { * 比如1s,1m,1h,1d代表1秒,1分钟,1小时,1天 */ private String interval; - // @NotNull(message = "invalid operation: startTime can not be null") + + /** + * 开始时间 + */ private Long startTime; - // @NotNull(message = "invalid operation: endTime can not be null") + /** + * 结束时间 + */ private Long endTime; /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java index 93b368bd8d..e710d0ea8f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java @@ -1,10 +1,12 @@ package cn.iocoder.yudao.module.iot.controller.admin.device; import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotTimeDataRespVO; import cn.iocoder.yudao.module.iot.service.device.IotDeviceDataService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -16,6 +18,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; +import java.util.Map; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -35,4 +38,11 @@ public class IotDeviceDataController { return success(BeanUtils.toBean(list, IotDeviceDataRespVO.class)); } + @GetMapping("/history-data") + @Operation(summary = "获取设备属性历史数据") + public CommonResult> getDevicePropertiesHistoryData(@Valid IotDeviceDataReqVO deviceDataReqVO) { + PageResult> list = deviceDataService.getDevicePropertiesHistoryData(deviceDataReqVO); + return success(BeanUtils.toBean(list, IotTimeDataRespVO.class)); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataReqVO.java index b8a95f607e..5f87a1cb82 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataReqVO.java @@ -1,13 +1,18 @@ package cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData; +import cn.iocoder.yudao.framework.common.pojo.PageParam; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Size; import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDateTime; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + @Schema(description = "管理后台 - IoT 设备数据 Request VO") @Data -public class IotDeviceDataReqVO { +public class IotDeviceDataReqVO extends PageParam { @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") private Long deviceId; @@ -18,4 +23,9 @@ public class IotDeviceDataReqVO { @Schema(description = "属性名称", requiredMode = Schema.RequiredMode.REQUIRED) private String name; + @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Size(min = 2, max = 2, message = "请选择时间范围") + private LocalDateTime[] times; + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TimeData.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotTimeDataRespVO.java similarity index 67% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TimeData.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotTimeDataRespVO.java index f7e251ea8a..1bf085c544 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TimeData.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotTimeDataRespVO.java @@ -1,16 +1,14 @@ -package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -/** - * 统计的时间数据 - */ + @Data @NoArgsConstructor @AllArgsConstructor -public class TimeData { +public class IotTimeDataRespVO { /** * 时间 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java index 94db527c28..c126946f1d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java @@ -88,6 +88,7 @@ public interface TdEngineMapper { /** * 创建表 - 创建超级表的子表 + * * @param tableDO 表信息 */ @InterceptorIgnore(tenantLine = "true") @@ -114,6 +115,7 @@ public interface TdEngineMapper { Map getLastData(SelectDto selectDto); + @InterceptorIgnore(tenantLine = "true") List> getHistoryData(SelectVisualDto selectVisualDto); List> getRealtimeData(SelectVisualDto selectVisualDto); @@ -122,5 +124,6 @@ public interface TdEngineMapper { List> getLastDataByTags(TagsSelectDao tagsSelectDao); - -} + @InterceptorIgnore(tenantLine = "true") + Long getHistoryCount(SelectVisualDto selectVisualDto); +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java index f67f426855..96181fd263 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java @@ -1,10 +1,12 @@ package cn.iocoder.yudao.module.iot.service.device; +import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import jakarta.validation.Valid; import java.util.List; +import java.util.Map; /** * IoT 设备数据 Service 接口 @@ -30,4 +32,12 @@ public interface IotDeviceDataService { * @return 设备属性最新数据 */ List getDevicePropertiesLatestData(@Valid IotDeviceDataReqVO deviceId); + + /** + * 获得设备属性历史数据 + * + * @param deviceDataReqVO 设备属性历史数据 Request VO + * @return 设备属性历史数据 + */ + PageResult> getDevicePropertiesHistoryData(@Valid IotDeviceDataReqVO deviceDataReqVO); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java index 86ac630c6f..1b44bd5d0a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java @@ -1,27 +1,38 @@ package cn.iocoder.yudao.module.iot.service.device; +import cn.hutool.core.date.DateUtil; import cn.hutool.json.JSONObject; +import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; +import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineMapper; +import cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto; import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService; import cn.iocoder.yudao.module.iot.service.thinkmodelfunction.IotThinkModelFunctionService; import jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import java.time.ZoneId; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; @Slf4j @Service public class IotDeviceDataServiceImpl implements IotDeviceDataService { + @Value("${spring.datasource.dynamic.datasource.tdengine.url}") + private String url; + @Resource private IotDeviceService deviceService; @Resource @@ -32,6 +43,9 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { @Resource private DeviceDataRedisDAO deviceDataRedisDAO; + @Resource + private TdEngineMapper tdEngineMapper; + @Override public void saveDeviceData(String productKey, String deviceName, String message) { // 1. 根据产品 key 和设备名称,获得设备信息 @@ -91,4 +105,33 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { }); return list; } + + @Override + public PageResult> getDevicePropertiesHistoryData(IotDeviceDataReqVO deviceDataReqVO) { + PageResult> pageResult = new PageResult<>(); + // 1. 获取设备信息 + IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId()); + // 2. 获取设备属性历史数据 + SelectVisualDto selectVisualDto = new SelectVisualDto(); + selectVisualDto.setDataBaseName(getDatabaseName()); + selectVisualDto.setTableName(getDeviceTableName(device.getProductKey(), device.getDeviceName())); + selectVisualDto.setFieldName(deviceDataReqVO.getIdentifier()); + selectVisualDto.setStartTime(DateUtil.date(deviceDataReqVO.getTimes()[0].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime()); + selectVisualDto.setEndTime(DateUtil.date(deviceDataReqVO.getTimes()[1].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime()); + Map params = new HashMap<>(); + params.put("rows", deviceDataReqVO.getPageSize()); + params.put("page", (deviceDataReqVO.getPageNo() - 1) * deviceDataReqVO.getPageSize()); + selectVisualDto.setParams(params); + pageResult.setList(tdEngineMapper.getHistoryData(selectVisualDto)); + pageResult.setTotal(tdEngineMapper.getHistoryCount(selectVisualDto)); + return pageResult; + } + + private String getDatabaseName() { + return url.substring(url.lastIndexOf("/") + 1); + } + + private static String getDeviceTableName(String productKey, String deviceName) { + return String.format("device_%s_%s", productKey.toLowerCase(), deviceName.toLowerCase()); + } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml index 9d5cf2a43e..4e127e44b1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml @@ -292,17 +292,18 @@ +