Commit 5db1c5116c338653d7e97555ddbb0e70a8651299
1 parent
56b2b540
refactor(iot): 对齐设备影子代码风格
Showing
5 changed files
with
33 additions
and
27 deletions
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceShadowController.java
| @@ -57,31 +57,23 @@ public class IotDeviceShadowController { | @@ -57,31 +57,23 @@ public class IotDeviceShadowController { | ||
| 57 | public CommonResult<IotDeviceShadowRespVO> getDeviceShadow(@RequestParam("deviceId") Long deviceId) { | 57 | public CommonResult<IotDeviceShadowRespVO> getDeviceShadow(@RequestParam("deviceId") Long deviceId) { |
| 58 | IotDeviceDO device = deviceService.validateDeviceExists(deviceId); | 58 | IotDeviceDO device = deviceService.validateDeviceExists(deviceId); |
| 59 | IotDeviceShadowDO shadow = deviceShadowService.getOrCreateShadow(device); | 59 | IotDeviceShadowDO shadow = deviceShadowService.getOrCreateShadow(device); |
| 60 | - | 60 | + // 拼接 VO |
| 61 | List<IotThingModelDO> thingModels = thingModelService.getThingModelListByProductIdAndType( | 61 | List<IotThingModelDO> thingModels = thingModelService.getThingModelListByProductIdAndType( |
| 62 | device.getProductId(), IotThingModelTypeEnum.PROPERTY.getType()); | 62 | device.getProductId(), IotThingModelTypeEnum.PROPERTY.getType()); |
| 63 | Map<String, Object> desired = shadow.getDesired() != null ? shadow.getDesired() : MapUtil.empty(); | 63 | Map<String, Object> desired = shadow.getDesired() != null ? shadow.getDesired() : MapUtil.empty(); |
| 64 | Map<String, Object> reported = shadow.getReported() != null ? shadow.getReported() : MapUtil.empty(); | 64 | Map<String, Object> reported = shadow.getReported() != null ? shadow.getReported() : MapUtil.empty(); |
| 65 | Map<String, Object> metadata = shadow.getMetadata() != null ? shadow.getMetadata() : MapUtil.empty(); | 65 | Map<String, Object> metadata = shadow.getMetadata() != null ? shadow.getMetadata() : MapUtil.empty(); |
| 66 | - // 拼接 VO | ||
| 67 | List<IotDeviceShadowPropertyRespVO> properties = convertList(thingModels, thingModel -> { | 66 | List<IotDeviceShadowPropertyRespVO> properties = convertList(thingModels, thingModel -> { |
| 68 | ThingModelProperty prop = thingModel.getProperty(); | 67 | ThingModelProperty prop = thingModel.getProperty(); |
| 69 | Assert.notNull(prop, "属性不能为空"); | 68 | Assert.notNull(prop, "属性不能为空"); |
| 70 | - return new IotDeviceShadowPropertyRespVO() | ||
| 71 | - .setIdentifier(thingModel.getIdentifier()).setName(thingModel.getName()) | ||
| 72 | - .setDataType(prop.getDataType()).setDataSpecs(prop.getDataSpecs()) | ||
| 73 | - .setDataSpecsList(prop.getDataSpecsList()) | ||
| 74 | - .setDesiredValue(desired.get(thingModel.getIdentifier())) | ||
| 75 | - .setReportedValue(reported.get(thingModel.getIdentifier())) | 69 | + return new IotDeviceShadowPropertyRespVO().setIdentifier(thingModel.getIdentifier()).setName(thingModel.getName()) |
| 70 | + .setDataType(prop.getDataType()).setDataSpecs(prop.getDataSpecs()).setDataSpecsList(prop.getDataSpecsList()) | ||
| 71 | + .setDesiredValue(desired.get(thingModel.getIdentifier())).setReportedValue(reported.get(thingModel.getIdentifier())) | ||
| 76 | .setDesiredTime(IotDeviceShadowProtocolUtils.getDesiredTimestamp(metadata, thingModel.getIdentifier())) | 72 | .setDesiredTime(IotDeviceShadowProtocolUtils.getDesiredTimestamp(metadata, thingModel.getIdentifier())) |
| 77 | .setReportedTime(IotDeviceShadowProtocolUtils.getReportedTimestamp(metadata, thingModel.getIdentifier())); | 73 | .setReportedTime(IotDeviceShadowProtocolUtils.getReportedTimestamp(metadata, thingModel.getIdentifier())); |
| 78 | }); | 74 | }); |
| 79 | - | ||
| 80 | IotDeviceShadowRespVO respVO = BeanUtils.toBean(shadow, IotDeviceShadowRespVO.class) | 75 | IotDeviceShadowRespVO respVO = BeanUtils.toBean(shadow, IotDeviceShadowRespVO.class) |
| 81 | - .setProperties(properties) | ||
| 82 | - .setDesired(desired) | ||
| 83 | - .setReported(reported) | ||
| 84 | - .setMetadata(metadata); | 76 | + .setProperties(properties).setDesired(desired).setReported(reported).setMetadata(metadata); |
| 85 | return success(respVO); | 77 | return success(respVO); |
| 86 | } | 78 | } |
| 87 | 79 |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/shadow/IotDeviceShadowRespVO.java
| @@ -21,7 +21,7 @@ public class IotDeviceShadowRespVO { | @@ -21,7 +21,7 @@ public class IotDeviceShadowRespVO { | ||
| 21 | @Schema(description = "最后更新时间(epoch 秒)", example = "1469564576") | 21 | @Schema(description = "最后更新时间(epoch 秒)", example = "1469564576") |
| 22 | private Long shadowTime; | 22 | private Long shadowTime; |
| 23 | 23 | ||
| 24 | - @Schema(description = "是否启用", example = "0") | 24 | + @Schema(description = "影子状态", example = "0") |
| 25 | private Integer status; | 25 | private Integer status; |
| 26 | 26 | ||
| 27 | @Schema(description = "属性对比列表") | 27 | @Schema(description = "属性对比列表") |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceShadowDO.java
| @@ -34,6 +34,8 @@ public class IotDeviceShadowDO extends TenantBaseDO { | @@ -34,6 +34,8 @@ public class IotDeviceShadowDO extends TenantBaseDO { | ||
| 34 | private Long id; | 34 | private Long id; |
| 35 | /** | 35 | /** |
| 36 | * 设备编号 | 36 | * 设备编号 |
| 37 | + * <p> | ||
| 38 | + * 关联 {@link IotDeviceDO#getId()} | ||
| 37 | */ | 39 | */ |
| 38 | private Long deviceId; | 40 | private Long deviceId; |
| 39 | /** | 41 | /** |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/shadow/IotDeviceShadowServiceImpl.java
| @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.service.device.shadow; | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.service.device.shadow; | ||
| 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.lang.Assert; | 5 | import cn.hutool.core.lang.Assert; |
| 6 | +import cn.hutool.core.map.MapUtil; | ||
| 6 | import cn.hutool.core.util.ObjUtil; | 7 | import cn.hutool.core.util.ObjUtil; |
| 7 | import cn.hutool.core.util.StrUtil; | 8 | import cn.hutool.core.util.StrUtil; |
| 8 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | 9 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| @@ -96,6 +97,14 @@ public class IotDeviceShadowServiceImpl implements IotDeviceShadowService { | @@ -96,6 +97,14 @@ public class IotDeviceShadowServiceImpl implements IotDeviceShadowService { | ||
| 96 | } | 97 | } |
| 97 | } | 98 | } |
| 98 | 99 | ||
| 100 | + /** | ||
| 101 | + * 处理设备影子上行:解析 params,并按内层 method 分发到 get、update | ||
| 102 | + * <p> | ||
| 103 | + * 影子未启用时,直接忽略,不回复 | ||
| 104 | + * | ||
| 105 | + * @param device 设备 | ||
| 106 | + * @param message 上行消息 | ||
| 107 | + */ | ||
| 99 | private void handleDeviceShadowUpdate0(IotDeviceDO device, IotDeviceMessage message) { | 108 | private void handleDeviceShadowUpdate0(IotDeviceDO device, IotDeviceMessage message) { |
| 100 | // 1.1 解析请求:params 结构为 { method, state: { reported }, version } | 109 | // 1.1 解析请求:params 结构为 { method, state: { reported }, version } |
| 101 | IotDeviceShadowUpdateReqDTO reqDTO = JsonUtils.convertObject(message.getParams(), | 110 | IotDeviceShadowUpdateReqDTO reqDTO = JsonUtils.convertObject(message.getParams(), |
| @@ -125,6 +134,14 @@ public class IotDeviceShadowServiceImpl implements IotDeviceShadowService { | @@ -125,6 +134,14 @@ public class IotDeviceShadowServiceImpl implements IotDeviceShadowService { | ||
| 125 | shadow.getVersion()); | 134 | shadow.getVersion()); |
| 126 | } | 135 | } |
| 127 | 136 | ||
| 137 | + /** | ||
| 138 | + * 处理设备上报的 update:version 为 -1 时清空影子,否则合并 reported,并回复新版本 | ||
| 139 | + * | ||
| 140 | + * @param device 设备 | ||
| 141 | + * @param message 上行消息 | ||
| 142 | + * @param reqDTO 上行 params | ||
| 143 | + * @param shadow DB 中的当前影子,用于错误回复时携带版本 | ||
| 144 | + */ | ||
| 128 | private void handleReportedUpdate(IotDeviceDO device, IotDeviceMessage message, | 145 | private void handleReportedUpdate(IotDeviceDO device, IotDeviceMessage message, |
| 129 | IotDeviceShadowUpdateReqDTO reqDTO, IotDeviceShadowDO shadow) { | 146 | IotDeviceShadowUpdateReqDTO reqDTO, IotDeviceShadowDO shadow) { |
| 130 | // 1. version 为 -1 时,清空影子,无需 state | 147 | // 1. version 为 -1 时,清空影子,无需 state |
| @@ -269,13 +286,14 @@ public class IotDeviceShadowServiceImpl implements IotDeviceShadowService { | @@ -269,13 +286,14 @@ public class IotDeviceShadowServiceImpl implements IotDeviceShadowService { | ||
| 269 | } | 286 | } |
| 270 | 287 | ||
| 271 | // 2.1 合并属性,并校验属性数 | 288 | // 2.1 合并属性,并校验属性数 |
| 272 | - Map<String, Object> state = mergeMap(desired ? latest.getDesired() : latest.getReported(), values); | 289 | + Map<String, Object> state = new HashMap<>(MapUtil.emptyIfNull(desired ? latest.getDesired() : latest.getReported())); |
| 290 | + state.putAll(values); | ||
| 273 | if (state.size() > MAX_PROPERTY_COUNT) { | 291 | if (state.size() > MAX_PROPERTY_COUNT) { |
| 274 | throw exception(DEVICE_SHADOW_PROPERTY_COUNT_EXCEEDED); | 292 | throw exception(DEVICE_SHADOW_PROPERTY_COUNT_EXCEEDED); |
| 275 | } | 293 | } |
| 276 | // 2.2 记录属性的更新时间 | 294 | // 2.2 记录属性的更新时间 |
| 277 | long now = DateUtil.currentSeconds(); | 295 | long now = DateUtil.currentSeconds(); |
| 278 | - Map<String, Object> metadata = mergeMap(latest.getMetadata(), null); | 296 | + Map<String, Object> metadata = new HashMap<>(MapUtil.emptyIfNull(latest.getMetadata())); |
| 279 | if (desired) { | 297 | if (desired) { |
| 280 | IotDeviceShadowProtocolUtils.putDesiredTimestamps(metadata, values.keySet(), now); | 298 | IotDeviceShadowProtocolUtils.putDesiredTimestamps(metadata, values.keySet(), now); |
| 281 | } else { | 299 | } else { |
| @@ -338,6 +356,9 @@ public class IotDeviceShadowServiceImpl implements IotDeviceShadowService { | @@ -338,6 +356,9 @@ public class IotDeviceShadowServiceImpl implements IotDeviceShadowService { | ||
| 338 | }); | 356 | }); |
| 339 | } | 357 | } |
| 340 | 358 | ||
| 359 | + /** | ||
| 360 | + * 回复全量影子:设备 get 请求的回复,或 desired 更新后的主动推送(requestId 为空) | ||
| 361 | + */ | ||
| 341 | private void sendShadowGetReply(IotDeviceDO device, String serverId, String requestId, IotDeviceShadowDO shadow) { | 362 | private void sendShadowGetReply(IotDeviceDO device, String serverId, String requestId, IotDeviceShadowDO shadow) { |
| 342 | sendShadowReply(device, serverId, requestId, SUCCESS.getCode(), SUCCESS.getMsg(), | 363 | sendShadowReply(device, serverId, requestId, SUCCESS.getCode(), SUCCESS.getMsg(), |
| 343 | IotDeviceShadowProtocolUtils.buildGetData(shadow.getDesired(), shadow.getReported(), | 364 | IotDeviceShadowProtocolUtils.buildGetData(shadow.getDesired(), shadow.getReported(), |
| @@ -381,12 +402,4 @@ public class IotDeviceShadowServiceImpl implements IotDeviceShadowService { | @@ -381,12 +402,4 @@ public class IotDeviceShadowServiceImpl implements IotDeviceShadowService { | ||
| 381 | } | 402 | } |
| 382 | } | 403 | } |
| 383 | 404 | ||
| 384 | - private static Map<String, Object> mergeMap(Map<String, Object> oldMap, Map<String, Object> newMap) { | ||
| 385 | - Map<String, Object> result = oldMap != null ? new HashMap<>(oldMap) : new HashMap<>(); | ||
| 386 | - if (CollUtil.isNotEmpty(newMap)) { | ||
| 387 | - result.putAll(newMap); | ||
| 388 | - } | ||
| 389 | - return result; | ||
| 390 | - } | ||
| 391 | - | ||
| 392 | } | 405 | } |
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/util/IotDeviceShadowProtocolUtils.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.map.MapUtil; | 3 | import cn.hutool.core.map.MapUtil; |
| 4 | +import lombok.experimental.UtilityClass; | ||
| 4 | 5 | ||
| 5 | import java.util.HashMap; | 6 | import java.util.HashMap; |
| 6 | import java.util.Map; | 7 | import java.util.Map; |
| @@ -13,11 +14,9 @@ import java.util.Set; | @@ -13,11 +14,9 @@ import java.util.Set; | ||
| 13 | * | 14 | * |
| 14 | * @author 芋道源码 | 15 | * @author 芋道源码 |
| 15 | */ | 16 | */ |
| 17 | +@UtilityClass | ||
| 16 | public final class IotDeviceShadowProtocolUtils { | 18 | public final class IotDeviceShadowProtocolUtils { |
| 17 | 19 | ||
| 18 | - private IotDeviceShadowProtocolUtils() { | ||
| 19 | - } | ||
| 20 | - | ||
| 21 | // ========== 内层 method(上行 params.method) ========== | 20 | // ========== 内层 method(上行 params.method) ========== |
| 22 | 21 | ||
| 23 | public static final String INNER_METHOD_GET = "get"; | 22 | public static final String INNER_METHOD_GET = "get"; |