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 | 57 | public CommonResult<IotDeviceShadowRespVO> getDeviceShadow(@RequestParam("deviceId") Long deviceId) { |
| 58 | 58 | IotDeviceDO device = deviceService.validateDeviceExists(deviceId); |
| 59 | 59 | IotDeviceShadowDO shadow = deviceShadowService.getOrCreateShadow(device); |
| 60 | - | |
| 60 | + // 拼接 VO | |
| 61 | 61 | List<IotThingModelDO> thingModels = thingModelService.getThingModelListByProductIdAndType( |
| 62 | 62 | device.getProductId(), IotThingModelTypeEnum.PROPERTY.getType()); |
| 63 | 63 | Map<String, Object> desired = shadow.getDesired() != null ? shadow.getDesired() : MapUtil.empty(); |
| 64 | 64 | Map<String, Object> reported = shadow.getReported() != null ? shadow.getReported() : MapUtil.empty(); |
| 65 | 65 | Map<String, Object> metadata = shadow.getMetadata() != null ? shadow.getMetadata() : MapUtil.empty(); |
| 66 | - // 拼接 VO | |
| 67 | 66 | List<IotDeviceShadowPropertyRespVO> properties = convertList(thingModels, thingModel -> { |
| 68 | 67 | ThingModelProperty prop = thingModel.getProperty(); |
| 69 | 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 | 72 | .setDesiredTime(IotDeviceShadowProtocolUtils.getDesiredTimestamp(metadata, thingModel.getIdentifier())) |
| 77 | 73 | .setReportedTime(IotDeviceShadowProtocolUtils.getReportedTimestamp(metadata, thingModel.getIdentifier())); |
| 78 | 74 | }); |
| 79 | - | |
| 80 | 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 | 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 | 21 | @Schema(description = "最后更新时间(epoch 秒)", example = "1469564576") |
| 22 | 22 | private Long shadowTime; |
| 23 | 23 | |
| 24 | - @Schema(description = "是否启用", example = "0") | |
| 24 | + @Schema(description = "影子状态", example = "0") | |
| 25 | 25 | private Integer status; |
| 26 | 26 | |
| 27 | 27 | @Schema(description = "属性对比列表") | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceShadowDO.java
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 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | 4 | import cn.hutool.core.date.DateUtil; |
| 5 | 5 | import cn.hutool.core.lang.Assert; |
| 6 | +import cn.hutool.core.map.MapUtil; | |
| 6 | 7 | import cn.hutool.core.util.ObjUtil; |
| 7 | 8 | import cn.hutool.core.util.StrUtil; |
| 8 | 9 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| ... | ... | @@ -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 | 108 | private void handleDeviceShadowUpdate0(IotDeviceDO device, IotDeviceMessage message) { |
| 100 | 109 | // 1.1 解析请求:params 结构为 { method, state: { reported }, version } |
| 101 | 110 | IotDeviceShadowUpdateReqDTO reqDTO = JsonUtils.convertObject(message.getParams(), |
| ... | ... | @@ -125,6 +134,14 @@ public class IotDeviceShadowServiceImpl implements IotDeviceShadowService { |
| 125 | 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 | 145 | private void handleReportedUpdate(IotDeviceDO device, IotDeviceMessage message, |
| 129 | 146 | IotDeviceShadowUpdateReqDTO reqDTO, IotDeviceShadowDO shadow) { |
| 130 | 147 | // 1. version 为 -1 时,清空影子,无需 state |
| ... | ... | @@ -269,13 +286,14 @@ public class IotDeviceShadowServiceImpl implements IotDeviceShadowService { |
| 269 | 286 | } |
| 270 | 287 | |
| 271 | 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 | 291 | if (state.size() > MAX_PROPERTY_COUNT) { |
| 274 | 292 | throw exception(DEVICE_SHADOW_PROPERTY_COUNT_EXCEEDED); |
| 275 | 293 | } |
| 276 | 294 | // 2.2 记录属性的更新时间 |
| 277 | 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 | 297 | if (desired) { |
| 280 | 298 | IotDeviceShadowProtocolUtils.putDesiredTimestamps(metadata, values.keySet(), now); |
| 281 | 299 | } else { |
| ... | ... | @@ -338,6 +356,9 @@ public class IotDeviceShadowServiceImpl implements IotDeviceShadowService { |
| 338 | 356 | }); |
| 339 | 357 | } |
| 340 | 358 | |
| 359 | + /** | |
| 360 | + * 回复全量影子:设备 get 请求的回复,或 desired 更新后的主动推送(requestId 为空) | |
| 361 | + */ | |
| 341 | 362 | private void sendShadowGetReply(IotDeviceDO device, String serverId, String requestId, IotDeviceShadowDO shadow) { |
| 342 | 363 | sendShadowReply(device, serverId, requestId, SUCCESS.getCode(), SUCCESS.getMsg(), |
| 343 | 364 | IotDeviceShadowProtocolUtils.buildGetData(shadow.getDesired(), shadow.getReported(), |
| ... | ... | @@ -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 | 1 | package cn.iocoder.yudao.module.iot.core.util; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.map.MapUtil; |
| 4 | +import lombok.experimental.UtilityClass; | |
| 4 | 5 | |
| 5 | 6 | import java.util.HashMap; |
| 6 | 7 | import java.util.Map; |
| ... | ... | @@ -13,11 +14,9 @@ import java.util.Set; |
| 13 | 14 | * |
| 14 | 15 | * @author 芋道源码 |
| 15 | 16 | */ |
| 17 | +@UtilityClass | |
| 16 | 18 | public final class IotDeviceShadowProtocolUtils { |
| 17 | 19 | |
| 18 | - private IotDeviceShadowProtocolUtils() { | |
| 19 | - } | |
| 20 | - | |
| 21 | 20 | // ========== 内层 method(上行 params.method) ========== |
| 22 | 21 | |
| 23 | 22 | public static final String INNER_METHOD_GET = "get"; | ... | ... |