Commit f5c2ee2ae5aa1840d130560ada903ae6b361d7b5

Authored by YunaiV
1 parent e9c5464a

feat:【IoT 物联网】设备消息查询时,增加 pair 查询

Showing 16 changed files with 214 additions and 25 deletions
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceMessageController.http
@@ -88,4 +88,14 @@ Authorization: Bearer {{token}} @@ -88,4 +88,14 @@ Authorization: Bearer {{token}}
88 "fileUrl": "http://example.com/firmware.bin", 88 "fileUrl": "http://example.com/firmware.bin",
89 "information": "{\"desc\":\"升级到最新版本\"}" 89 "information": "{\"desc\":\"升级到最新版本\"}"
90 } 90 }
91 -}  
92 \ No newline at end of file 91 \ No newline at end of file
  92 +}
  93 +
  94 +### 查询设备消息对分页 - 基础查询(设备编号25)
  95 +GET {{baseUrl}}/iot/device/message/pair-page?deviceId=25&pageNo=1&pageSize=10
  96 +Authorization: Bearer {{token}}
  97 +tenant-id: {{adminTenantId}}
  98 +
  99 +### 查询设备消息对分页 - 按标识符过滤(identifier=eat)
  100 +GET {{baseUrl}}/iot/device/message/pair-page?deviceId=25&identifier=eat&pageNo=1&pageSize=10
  101 +Authorization: Bearer {{token}}
  102 +tenant-id: {{adminTenantId}}
93 \ No newline at end of file 103 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceMessageController.java
1 package cn.iocoder.yudao.module.iot.controller.admin.device; 1 package cn.iocoder.yudao.module.iot.controller.admin.device;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 6 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
6 -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.message.IotDeviceMessageRespVO;  
7 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.message.IotDeviceMessagePageReqVO; 7 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.message.IotDeviceMessagePageReqVO;
  8 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.message.IotDeviceMessageRespPairVO;
  9 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.message.IotDeviceMessageRespVO;
8 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.message.IotDeviceMessageSendReqVO; 10 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.message.IotDeviceMessageSendReqVO;
9 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; 11 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
10 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceMessageDO; 12 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceMessageDO;
  13 +import cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceMessageMapper;
  14 +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
11 import cn.iocoder.yudao.module.iot.service.device.message.IotDeviceMessageService; 15 import cn.iocoder.yudao.module.iot.service.device.message.IotDeviceMessageService;
  16 +import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService;
12 import io.swagger.v3.oas.annotations.Operation; 17 import io.swagger.v3.oas.annotations.Operation;
13 import io.swagger.v3.oas.annotations.tags.Tag; 18 import io.swagger.v3.oas.annotations.tags.Tag;
14 import jakarta.annotation.Resource; 19 import jakarta.annotation.Resource;
@@ -17,7 +22,12 @@ import org.springframework.security.access.prepost.PreAuthorize; @@ -17,7 +22,12 @@ import org.springframework.security.access.prepost.PreAuthorize;
17 import org.springframework.validation.annotation.Validated; 22 import org.springframework.validation.annotation.Validated;
18 import org.springframework.web.bind.annotation.*; 23 import org.springframework.web.bind.annotation.*;
19 24
  25 +import java.util.List;
  26 +import java.util.Map;
  27 +
20 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 28 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  29 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  30 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
21 31
22 @Tag(name = "管理后台 - IoT 设备消息") 32 @Tag(name = "管理后台 - IoT 设备消息")
23 @RestController 33 @RestController
@@ -27,19 +37,54 @@ public class IotDeviceMessageController { @@ -27,19 +37,54 @@ public class IotDeviceMessageController {
27 37
28 @Resource 38 @Resource
29 private IotDeviceMessageService deviceMessageService; 39 private IotDeviceMessageService deviceMessageService;
  40 + @Resource
  41 + private IotDeviceService deviceService;
  42 + @Resource
  43 + private IotThingModelService thingModelService;
  44 + @Resource
  45 + private IotDeviceMessageMapper deviceMessageMapper;
30 46
31 @GetMapping("/page") 47 @GetMapping("/page")
32 @Operation(summary = "获得设备消息分页") 48 @Operation(summary = "获得设备消息分页")
33 @PreAuthorize("@ss.hasPermission('iot:device:message-query')") 49 @PreAuthorize("@ss.hasPermission('iot:device:message-query')")
34 - public CommonResult<PageResult<IotDeviceMessageRespVO>> getDeviceLogPage(@Valid IotDeviceMessagePageReqVO pageReqVO) { 50 + public CommonResult<PageResult<IotDeviceMessageRespVO>> getDeviceMessagePage(
  51 + @Valid IotDeviceMessagePageReqVO pageReqVO) {
35 PageResult<IotDeviceMessageDO> pageResult = deviceMessageService.getDeviceMessagePage(pageReqVO); 52 PageResult<IotDeviceMessageDO> pageResult = deviceMessageService.getDeviceMessagePage(pageReqVO);
36 return success(BeanUtils.toBean(pageResult, IotDeviceMessageRespVO.class)); 53 return success(BeanUtils.toBean(pageResult, IotDeviceMessageRespVO.class));
37 } 54 }
38 55
  56 + @GetMapping("/pair-page")
  57 + @Operation(summary = "获得设备消息对分页")
  58 + @PreAuthorize("@ss.hasPermission('iot:device:message-query')")
  59 + public CommonResult<PageResult<IotDeviceMessageRespPairVO>> getDeviceMessagePairPage(
  60 + @Valid IotDeviceMessagePageReqVO pageReqVO) {
  61 + // 1.1 先按照条件,查询 request 的消息(非 reply)
  62 + pageReqVO.setReply(false);
  63 + PageResult<IotDeviceMessageDO> requestMessagePageResult = deviceMessageService.getDeviceMessagePage(pageReqVO);
  64 + if (CollUtil.isEmpty(requestMessagePageResult.getList())) {
  65 + return success(PageResult.empty());
  66 + }
  67 + // 1.2 接着按照 requestIds,批量查询 reply 消息
  68 + List<String> requestIds = convertList(requestMessagePageResult.getList(), IotDeviceMessageDO::getRequestId);
  69 + List<IotDeviceMessageDO> replyMessageList = deviceMessageService.getDeviceMessageListByRequestIdsAndReply(
  70 + pageReqVO.getDeviceId(), requestIds, true);
  71 + Map<String, IotDeviceMessageDO> replyMessages = convertMap(replyMessageList, IotDeviceMessageDO::getRequestId);
  72 +
  73 + // 2. 组装结果
  74 + List<IotDeviceMessageRespPairVO> pairMessages = convertList(requestMessagePageResult.getList(),
  75 + requestMessage -> {
  76 + IotDeviceMessageDO replyMessage = replyMessages.get(requestMessage.getRequestId());
  77 + return new IotDeviceMessageRespPairVO()
  78 + .setRequest(BeanUtils.toBean(requestMessage, IotDeviceMessageRespVO.class))
  79 + .setReply(BeanUtils.toBean(replyMessage, IotDeviceMessageRespVO.class));
  80 + });
  81 + return success(new PageResult<>(pairMessages, requestMessagePageResult.getTotal()));
  82 + }
  83 +
39 @PostMapping("/send") 84 @PostMapping("/send")
40 @Operation(summary = "发送消息", description = "可用于设备模拟") 85 @Operation(summary = "发送消息", description = "可用于设备模拟")
41 @PreAuthorize("@ss.hasPermission('iot:device:message-end')") 86 @PreAuthorize("@ss.hasPermission('iot:device:message-end')")
42 - public CommonResult<Boolean> upstreamDevice(@Valid @RequestBody IotDeviceMessageSendReqVO sendReqVO) { 87 + public CommonResult<Boolean> sendDeviceMessage(@Valid @RequestBody IotDeviceMessageSendReqVO sendReqVO) {
43 deviceMessageService.sendDeviceMessage(BeanUtils.toBean(sendReqVO, IotDeviceMessage.class)); 88 deviceMessageService.sendDeviceMessage(BeanUtils.toBean(sendReqVO, IotDeviceMessage.class));
44 return success(true); 89 return success(true);
45 } 90 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/message/IotDeviceMessagePageReqVO.java
@@ -5,7 +5,13 @@ import cn.iocoder.yudao.framework.common.validation.InEnum; @@ -5,7 +5,13 @@ import cn.iocoder.yudao.framework.common.validation.InEnum;
5 import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; 5 import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
6 import io.swagger.v3.oas.annotations.media.Schema; 6 import io.swagger.v3.oas.annotations.media.Schema;
7 import jakarta.validation.constraints.NotNull; 7 import jakarta.validation.constraints.NotNull;
  8 +import jakarta.validation.constraints.Size;
8 import lombok.Data; 9 import lombok.Data;
  10 +import org.springframework.format.annotation.DateTimeFormat;
  11 +
  12 +import java.time.LocalDateTime;
  13 +
  14 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
9 15
10 @Schema(description = "管理后台 - IoT 设备消息分页查询 Request VO") 16 @Schema(description = "管理后台 - IoT 设备消息分页查询 Request VO")
11 @Data 17 @Data
@@ -22,4 +28,15 @@ public class IotDeviceMessagePageReqVO extends PageParam { @@ -22,4 +28,15 @@ public class IotDeviceMessagePageReqVO extends PageParam {
22 @Schema(description = "是否上行", example = "true") 28 @Schema(description = "是否上行", example = "true")
23 private Boolean upstream; 29 private Boolean upstream;
24 30
  31 + @Schema(description = "是否回复", example = "true")
  32 + private Boolean reply;
  33 +
  34 + @Schema(description = "标识符", example = "temperature")
  35 + private String identifier;
  36 +
  37 + @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
  38 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  39 + @Size(min = 2, max = 2, message = "请选择时间范围")
  40 + private LocalDateTime[] times;
  41 +
25 } 42 }
26 \ No newline at end of file 43 \ 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/message/IotDeviceMessageRespPairVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.message;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +@Schema(description = "管理后台 - IoT 设备消息对 Response VO")
  7 +@Data
  8 +public class IotDeviceMessageRespPairVO {
  9 +
  10 + @Schema(description = "请求消息", requiredMode = Schema.RequiredMode.REQUIRED)
  11 + private IotDeviceMessageRespVO request;
  12 +
  13 + @Schema(description = "响应消息")
  14 + private IotDeviceMessageRespVO reply; // 通过 requestId 配对
  15 +
  16 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/message/IotDeviceMessageRespVO.java
@@ -30,6 +30,9 @@ public class IotDeviceMessageRespVO { @@ -30,6 +30,9 @@ public class IotDeviceMessageRespVO {
30 @Schema(description = "是否回复消息", example = "false", examples = "true") 30 @Schema(description = "是否回复消息", example = "false", examples = "true")
31 private Boolean reply; 31 private Boolean reply;
32 32
  33 + @Schema(description = "标识符", example = "temperature")
  34 + private String identifier;
  35 +
33 // ========== codec(编解码)字段 ========== 36 // ========== codec(编解码)字段 ==========
34 37
35 @Schema(description = "请求编号", example = "req_123") 38 @Schema(description = "请求编号", example = "req_123")
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceMessageDO.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.device; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.device;
2 2
3 import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; 3 import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
4 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; 4 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
  5 +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
5 import lombok.AllArgsConstructor; 6 import lombok.AllArgsConstructor;
6 import lombok.Builder; 7 import lombok.Builder;
7 import lombok.Data; 8 import lombok.Data;
@@ -63,6 +64,13 @@ public class IotDeviceMessageDO { @@ -63,6 +64,13 @@ public class IotDeviceMessageDO {
63 * 计算并存储的目的:方便计算多少条请求、多少条回复 64 * 计算并存储的目的:方便计算多少条请求、多少条回复
64 */ 65 */
65 private Boolean reply; 66 private Boolean reply;
  67 + /**
  68 + * 标识符
  69 + *
  70 + * 例如说:{@link IotThingModelDO#getIdentifier()}
  71 + * 目前,只有事件上报、服务调用才有!!!
  72 + */
  73 + private String identifier;
66 74
67 // ========== codec(编解码)字段 ========== 75 // ========== codec(编解码)字段 ==========
68 76
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java
@@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelP @@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelP
8 import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; 8 import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
9 import org.apache.ibatis.annotations.Mapper; 9 import org.apache.ibatis.annotations.Mapper;
10 10
11 -import java.time.LocalDateTime; 11 +import java.util.Collection;
12 import java.util.List; 12 import java.util.List;
13 13
14 /** 14 /**
@@ -50,6 +50,12 @@ public interface IotThingModelMapper extends BaseMapperX&lt;IotThingModelDO&gt; { @@ -50,6 +50,12 @@ public interface IotThingModelMapper extends BaseMapperX&lt;IotThingModelDO&gt; {
50 return selectList(IotThingModelDO::getProductId, productId); 50 return selectList(IotThingModelDO::getProductId, productId);
51 } 51 }
52 52
  53 + default List<IotThingModelDO> selectListByProductIdAndIdentifiers(Long productId, Collection<String> identifiers) {
  54 + return selectList(new LambdaQueryWrapperX<IotThingModelDO>()
  55 + .eq(IotThingModelDO::getProductId, productId)
  56 + .in(IotThingModelDO::getIdentifier, identifiers));
  57 + }
  58 +
53 default List<IotThingModelDO> selectListByProductIdAndType(Long productId, Integer type) { 59 default List<IotThingModelDO> selectListByProductIdAndType(Long productId, Integer type) {
54 return selectList(IotThingModelDO::getProductId, productId, 60 return selectList(IotThingModelDO::getProductId, productId,
55 IotThingModelDO::getType, type); 61 IotThingModelDO::getType, type);
@@ -69,16 +75,4 @@ public interface IotThingModelMapper extends BaseMapperX&lt;IotThingModelDO&gt; { @@ -69,16 +75,4 @@ public interface IotThingModelMapper extends BaseMapperX&lt;IotThingModelDO&gt; {
69 IotThingModelDO::getName, name); 75 IotThingModelDO::getName, name);
70 } 76 }
71 77
72 - // TODO @super:用不到,删除下;  
73 - /**  
74 - * 统计物模型数量  
75 - *  
76 - * @param createTime 创建时间,如果为空,则统计所有物模型数量  
77 - * @return 物模型数量  
78 - */  
79 - default Long selectCountByCreateTime(LocalDateTime createTime) {  
80 - return selectCount(new LambdaQueryWrapperX<IotThingModelDO>()  
81 - .geIfPresent(IotThingModelDO::getCreateTime, createTime));  
82 - }  
83 -  
84 } 78 }
85 \ No newline at end of file 79 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceMessageMapper.java
@@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage; @@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
8 import org.apache.ibatis.annotations.Mapper; 8 import org.apache.ibatis.annotations.Mapper;
9 import org.apache.ibatis.annotations.Param; 9 import org.apache.ibatis.annotations.Param;
10 10
  11 +import java.util.Collection;
11 import java.util.List; 12 import java.util.List;
12 import java.util.Map; 13 import java.util.Map;
13 14
@@ -58,6 +59,18 @@ public interface IotDeviceMessageMapper { @@ -58,6 +59,18 @@ public interface IotDeviceMessageMapper {
58 Long selectCountByCreateTime(@Param("createTime") Long createTime); 59 Long selectCountByCreateTime(@Param("createTime") Long createTime);
59 60
60 /** 61 /**
  62 + * 按照 requestIds 批量查询消息
  63 + *
  64 + * @param deviceId 设备编号
  65 + * @param requestIds 请求编号集合
  66 + * @param reply 是否回复消息
  67 + * @return 消息列表
  68 + */
  69 + List<IotDeviceMessageDO> selectListByRequestIdsAndReply(@Param("deviceId") Long deviceId,
  70 + @Param("requestIds") Collection<String> requestIds,
  71 + @Param("reply") Boolean reply);
  72 +
  73 + /**
61 * 按照时间范围(小时),统计设备的消息数量 74 * 按照时间范围(小时),统计设备的消息数量
62 */ 75 */
63 List<Map<String, Object>> selectDeviceMessageCountGroupByDate(@Param("startTime") Long startTime, 76 List<Map<String, Object>> selectDeviceMessageCountGroupByDate(@Param("startTime") Long startTime,
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java
@@ -32,7 +32,7 @@ public interface IotDevicePropertyMapper { @@ -32,7 +32,7 @@ public interface IotDevicePropertyMapper {
32 List<TDengineTableField> oldFields, 32 List<TDengineTableField> oldFields,
33 List<TDengineTableField> newFields) { 33 List<TDengineTableField> newFields) {
34 oldFields.removeIf(field -> StrUtil.equalsAny(field.getField(), 34 oldFields.removeIf(field -> StrUtil.equalsAny(field.getField(),
35 - TDengineTableField.FIELD_TS, "report_time")); 35 + TDengineTableField.FIELD_TS, "report_time", "device_id"));
36 List<TDengineTableField> addFields = newFields.stream().filter( // 新增的字段 36 List<TDengineTableField> addFields = newFields.stream().filter( // 新增的字段
37 newField -> oldFields.stream().noneMatch(oldField -> oldField.getField().equals(newField.getField()))) 37 newField -> oldFields.stream().noneMatch(oldField -> oldField.getField().equals(newField.getField())))
38 .collect(Collectors.toList()); 38 .collect(Collectors.toList());
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/message/IotDeviceMessageService.java
@@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsD @@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsD
7 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; 7 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
8 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; 8 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
9 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceMessageDO; 9 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceMessageDO;
  10 +import jakarta.validation.constraints.NotEmpty;
  11 +import jakarta.validation.constraints.NotNull;
10 12
11 import javax.annotation.Nullable; 13 import javax.annotation.Nullable;
12 import java.time.LocalDateTime; 14 import java.time.LocalDateTime;
@@ -64,6 +66,19 @@ public interface IotDeviceMessageService { @@ -64,6 +66,19 @@ public interface IotDeviceMessageService {
64 PageResult<IotDeviceMessageDO> getDeviceMessagePage(IotDeviceMessagePageReqVO pageReqVO); 66 PageResult<IotDeviceMessageDO> getDeviceMessagePage(IotDeviceMessagePageReqVO pageReqVO);
65 67
66 /** 68 /**
  69 + * 获得指定 requestId 的设备消息列表
  70 + *
  71 + * @param deviceId 设备编号
  72 + * @param requestIds requestId 列表
  73 + * @param reply 是否回复
  74 + * @return 设备消息列表
  75 + */
  76 + List<IotDeviceMessageDO> getDeviceMessageListByRequestIdsAndReply(
  77 + @NotNull(message = "设备编号不能为空") Long deviceId,
  78 + @NotEmpty(message = "请求编号不能为空") List<String> requestIds,
  79 + Boolean reply);
  80 +
  81 + /**
67 * 获得设备消息数量 82 * 获得设备消息数量
68 * 83 *
69 * @param createTime 创建时间,如果为空,则统计所有消息数量 84 * @param createTime 创建时间,如果为空,则统计所有消息数量
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/message/IotDeviceMessageServiceImpl.java
@@ -76,7 +76,8 @@ public class IotDeviceMessageServiceImpl implements IotDeviceMessageService { @@ -76,7 +76,8 @@ public class IotDeviceMessageServiceImpl implements IotDeviceMessageService {
76 void createDeviceLogAsync(IotDeviceMessage message) { 76 void createDeviceLogAsync(IotDeviceMessage message) {
77 IotDeviceMessageDO messageDO = BeanUtils.toBean(message, IotDeviceMessageDO.class) 77 IotDeviceMessageDO messageDO = BeanUtils.toBean(message, IotDeviceMessageDO.class)
78 .setUpstream(IotDeviceMessageUtils.isUpstreamMessage(message)) 78 .setUpstream(IotDeviceMessageUtils.isUpstreamMessage(message))
79 - .setReply(IotDeviceMessageUtils.isReplyMessage(message)); 79 + .setReply(IotDeviceMessageUtils.isReplyMessage(message))
  80 + .setIdentifier(IotDeviceMessageUtils.getIdentifier(message));
80 if (message.getParams() != null) { 81 if (message.getParams() != null) {
81 messageDO.setParams(JsonUtils.toJsonString(messageDO.getParams())); 82 messageDO.setParams(JsonUtils.toJsonString(messageDO.getParams()));
82 } 83 }
@@ -213,6 +214,13 @@ public class IotDeviceMessageServiceImpl implements IotDeviceMessageService { @@ -213,6 +214,13 @@ public class IotDeviceMessageServiceImpl implements IotDeviceMessageService {
213 } 214 }
214 215
215 @Override 216 @Override
  217 + public List<IotDeviceMessageDO> getDeviceMessageListByRequestIdsAndReply(Long deviceId,
  218 + List<String> requestIds,
  219 + Boolean reply) {
  220 + return deviceMessageMapper.selectListByRequestIdsAndReply(deviceId, requestIds, reply);
  221 + }
  222 +
  223 + @Override
216 public Long getDeviceMessageCount(LocalDateTime createTime) { 224 public Long getDeviceMessageCount(LocalDateTime createTime) {
217 return deviceMessageMapper.selectCountByCreateTime(createTime != null ? LocalDateTimeUtil.toEpochMilli(createTime) : null); 225 return deviceMessageMapper.selectCountByCreateTime(createTime != null ? LocalDateTimeUtil.toEpochMilli(createTime) : null);
218 } 226 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java
@@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelS @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelS
7 import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; 7 import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
8 import jakarta.validation.Valid; 8 import jakarta.validation.Valid;
9 9
  10 +import java.util.Collection;
10 import java.util.List; 11 import java.util.List;
11 12
12 /** 13 /**
@@ -58,6 +59,15 @@ public interface IotThingModelService { @@ -58,6 +59,15 @@ public interface IotThingModelService {
58 * 获得产品物模型列表 59 * 获得产品物模型列表
59 * 60 *
60 * @param productId 产品编号 61 * @param productId 产品编号
  62 + * @param identifiers 功能标识列表
  63 + * @return 产品物模型列表
  64 + */
  65 + List<IotThingModelDO> getThingModelListByProductIdAndIdentifiers(Long productId, Collection<String> identifiers);
  66 +
  67 + /**
  68 + * 获得产品物模型列表
  69 + *
  70 + * @param productId 产品编号
61 * @param type 物模型类型 71 * @param type 物模型类型
62 * @return 产品物模型列表 72 * @return 产品物模型列表
63 */ 73 */
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java
@@ -132,6 +132,11 @@ public class IotThingModelServiceImpl implements IotThingModelService { @@ -132,6 +132,11 @@ public class IotThingModelServiceImpl implements IotThingModelService {
132 } 132 }
133 133
134 @Override 134 @Override
  135 + public List<IotThingModelDO> getThingModelListByProductIdAndIdentifiers(Long productId, Collection<String> identifiers) {
  136 + return thingModelMapper.selectListByProductIdAndIdentifiers(productId, identifiers);
  137 + }
  138 +
  139 + @Override
135 public List<IotThingModelDO> getThingModelListByProductIdAndType(Long productId, Integer type) { 140 public List<IotThingModelDO> getThingModelListByProductIdAndType(Long productId, Integer type) {
136 return thingModelMapper.selectListByProductIdAndType(productId, type); 141 return thingModelMapper.selectListByProductIdAndType(productId, type);
137 } 142 }
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMessageMapper.xml
@@ -13,6 +13,7 @@ @@ -13,6 +13,7 @@
13 server_id NCHAR(50), 13 server_id NCHAR(50),
14 upstream BOOL, 14 upstream BOOL,
15 reply BOOL, 15 reply BOOL,
  16 + identifier NCHAR(100),
16 request_id NCHAR(50), 17 request_id NCHAR(50),
17 method NCHAR(100), 18 method NCHAR(100),
18 params NCHAR(2048), 19 params NCHAR(2048),
@@ -31,22 +32,22 @@ @@ -31,22 +32,22 @@
31 <insert id="insert"> 32 <insert id="insert">
32 INSERT INTO device_message_${deviceId} ( 33 INSERT INTO device_message_${deviceId} (
33 ts, id, report_time, tenant_id, server_id, 34 ts, id, report_time, tenant_id, server_id,
34 - upstream, reply, request_id, method, params,  
35 - data, code, msg 35 + upstream, reply, identifier, request_id, method,
  36 + params, data, code, msg
36 ) 37 )
37 USING device_message 38 USING device_message
38 TAGS (#{deviceId}) 39 TAGS (#{deviceId})
39 VALUES ( 40 VALUES (
40 NOW, #{id}, #{reportTime}, #{tenantId}, #{serverId}, 41 NOW, #{id}, #{reportTime}, #{tenantId}, #{serverId},
41 - #{upstream}, #{reply}, #{requestId}, #{method}, #{params},  
42 - #{data}, #{code}, #{msg} 42 + #{upstream}, #{reply}, #{identifier}, #{requestId}, #{method},
  43 + #{params}, #{data}, #{code}, #{msg}
43 ) 44 )
44 </insert> 45 </insert>
45 46
46 <select id="selectPage" resultType="cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceMessageDO"> 47 <select id="selectPage" resultType="cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceMessageDO">
47 SELECT ts, id, report_time, tenant_id, server_id, 48 SELECT ts, id, report_time, tenant_id, server_id,
48 - upstream, reply, request_id, method, params,  
49 - data, code, msg 49 + upstream, reply, identifier, request_id, method,
  50 + params, data, code, msg
50 FROM device_message_${reqVO.deviceId} 51 FROM device_message_${reqVO.deviceId}
51 <where> 52 <where>
52 <if test="reqVO.method != null and reqVO.method != ''"> 53 <if test="reqVO.method != null and reqVO.method != ''">
@@ -55,10 +56,29 @@ @@ -55,10 +56,29 @@
55 <if test="reqVO.upstream != null"> 56 <if test="reqVO.upstream != null">
56 AND upstream = #{reqVO.upstream} 57 AND upstream = #{reqVO.upstream}
57 </if> 58 </if>
  59 + <if test="reqVO.reply != null">
  60 + AND reply = #{reqVO.reply}
  61 + </if>
  62 + <if test="reqVO.identifier != null and reqVO.identifier != ''">
  63 + AND identifier = #{reqVO.identifier}
  64 + </if>
58 </where> 65 </where>
59 ORDER BY ts DESC 66 ORDER BY ts DESC
60 </select> 67 </select>
61 68
  69 + <select id="selectListByRequestIdsAndReply" resultType="cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceMessageDO">
  70 + SELECT ts, id, report_time, tenant_id, server_id,
  71 + upstream, reply, identifier, request_id, method,
  72 + params, data, code, msg
  73 + FROM device_message_${deviceId}
  74 + WHERE reply = #{reply}
  75 + AND request_id IN
  76 + <foreach collection="requestIds" item="requestId" open="(" close=")" separator=",">
  77 + #{requestId}
  78 + </foreach>
  79 + ORDER BY ts DESC
  80 + </select>
  81 +
62 <select id="selectCountByCreateTime" resultType="Long"> 82 <select id="selectCountByCreateTime" resultType="Long">
63 SELECT COUNT(*) 83 SELECT COUNT(*)
64 FROM device_message 84 FROM device_message
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/enums/IotDeviceMessageMethodEnum.java
@@ -32,6 +32,10 @@ public enum IotDeviceMessageMethodEnum implements ArrayValuable&lt;String&gt; { @@ -32,6 +32,10 @@ public enum IotDeviceMessageMethodEnum implements ArrayValuable&lt;String&gt; {
32 32
33 EVENT_POST("thing.event.post", "事件上报", true), 33 EVENT_POST("thing.event.post", "事件上报", true),
34 34
  35 + // ========== 设备服务调用 ==========
  36 +
  37 + SERVICE_INVOKE("thing.service.invoke", "服务调用", false),
  38 +
35 ; 39 ;
36 40
37 public static final String[] ARRAYS = Arrays.stream(values()).map(IotDeviceMessageMethodEnum::getMethod) 41 public static final String[] ARRAYS = Arrays.stream(values()).map(IotDeviceMessageMethodEnum::getMethod)
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/util/IotDeviceMessageUtils.java
1 package cn.iocoder.yudao.module.iot.core.util; 1 package cn.iocoder.yudao.module.iot.core.util;
2 2
3 import cn.hutool.core.lang.Assert; 3 import cn.hutool.core.lang.Assert;
  4 +import cn.hutool.core.map.MapUtil;
4 import cn.hutool.core.util.IdUtil; 5 import cn.hutool.core.util.IdUtil;
  6 +import cn.hutool.core.util.StrUtil;
5 import cn.hutool.system.SystemUtil; 7 import cn.hutool.system.SystemUtil;
6 import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; 8 import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
7 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; 9 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
8 10
  11 +import java.util.Map;
  12 +
9 /** 13 /**
10 * IoT 设备【消息】的工具类 14 * IoT 设备【消息】的工具类
11 * 15 *
@@ -43,6 +47,23 @@ public class IotDeviceMessageUtils { @@ -43,6 +47,23 @@ public class IotDeviceMessageUtils {
43 return message.getCode() != null; 47 return message.getCode() != null;
44 } 48 }
45 49
  50 + /**
  51 + * 提取消息中的标识符
  52 + *
  53 + * @param message 消息
  54 + * @return 标识符
  55 + */
  56 + @SuppressWarnings("unchecked")
  57 + public static String getIdentifier(IotDeviceMessage message) {
  58 + if (StrUtil.equalsAny(message.getMethod(), IotDeviceMessageMethodEnum.EVENT_POST.getMethod(),
  59 + message.getMethod(), IotDeviceMessageMethodEnum.SERVICE_INVOKE.getMethod())
  60 + && message.getParams() != null) {
  61 + Map<String, Object> params = (Map<String, Object>) message.getParams();
  62 + return MapUtil.getStr(params, "identifier");
  63 + }
  64 + return null;
  65 + }
  66 +
46 // ========== Topic 相关 ========== 67 // ========== Topic 相关 ==========
47 68
48 public static String buildMessageBusGatewayDeviceMessageTopic(String serverId) { 69 public static String buildMessageBusGatewayDeviceMessageTopic(String serverId) {