Commit dfa03d24fd274ad5dce83c969b86129367fa0aab

Authored by YunaiV
1 parent 8c904486

【功能优化】Bpm:完善设备属性的历史值

Showing 10 changed files with 52 additions and 196 deletions
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDevicePropertyController.java
1 1 package cn.iocoder.yudao.module.iot.controller.admin.device;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.date.LocalDateTimeUtil;
4 5 import cn.hutool.core.lang.Assert;
5 6 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
6 7 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 8 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
8   -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceDataPageReqVO;
9   -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceDataRespVO;
10   -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotTimeDataRespVO;
  9 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyPageReqVO;
  10 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyRespVO;
11 11 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
12 12 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO;
13 13 import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
... ... @@ -42,9 +42,10 @@ public class IotDevicePropertyController {
42 42 @Resource
43 43 private IotDeviceService deviceService;
44 44  
  45 + // TODO @芋艿:权限
45 46 @GetMapping("/latest")
46 47 @Operation(summary = "获取设备属性最新属性")
47   - public CommonResult<List<IotDeviceDataRespVO>> getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO pageReqVO) {
  48 + public CommonResult<List<IotDevicePropertyRespVO>> getLatestDeviceProperties(@Valid IotDevicePropertyPageReqVO pageReqVO) {
48 49 Map<String, IotDevicePropertyDO> properties = devicePropertyService.getLatestDeviceProperties(pageReqVO);
49 50  
50 51 // 拼接数据
... ... @@ -58,18 +59,20 @@ public class IotDevicePropertyController {
58 59 return null;
59 60 }
60 61 IotDevicePropertyDO property = entry.getValue();
61   - return BeanUtils.toBean(thingModel, IotDeviceDataRespVO.class)
  62 + return BeanUtils.toBean(thingModel, IotDevicePropertyRespVO.class)
62 63 .setDataType(thingModel.getProperty().getDataType())
63   - .setValue(property.getValue()).setUpdateTime(property.getUpdateTime());
  64 + .setValue(property.getValue())
  65 + .setUpdateTime(LocalDateTimeUtil.toEpochMilli(property.getUpdateTime()));
64 66 }));
65 67 }
66 68  
67   - // TODO @浩浩:这里的 /history-page 包括方法名。
68   - @GetMapping("/history")
  69 + // TODO @芋艿:权限
  70 + @GetMapping("/history-page")
69 71 @Operation(summary = "获取设备属性历史数据")
70   - public CommonResult<PageResult<IotTimeDataRespVO>> getHistoryDeviceProperties(@Valid IotDeviceDataPageReqVO pageReqVO) {
71   - PageResult<Map<String, Object>> list = devicePropertyService.getHistoryDeviceProperties(pageReqVO);
72   - return success(BeanUtils.toBean(list, IotTimeDataRespVO.class));
  72 + public CommonResult<PageResult<IotDevicePropertyRespVO>> getHistoryDevicePropertyPage(
  73 + @Valid IotDevicePropertyPageReqVO pageReqVO) {
  74 + Assert.notEmpty(pageReqVO.getIdentifier(), "标识符不能为空");
  75 + return success(devicePropertyService.getHistoryDevicePropertyPage(pageReqVO));
73 76 }
74 77  
75 78 }
76 79 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDeviceDataPageReqVO.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyPageReqVO.java
... ... @@ -5,14 +5,17 @@ import io.swagger.v3.oas.annotations.media.Schema;
5 5 import jakarta.validation.constraints.NotNull;
6 6 import lombok.Data;
7 7  
8   -@Schema(description = "管理后台 - IoT 设备数据 Request VO")
  8 +@Schema(description = "管理后台 - IoT 设备属性 Request VO")
9 9 @Data
10   -public class IotDeviceDataPageReqVO extends PageParam {
  10 +public class IotDevicePropertyPageReqVO extends PageParam {
11 11  
12 12 @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
13 13 @NotNull(message = "设备编号不能为空")
14 14 private Long deviceId;
15 15  
  16 + @Schema(description = "设备 Key", hidden = true)
  17 + private String deviceKey; // 非前端传递,后端自己查询设置
  18 +
16 19 @Schema(description = "属性标识符", requiredMode = Schema.RequiredMode.REQUIRED)
17 20 private String identifier;
18 21  
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDeviceDataRespVO.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyRespVO.java
... ... @@ -3,11 +3,9 @@ package cn.iocoder.yudao.module.iot.controller.admin.device.vo.data;
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.Data;
5 5  
6   -import java.time.LocalDateTime;
7   -
8 6 @Schema(description = "管理后台 - IoT 设备属性 Response VO")
9 7 @Data
10   -public class IotDeviceDataRespVO {
  8 +public class IotDevicePropertyRespVO {
11 9  
12 10 @Schema(description = "属性标识符", requiredMode = Schema.RequiredMode.REQUIRED)
13 11 private String identifier;
... ... @@ -16,13 +14,10 @@ public class IotDeviceDataRespVO {
16 14 private Object value;
17 15  
18 16 @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
19   - private LocalDateTime updateTime;
  17 + private Long updateTime;
20 18  
21 19 // ========== 基于 ThingModel 查询 ==========
22 20  
23   -// @Schema(description = "物模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21816")
24   -// private Long thingModelId;
25   -
26 21 @Schema(description = "属性名称", requiredMode = Schema.RequiredMode.REQUIRED)
27 22 private String name;
28 23  
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotTimeDataRespVO.java deleted
1   -package cn.iocoder.yudao.module.iot.controller.admin.device.vo.data;
2   -
3   -import lombok.AllArgsConstructor;
4   -import lombok.Data;
5   -import lombok.NoArgsConstructor;
6   -
7   -
8   -@Data
9   -@NoArgsConstructor
10   -@AllArgsConstructor
11   -public class IotTimeDataRespVO {
12   -
13   - /**
14   - * 时间
15   - */
16   - private long time;
17   -
18   - /**
19   - * 数据值
20   - */
21   - private Object data;
22   -
23   -}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectVisualDO.java deleted
1   -package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine;
2   -
3   -import lombok.Data;
4   -
5   -import java.util.Map;
6   -
7   -// TODO @haohao:类似 SelectDO 的想法,只是它是返回。ps:貌似可以在 tdengine 里面,创建一个 query 包,放这种比较特殊的查询和结果对象。dataobject 更多还是实际存储的结构化的 do
8   -@Data
9   -@Deprecated
10   -public class SelectVisualDO {
11   -
12   - /**
13   - * 数据库名称
14   - */
15   - private String dataBaseName;
16   -
17   - /**
18   - * 表名
19   - */
20   - private String tableName;
21   -
22   -
23   - private String deviceKey;
24   -
25   - /**
26   - * 属性
27   - */
28   - private String fieldName;
29   -
30   - /**
31   - * 查询类型,0历史数据,1实时数据,2聚合数据
32   - */
33   - private int type;
34   -
35   - /**
36   - * 查询的数据量
37   - */
38   - private int num;
39   -
40   - /**
41   - * 聚合函数
42   - */
43   - private String aggregate;
44   -
45   - /**
46   - * 统计间隔数字+s/m/h/d
47   - * 比如1s,1m,1h,1d代表1秒,1分钟,1小时,1天
48   - */
49   - private String interval;
50   -
51   - /**
52   - * 开始时间
53   - */
54   - private Long startTime;
55   -
56   - /**
57   - * 结束时间
58   - */
59   - private Long endTime;
60   -
61   - /**
62   - * 请求参数
63   - */
64   - private Map<String, Object> params;
65   -
66   - private String sql;
67   -
68   - private String deviceId;
69   -
70   - private Long lastTime;
71   -}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogMapper.java
... ... @@ -44,14 +44,6 @@ public interface IotDeviceLogMapper {
44 44 * @return 设备日志列表
45 45 */
46 46 IPage<IotDeviceLogDO> selectPage(IPage<IotDeviceLogDO> page,
47   - @Param("reqVO") IotDeviceLogPageReqVO reqVO);
48   -
49   - /**
50   - * 获得设备日志总数
51   - *
52   - * @param reqVO 查询条件
53   - * @return 日志总数
54   - */
55   - Long selectCount(@Param("reqVO") IotDeviceLogPageReqVO reqVO);
  47 + @Param("reqVO") IotDeviceLogPageReqVO reqVO);
56 48  
57 49 }
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java
... ... @@ -3,12 +3,13 @@ package cn.iocoder.yudao.module.iot.dal.tdengine;
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.util.ObjectUtil;
5 5 import cn.hutool.core.util.StrUtil;
6   -import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
  6 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyPageReqVO;
  7 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyRespVO;
7 8 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
8   -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO;
9 9 import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField;
10 10 import cn.iocoder.yudao.module.iot.framework.tdengine.core.annotation.TDengineDS;
11 11 import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
  12 +import com.baomidou.mybatisplus.core.metadata.IPage;
12 13 import org.apache.ibatis.annotations.Mapper;
13 14 import org.apache.ibatis.annotations.Param;
14 15  
... ... @@ -83,23 +84,7 @@ public interface IotDevicePropertyMapper {
83 84 @Param("properties") Map<String, Object> properties,
84 85 @Param("reportTime") Long reportTime);
85 86  
86   - // TODO @芋艿:待实现
87   - /**
88   - * 获取历史数据列表
89   - *
90   - * @param selectVisualDO 查询条件
91   - * @return 历史数据列表
92   - */
93   - @TenantIgnore
94   - List<Map<String, Object>> selectHistoryDataList(SelectVisualDO selectVisualDO);
95   -
96   - /**
97   - * 获取历史数据条数
98   - *
99   - * @param selectVisualDO 查询条件
100   - * @return 数据条数
101   - */
102   - @TenantIgnore
103   - Long selectHistoryCount(SelectVisualDO selectVisualDO);
  87 + IPage<IotDevicePropertyRespVO> selectPageByHistory(IPage<?> page,
  88 + @Param("reqVO") IotDevicePropertyPageReqVO reqVO);
104 89  
105 90 }
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java
1 1 package cn.iocoder.yudao.module.iot.service.device.data;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4   -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceDataPageReqVO;
  4 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyPageReqVO;
  5 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyRespVO;
5 6 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO;
6 7 import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
7 8 import jakarta.validation.Valid;
... ... @@ -35,14 +36,14 @@ public interface IotDevicePropertyService {
35 36 * @param deviceId 设备编号
36 37 * @return 设备属性最新数据
37 38 */
38   - Map<String, IotDevicePropertyDO> getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceId);
  39 + Map<String, IotDevicePropertyDO> getLatestDeviceProperties(@Valid IotDevicePropertyPageReqVO deviceId);
39 40  
40 41 /**
41 42 * 获得设备属性历史数据
42 43 *
43   - * @param deviceDataReqVO 设备属性历史数据 Request VO
  44 + * @param pageReqVO 分页请求
44 45 * @return 设备属性历史数据
45 46 */
46   - PageResult<Map<String, Object>> getHistoryDeviceProperties(@Valid IotDeviceDataPageReqVO deviceDataReqVO);
  47 + PageResult<IotDevicePropertyRespVO> getHistoryDevicePropertyPage(@Valid IotDevicePropertyPageReqVO pageReqVO);
47 48  
48 49 }
49 50 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java
... ... @@ -6,7 +6,8 @@ import cn.hutool.core.map.MapUtil;
6 6 import cn.hutool.core.util.StrUtil;
7 7 import cn.iocoder.yudao.framework.common.pojo.PageResult;
8 8 import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
9   -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceDataPageReqVO;
  9 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyPageReqVO;
  10 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyRespVO;
10 11 import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDateOrTextDataSpecs;
11 12 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
12 13 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO;
... ... @@ -21,6 +22,8 @@ import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
21 22 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
22 23 import cn.iocoder.yudao.module.iot.service.product.IotProductService;
23 24 import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService;
  25 +import com.baomidou.mybatisplus.core.metadata.IPage;
  26 +import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
24 27 import jakarta.annotation.Resource;
25 28 import jakarta.validation.Valid;
26 29 import lombok.extern.slf4j.Slf4j;
... ... @@ -150,8 +153,9 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService {
150 153 entry -> IotDevicePropertyDO.builder().value(entry.getValue()).updateTime(message.getReportTime()).build()));
151 154 }
152 155  
  156 + // TODO @芋艿:需要在优化下,根据 name 之类的过滤
153 157 @Override
154   - public Map<String, IotDevicePropertyDO> getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO pageReqVO) {
  158 + public Map<String, IotDevicePropertyDO> getLatestDeviceProperties(@Valid IotDevicePropertyPageReqVO pageReqVO) {
155 159 // 获取设备信息
156 160 IotDeviceDO device = deviceService.validateDeviceExists(pageReqVO.getDeviceId());
157 161  
... ... @@ -160,34 +164,15 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService {
160 164 }
161 165  
162 166 @Override
163   - public PageResult<Map<String, Object>> getHistoryDeviceProperties(IotDeviceDataPageReqVO deviceDataReqVO) {
164   -// PageResult<Map<String, Object>> pageResult = new PageResult<>();
165   -// // 1. 获取设备信息
166   -// IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId());
167   -// // 2. 获取设备属性历史数据
168   -// SelectVisualDO selectVisualDO = new SelectVisualDO();
169   -// selectVisualDO.setDataBaseName(getDatabaseName());
170   -// selectVisualDO.setTableName(getDeviceTableName(device.getProductKey(), device.getDeviceName()));
171   -// selectVisualDO.setDeviceKey(device.getDeviceKey());
172   -// selectVisualDO.setFieldName(deviceDataReqVO.getIdentifier());
173   -// selectVisualDO.setStartTime(DateUtil.date(deviceDataReqVO.getTimes()[0].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime());
174   -// selectVisualDO.setEndTime(DateUtil.date(deviceDataReqVO.getTimes()[1].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime());
175   -// Map<String, Object> params = new HashMap<>();
176   -// params.put("rows", deviceDataReqVO.getPageSize());
177   -// params.put("page", (deviceDataReqVO.getPageNo() - 1) * deviceDataReqVO.getPageSize());
178   -// selectVisualDO.setParams(params);
179   -// pageResult.setList(devicePropertyDataMapper.selectHistoryDataList(selectVisualDO));
180   -// pageResult.setTotal(devicePropertyDataMapper.selectHistoryCount(selectVisualDO));
181   -// return pageResult;
182   - return null; // TODO 芋艿:晚点实现
183   - }
  167 + public PageResult<IotDevicePropertyRespVO> getHistoryDevicePropertyPage(IotDevicePropertyPageReqVO pageReqVO) {
  168 + // 获取设备信息
  169 + IotDeviceDO device = deviceService.validateDeviceExists(pageReqVO.getDeviceId());
  170 + pageReqVO.setDeviceKey(device.getDeviceKey());
184 171  
185   -// private String getDatabaseName() {
186   -// return StrUtil.subAfter(url, "/", true);
187   -// }
188   -//
189   -// private static String getDeviceTableName(String productKey, String deviceName) {
190   -// return String.format(IotConstants.DEVICE_TABLE_NAME_FORMAT, productKey, deviceName);
191   -// }
  172 + // TODO @芋艿:增加一个表不存在的 try catch
  173 + IPage<IotDevicePropertyRespVO> page = devicePropertyMapper.selectPageByHistory(
  174 + new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO);
  175 + return new PageResult<>(page.getRecords(), page.getTotal());
  176 + }
192 177  
193 178 }
194 179 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyMapper.xml
... ... @@ -45,7 +45,6 @@
45 45 DROP COLUMN ${field.field}
46 46 </update>
47 47  
48   - <!-- TODO 芋艿,report_time 需要增加下 -->
49 48 <insert id="insert">
50 49 INSERT INTO device_property_${device.deviceKey}
51 50 USING product_property_${device.productKey}
... ... @@ -63,29 +62,16 @@
63 62 )
64 63 </insert>
65 64  
66   - <!-- 描述超级表结构 -->
67 65 <select id="describeSuperTable" resultType="java.util.Map">
68 66 DESCRIBE product_property_${productKey}
69 67 </select>
70 68  
71   - <!-- 获取历史数据 -->
72   - <select id="selectHistoryDataList" resultType="java.util.Map"
73   - parameterType="cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO">
74   - SELECT ${fieldName} AS data, ts AS time
75   - FROM device_property_${deviceKey}
76   - WHERE ts BETWEEN #{startTime} AND #{endTime}
77   - AND ${fieldName} IS NOT NULL
  69 + <!-- TODO 芋艿:缺少时间范围 AND ts BETWEEN #{reqVO.startTime} AND #{reqVO.endTime} -->
  70 + <select id="selectPageByHistory" resultType="cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyRespVO">
  71 + SELECT ${reqVO.identifier} AS `value`, report_time AS update_time
  72 + FROM device_property_${reqVO.deviceKey}
  73 + WHERE ${reqVO.identifier} IS NOT NULL
78 74 ORDER BY ts DESC
79   - LIMIT #{params.rows} OFFSET #{params.page}
80   - </select>
81   -
82   - <!-- 统计历史数据总数 -->
83   - <select id="selectHistoryCount" resultType="java.lang.Long"
84   - parameterType="cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO">
85   - SELECT COUNT(*)
86   - FROM device_property_${deviceKey}
87   - WHERE ts BETWEEN #{startTime} AND #{endTime}
88   - AND ${fieldName} IS NOT NULL
89 75 </select>
90 76  
91 77 </mapper>
92 78 \ No newline at end of file
... ...