Commit 348c138749cbdc3a6dd874098ec1a1a46b2216e9
1 parent
34453a3f
【功能完善】IoT:引入 IotStandardResponse 实体类,统一处理器的响应格式,优化错误处理逻辑
Showing
12 changed files
with
412 additions
and
88 deletions
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceConfigSetVertxHandler.java
| ... | ... | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.plugin.common.downstream.router; |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | 4 | import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceConfigSetReqDTO; |
| 5 | 5 | import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; |
| 6 | +import cn.iocoder.yudao.module.iot.plugin.common.pojo.IotStandardResponse; | |
| 6 | 7 | import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; |
| 7 | 8 | import io.vertx.core.Handler; |
| 8 | 9 | import io.vertx.core.json.JsonObject; |
| ... | ... | @@ -25,6 +26,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC |
| 25 | 26 | public class IotDeviceConfigSetVertxHandler implements Handler<RoutingContext> { |
| 26 | 27 | |
| 27 | 28 | public static final String PATH = "/sys/:productKey/:deviceName/thing/service/config/set"; |
| 29 | + public static final String METHOD = "thing.service.config.set"; | |
| 28 | 30 | |
| 29 | 31 | private final IotDeviceDownstreamHandler deviceDownstreamHandler; |
| 30 | 32 | |
| ... | ... | @@ -44,17 +46,32 @@ public class IotDeviceConfigSetVertxHandler implements Handler<RoutingContext> { |
| 44 | 46 | .setConfig(config); |
| 45 | 47 | } catch (Exception e) { |
| 46 | 48 | log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); |
| 47 | - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST)); | |
| 49 | + // 使用IotStandardResponse实体类返回错误 | |
| 50 | + IotStandardResponse errorResponse = IotStandardResponse.error( | |
| 51 | + null, METHOD, BAD_REQUEST.getCode(), BAD_REQUEST.getMsg()); | |
| 52 | + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); | |
| 48 | 53 | return; |
| 49 | 54 | } |
| 50 | 55 | |
| 51 | 56 | // 2. 调用处理器 |
| 52 | 57 | try { |
| 53 | 58 | CommonResult<Boolean> result = deviceDownstreamHandler.setDeviceConfig(reqDTO); |
| 54 | - IotPluginCommonUtils.writeJson(routingContext, result); | |
| 59 | + | |
| 60 | + // 使用IotStandardResponse实体类返回结果 | |
| 61 | + IotStandardResponse response; | |
| 62 | + if (result.isSuccess()) { | |
| 63 | + response = IotStandardResponse.success(reqDTO.getRequestId(), METHOD, result.getData()); | |
| 64 | + } else { | |
| 65 | + response = IotStandardResponse.error( | |
| 66 | + reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); | |
| 67 | + } | |
| 68 | + IotPluginCommonUtils.writeJsonResponse(routingContext, response); | |
| 55 | 69 | } catch (Exception e) { |
| 56 | 70 | log.error("[handle][请求参数({}) 配置设置异常]", reqDTO, e); |
| 57 | - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR)); | |
| 71 | + // 使用IotStandardResponse实体类返回错误 | |
| 72 | + IotStandardResponse errorResponse = IotStandardResponse.error( | |
| 73 | + reqDTO.getRequestId(), METHOD, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); | |
| 74 | + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); | |
| 58 | 75 | } |
| 59 | 76 | } |
| 60 | 77 | ... | ... |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceOtaUpgradeVertxHandler.java
| ... | ... | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.plugin.common.downstream.router; |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | 4 | import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceOtaUpgradeReqDTO; |
| 5 | 5 | import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; |
| 6 | +import cn.iocoder.yudao.module.iot.plugin.common.pojo.IotStandardResponse; | |
| 6 | 7 | import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; |
| 7 | 8 | import io.vertx.core.Handler; |
| 8 | 9 | import io.vertx.core.json.JsonObject; |
| ... | ... | @@ -23,6 +24,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC |
| 23 | 24 | public class IotDeviceOtaUpgradeVertxHandler implements Handler<RoutingContext> { |
| 24 | 25 | |
| 25 | 26 | public static final String PATH = "/ota/:productKey/:deviceName/upgrade"; |
| 27 | + public static final String METHOD = "ota.device.upgrade"; | |
| 26 | 28 | |
| 27 | 29 | private final IotDeviceDownstreamHandler deviceDownstreamHandler; |
| 28 | 30 | |
| ... | ... | @@ -49,17 +51,32 @@ public class IotDeviceOtaUpgradeVertxHandler implements Handler<RoutingContext> |
| 49 | 51 | .setInformation(information); |
| 50 | 52 | } catch (Exception e) { |
| 51 | 53 | log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); |
| 52 | - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST)); | |
| 54 | + // 使用IotStandardResponse实体类返回错误 | |
| 55 | + IotStandardResponse errorResponse = IotStandardResponse.error( | |
| 56 | + null, METHOD, BAD_REQUEST.getCode(), BAD_REQUEST.getMsg()); | |
| 57 | + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); | |
| 53 | 58 | return; |
| 54 | 59 | } |
| 55 | 60 | |
| 56 | 61 | // 2. 调用处理器 |
| 57 | 62 | try { |
| 58 | 63 | CommonResult<Boolean> result = deviceDownstreamHandler.upgradeDeviceOta(reqDTO); |
| 59 | - IotPluginCommonUtils.writeJson(routingContext, result); | |
| 64 | + | |
| 65 | + // 使用IotStandardResponse实体类返回结果 | |
| 66 | + IotStandardResponse response; | |
| 67 | + if (result.isSuccess()) { | |
| 68 | + response = IotStandardResponse.success(reqDTO.getRequestId(), METHOD, result.getData()); | |
| 69 | + } else { | |
| 70 | + response = IotStandardResponse.error( | |
| 71 | + reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); | |
| 72 | + } | |
| 73 | + IotPluginCommonUtils.writeJsonResponse(routingContext, response); | |
| 60 | 74 | } catch (Exception e) { |
| 61 | 75 | log.error("[handle][请求参数({}) OTA 升级异常]", reqDTO, e); |
| 62 | - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR)); | |
| 76 | + // 使用IotStandardResponse实体类返回错误 | |
| 77 | + IotStandardResponse errorResponse = IotStandardResponse.error( | |
| 78 | + reqDTO.getRequestId(), METHOD, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); | |
| 79 | + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); | |
| 63 | 80 | } |
| 64 | 81 | } |
| 65 | 82 | } | ... | ... |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertyGetVertxHandler.java
| ... | ... | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.plugin.common.downstream.router; |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | 4 | import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertyGetReqDTO; |
| 5 | 5 | import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; |
| 6 | +import cn.iocoder.yudao.module.iot.plugin.common.pojo.IotStandardResponse; | |
| 6 | 7 | import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; |
| 7 | 8 | import io.vertx.core.Handler; |
| 8 | 9 | import io.vertx.core.json.JsonObject; |
| ... | ... | @@ -25,6 +26,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC |
| 25 | 26 | public class IotDevicePropertyGetVertxHandler implements Handler<RoutingContext> { |
| 26 | 27 | |
| 27 | 28 | public static final String PATH = "/sys/:productKey/:deviceName/thing/service/property/get"; |
| 29 | + public static final String METHOD = "thing.service.property.get"; | |
| 28 | 30 | |
| 29 | 31 | private final IotDeviceDownstreamHandler deviceDownstreamHandler; |
| 30 | 32 | |
| ... | ... | @@ -44,17 +46,32 @@ public class IotDevicePropertyGetVertxHandler implements Handler<RoutingContext> |
| 44 | 46 | .setIdentifiers(identifiers); |
| 45 | 47 | } catch (Exception e) { |
| 46 | 48 | log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); |
| 47 | - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST)); | |
| 49 | + // 使用IotStandardResponse实体类返回错误 | |
| 50 | + IotStandardResponse errorResponse = IotStandardResponse.error( | |
| 51 | + null, METHOD, BAD_REQUEST.getCode(), BAD_REQUEST.getMsg()); | |
| 52 | + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); | |
| 48 | 53 | return; |
| 49 | 54 | } |
| 50 | 55 | |
| 51 | 56 | // 2. 调用处理器 |
| 52 | 57 | try { |
| 53 | 58 | CommonResult<Boolean> result = deviceDownstreamHandler.getDeviceProperty(reqDTO); |
| 54 | - IotPluginCommonUtils.writeJson(routingContext, result); | |
| 59 | + | |
| 60 | + // 使用IotStandardResponse实体类返回结果 | |
| 61 | + IotStandardResponse response; | |
| 62 | + if (result.isSuccess()) { | |
| 63 | + response = IotStandardResponse.success(reqDTO.getRequestId(), METHOD, result.getData()); | |
| 64 | + } else { | |
| 65 | + response = IotStandardResponse.error( | |
| 66 | + reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); | |
| 67 | + } | |
| 68 | + IotPluginCommonUtils.writeJsonResponse(routingContext, response); | |
| 55 | 69 | } catch (Exception e) { |
| 56 | 70 | log.error("[handle][请求参数({}) 属性获取异常]", reqDTO, e); |
| 57 | - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR)); | |
| 71 | + // 使用IotStandardResponse实体类返回错误 | |
| 72 | + IotStandardResponse errorResponse = IotStandardResponse.error( | |
| 73 | + reqDTO.getRequestId(), METHOD, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); | |
| 74 | + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); | |
| 58 | 75 | } |
| 59 | 76 | } |
| 60 | 77 | ... | ... |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertySetVertxHandler.java
| ... | ... | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.plugin.common.downstream.router; |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | 4 | import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertySetReqDTO; |
| 5 | 5 | import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; |
| 6 | +import cn.iocoder.yudao.module.iot.plugin.common.pojo.IotStandardResponse; | |
| 6 | 7 | import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; |
| 7 | 8 | import io.vertx.core.Handler; |
| 8 | 9 | import io.vertx.core.json.JsonObject; |
| ... | ... | @@ -25,6 +26,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC |
| 25 | 26 | public class IotDevicePropertySetVertxHandler implements Handler<RoutingContext> { |
| 26 | 27 | |
| 27 | 28 | public static final String PATH = "/sys/:productKey/:deviceName/thing/service/property/set"; |
| 29 | + public static final String METHOD = "thing.service.property.set"; | |
| 28 | 30 | |
| 29 | 31 | private final IotDeviceDownstreamHandler deviceDownstreamHandler; |
| 30 | 32 | |
| ... | ... | @@ -44,17 +46,32 @@ public class IotDevicePropertySetVertxHandler implements Handler<RoutingContext> |
| 44 | 46 | .setProperties(properties); |
| 45 | 47 | } catch (Exception e) { |
| 46 | 48 | log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); |
| 47 | - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST)); | |
| 49 | + // 使用IotStandardResponse实体类返回错误 | |
| 50 | + IotStandardResponse errorResponse = IotStandardResponse.error( | |
| 51 | + null, METHOD, BAD_REQUEST.getCode(), BAD_REQUEST.getMsg()); | |
| 52 | + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); | |
| 48 | 53 | return; |
| 49 | 54 | } |
| 50 | 55 | |
| 51 | 56 | // 2. 调用处理器 |
| 52 | 57 | try { |
| 53 | 58 | CommonResult<Boolean> result = deviceDownstreamHandler.setDeviceProperty(reqDTO); |
| 54 | - IotPluginCommonUtils.writeJson(routingContext, result); | |
| 59 | + | |
| 60 | + // 使用IotStandardResponse实体类返回结果 | |
| 61 | + IotStandardResponse response; | |
| 62 | + if (result.isSuccess()) { | |
| 63 | + response = IotStandardResponse.success(reqDTO.getRequestId(), METHOD, result.getData()); | |
| 64 | + } else { | |
| 65 | + response = IotStandardResponse.error( | |
| 66 | + reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); | |
| 67 | + } | |
| 68 | + IotPluginCommonUtils.writeJsonResponse(routingContext, response); | |
| 55 | 69 | } catch (Exception e) { |
| 56 | 70 | log.error("[handle][请求参数({}) 属性设置异常]", reqDTO, e); |
| 57 | - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR)); | |
| 71 | + // 使用IotStandardResponse实体类返回错误 | |
| 72 | + IotStandardResponse errorResponse = IotStandardResponse.error( | |
| 73 | + reqDTO.getRequestId(), METHOD, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); | |
| 74 | + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); | |
| 58 | 75 | } |
| 59 | 76 | } |
| 60 | 77 | ... | ... |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java
| ... | ... | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.plugin.common.downstream.router; |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | 4 | import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceServiceInvokeReqDTO; |
| 5 | 5 | import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; |
| 6 | +import cn.iocoder.yudao.module.iot.plugin.common.pojo.IotStandardResponse; | |
| 6 | 7 | import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; |
| 7 | 8 | import io.vertx.core.Handler; |
| 8 | 9 | import io.vertx.core.json.JsonObject; |
| ... | ... | @@ -25,6 +26,8 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC |
| 25 | 26 | public class IotDeviceServiceInvokeVertxHandler implements Handler<RoutingContext> { |
| 26 | 27 | |
| 27 | 28 | public static final String PATH = "/sys/:productKey/:deviceName/thing/service/:identifier"; |
| 29 | + public static final String METHOD_PREFIX = "thing.service."; | |
| 30 | + public static final String METHOD_SUFFIX = ""; | |
| 28 | 31 | |
| 29 | 32 | private final IotDeviceDownstreamHandler deviceDownstreamHandler; |
| 30 | 33 | |
| ... | ... | @@ -45,17 +48,35 @@ public class IotDeviceServiceInvokeVertxHandler implements Handler<RoutingContex |
| 45 | 48 | .setIdentifier(identifier).setParams(params); |
| 46 | 49 | } catch (Exception e) { |
| 47 | 50 | log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); |
| 48 | - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST)); | |
| 51 | + // 使用IotStandardResponse实体类返回错误 | |
| 52 | + String method = METHOD_PREFIX + routingContext.pathParam("identifier") + METHOD_SUFFIX; | |
| 53 | + IotStandardResponse errorResponse = IotStandardResponse.error( | |
| 54 | + null, method, BAD_REQUEST.getCode(), BAD_REQUEST.getMsg()); | |
| 55 | + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); | |
| 49 | 56 | return; |
| 50 | 57 | } |
| 51 | 58 | |
| 52 | 59 | // 2. 调用处理器 |
| 53 | 60 | try { |
| 54 | 61 | CommonResult<Boolean> result = deviceDownstreamHandler.invokeDeviceService(reqDTO); |
| 55 | - IotPluginCommonUtils.writeJson(routingContext, result); | |
| 62 | + | |
| 63 | + // 使用IotStandardResponse实体类返回结果 | |
| 64 | + String method = METHOD_PREFIX + reqDTO.getIdentifier() + METHOD_SUFFIX; | |
| 65 | + IotStandardResponse response; | |
| 66 | + if (result.isSuccess()) { | |
| 67 | + response = IotStandardResponse.success(reqDTO.getRequestId(), method, result.getData()); | |
| 68 | + } else { | |
| 69 | + response = IotStandardResponse.error( | |
| 70 | + reqDTO.getRequestId(), method, result.getCode(), result.getMsg()); | |
| 71 | + } | |
| 72 | + IotPluginCommonUtils.writeJsonResponse(routingContext, response); | |
| 56 | 73 | } catch (Exception e) { |
| 57 | 74 | log.error("[handle][请求参数({}) 服务调用异常]", reqDTO, e); |
| 58 | - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR)); | |
| 75 | + // 使用IotStandardResponse实体类返回错误 | |
| 76 | + String method = METHOD_PREFIX + reqDTO.getIdentifier() + METHOD_SUFFIX; | |
| 77 | + IotStandardResponse errorResponse = IotStandardResponse.error( | |
| 78 | + reqDTO.getRequestId(), method, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); | |
| 79 | + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); | |
| 59 | 80 | } |
| 60 | 81 | } |
| 61 | 82 | ... | ... |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/pojo/IotStandardResponse.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.plugin.common.pojo; | |
| 2 | + | |
| 3 | +import lombok.Data; | |
| 4 | +import lombok.experimental.Accessors; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * IoT 标准协议响应实体类 | |
| 8 | + * <p> | |
| 9 | + * 用于统一 MQTT 和 HTTP 的响应格式 | |
| 10 | + * | |
| 11 | + * @author haohao | |
| 12 | + */ | |
| 13 | +@Data | |
| 14 | +@Accessors(chain = true) | |
| 15 | +public class IotStandardResponse { | |
| 16 | + | |
| 17 | + /** | |
| 18 | + * 消息ID | |
| 19 | + */ | |
| 20 | + private String id; | |
| 21 | + | |
| 22 | + /** | |
| 23 | + * 状态码 | |
| 24 | + */ | |
| 25 | + private Integer code; | |
| 26 | + | |
| 27 | + /** | |
| 28 | + * 响应数据 | |
| 29 | + */ | |
| 30 | + private Object data; | |
| 31 | + | |
| 32 | + /** | |
| 33 | + * 响应消息 | |
| 34 | + */ | |
| 35 | + private String message; | |
| 36 | + | |
| 37 | + /** | |
| 38 | + * 方法名 | |
| 39 | + */ | |
| 40 | + private String method; | |
| 41 | + | |
| 42 | + /** | |
| 43 | + * 协议版本 | |
| 44 | + */ | |
| 45 | + private String version; | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * 创建成功响应 | |
| 49 | + * | |
| 50 | + * @param id 消息ID | |
| 51 | + * @param method 方法名 | |
| 52 | + * @return 成功响应 | |
| 53 | + */ | |
| 54 | + public static IotStandardResponse success(String id, String method) { | |
| 55 | + return success(id, method, null); | |
| 56 | + } | |
| 57 | + | |
| 58 | + /** | |
| 59 | + * 创建成功响应 | |
| 60 | + * | |
| 61 | + * @param id 消息ID | |
| 62 | + * @param method 方法名 | |
| 63 | + * @param data 响应数据 | |
| 64 | + * @return 成功响应 | |
| 65 | + */ | |
| 66 | + public static IotStandardResponse success(String id, String method, Object data) { | |
| 67 | + return new IotStandardResponse() | |
| 68 | + .setId(id) | |
| 69 | + .setCode(200) | |
| 70 | + .setData(data) | |
| 71 | + .setMessage("success") | |
| 72 | + .setMethod(method) | |
| 73 | + .setVersion("1.0"); | |
| 74 | + } | |
| 75 | + | |
| 76 | + /** | |
| 77 | + * 创建错误响应 | |
| 78 | + * | |
| 79 | + * @param id 消息ID | |
| 80 | + * @param method 方法名 | |
| 81 | + * @param code 错误码 | |
| 82 | + * @param message 错误消息 | |
| 83 | + * @return 错误响应 | |
| 84 | + */ | |
| 85 | + public static IotStandardResponse error(String id, String method, Integer code, String message) { | |
| 86 | + return new IotStandardResponse() | |
| 87 | + .setId(id) | |
| 88 | + .setCode(code) | |
| 89 | + .setData(null) | |
| 90 | + .setMessage(message) | |
| 91 | + .setMethod(method) | |
| 92 | + .setVersion("1.0"); | |
| 93 | + } | |
| 94 | +} | |
| 0 | 95 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java
| ... | ... | @@ -3,8 +3,8 @@ package cn.iocoder.yudao.module.iot.plugin.common.util; |
| 3 | 3 | import cn.hutool.core.util.IdUtil; |
| 4 | 4 | import cn.hutool.core.util.StrUtil; |
| 5 | 5 | import cn.hutool.system.SystemUtil; |
| 6 | -import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 7 | 6 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 7 | +import cn.iocoder.yudao.module.iot.plugin.common.pojo.IotStandardResponse; | |
| 8 | 8 | import io.vertx.core.http.HttpHeaders; |
| 9 | 9 | import io.vertx.ext.web.RoutingContext; |
| 10 | 10 | import org.springframework.http.MediaType; |
| ... | ... | @@ -12,7 +12,7 @@ import org.springframework.http.MediaType; |
| 12 | 12 | /** |
| 13 | 13 | * IoT 插件的通用工具类 |
| 14 | 14 | * |
| 15 | - * 芋道源码 | |
| 15 | + * @author 芋道源码 | |
| 16 | 16 | */ |
| 17 | 17 | public class IotPluginCommonUtils { |
| 18 | 18 | |
| ... | ... | @@ -33,34 +33,43 @@ public class IotPluginCommonUtils { |
| 33 | 33 | SystemUtil.getHostInfo().getAddress(), SystemUtil.getCurrentPID(), IdUtil.fastSimpleUUID()); |
| 34 | 34 | } |
| 35 | 35 | |
| 36 | + /** | |
| 37 | + * 将对象转换为JSON字符串后写入HTTP响应 | |
| 38 | + * | |
| 39 | + * @param routingContext 路由上下文 | |
| 40 | + * @param data 数据对象 | |
| 41 | + */ | |
| 36 | 42 | @SuppressWarnings("deprecation") |
| 37 | - public static void writeJson(RoutingContext routingContext, CommonResult<?> result) { | |
| 38 | - routingContext.response() | |
| 39 | - .setStatusCode(200) | |
| 40 | - .putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) | |
| 41 | - .end(JsonUtils.toJsonString(result)); | |
| 42 | - } | |
| 43 | - | |
| 44 | - @SuppressWarnings("deprecation") | |
| 45 | - public static void writeJson(RoutingContext routingContext, String result) { | |
| 43 | + public static void writeJsonResponse(RoutingContext routingContext, Object data) { | |
| 46 | 44 | routingContext.response() |
| 47 | 45 | .setStatusCode(200) |
| 48 | 46 | .putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) |
| 49 | - .end(result); | |
| 47 | + .end(JsonUtils.toJsonString(data)); | |
| 50 | 48 | } |
| 51 | 49 | |
| 52 | 50 | /** |
| 53 | - * 将对象转换为 JSON 字符串后写入响应 | |
| 51 | + * 生成标准JSON格式的响应并写入HTTP响应(基于IotStandardResponse) | |
| 52 | + * <p> | |
| 53 | + * 推荐使用此方法,统一MQTT和HTTP的响应格式。使用方式: | |
| 54 | + * | |
| 55 | + * <pre> | |
| 56 | + * // 成功响应 | |
| 57 | + * IotStandardResponse response = IotStandardResponse.success(requestId, method, data); | |
| 58 | + * IotPluginCommonUtils.writeJsonResponse(routingContext, response); | |
| 59 | + * | |
| 60 | + * // 错误响应 | |
| 61 | + * IotStandardResponse errorResponse = IotStandardResponse.error(requestId, method, code, message); | |
| 62 | + * IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); | |
| 63 | + * </pre> | |
| 54 | 64 | * |
| 55 | 65 | * @param routingContext 路由上下文 |
| 56 | - * @param data 数据对象 | |
| 66 | + * @param response IotStandardResponse响应对象 | |
| 57 | 67 | */ |
| 58 | 68 | @SuppressWarnings("deprecation") |
| 59 | - public static void writeJson(RoutingContext routingContext, Object data) { | |
| 69 | + public static void writeJsonResponse(RoutingContext routingContext, IotStandardResponse response) { | |
| 60 | 70 | routingContext.response() |
| 61 | 71 | .setStatusCode(200) |
| 62 | 72 | .putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) |
| 63 | - .end(JsonUtils.toJsonString(data)); | |
| 73 | + .end(JsonUtils.toJsonString(response)); | |
| 64 | 74 | } |
| 65 | - | |
| 66 | 75 | } | ... | ... |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java
| ... | ... | @@ -14,7 +14,12 @@ import java.util.Collections; |
| 14 | 14 | |
| 15 | 15 | /** |
| 16 | 16 | * IoT Emqx 连接认证的 Vert.x Handler |
| 17 | - * <a href="https://docs.emqx.com/zh/emqx/latest/access-control/authn/http.html">MQTT HTTP</a> | |
| 17 | + * <a href= | |
| 18 | + * "https://docs.emqx.com/zh/emqx/latest/access-control/authn/http.html">MQTT | |
| 19 | + * HTTP</a> | |
| 20 | + * | |
| 21 | + * 注意:该处理器需要返回特定格式:{"result": "allow"} 或 {"result": "deny"}, | |
| 22 | + * 以符合 EMQX 认证插件的要求,因此不使用 IotStandardResponse 实体类。 | |
| 18 | 23 | * |
| 19 | 24 | * @author haohao |
| 20 | 25 | */ |
| ... | ... | @@ -43,15 +48,18 @@ public class IotDeviceAuthVertxHandler implements Handler<RoutingContext> { |
| 43 | 48 | // 调用认证 API |
| 44 | 49 | CommonResult<Boolean> authResult = deviceUpstreamApi.authenticateEmqxConnection(authReqDTO); |
| 45 | 50 | if (authResult.getCode() != 0 || !authResult.getData()) { |
| 46 | - IotPluginCommonUtils.writeJson(routingContext, Collections.singletonMap("result", "deny")); | |
| 51 | + // 注意:这里必须返回 {"result": "deny"} 格式,以符合 EMQX 认证插件的要求 | |
| 52 | + IotPluginCommonUtils.writeJsonResponse(routingContext, Collections.singletonMap("result", "deny")); | |
| 47 | 53 | return; |
| 48 | 54 | } |
| 49 | 55 | |
| 50 | 56 | // 响应结果 |
| 51 | - IotPluginCommonUtils.writeJson(routingContext, Collections.singletonMap("result", "allow")); | |
| 57 | + // 注意:这里必须返回 {"result": "allow"} 格式,以符合 EMQX 认证插件的要求 | |
| 58 | + IotPluginCommonUtils.writeJsonResponse(routingContext, Collections.singletonMap("result", "allow")); | |
| 52 | 59 | } catch (Exception e) { |
| 53 | 60 | log.error("[handle][EMQX 认证异常]", e); |
| 54 | - IotPluginCommonUtils.writeJson(routingContext, Collections.singletonMap("result", "deny")); | |
| 61 | + // 注意:这里必须返回 {"result": "deny"} 格式,以符合 EMQX 认证插件的要求 | |
| 62 | + IotPluginCommonUtils.writeJsonResponse(routingContext, Collections.singletonMap("result", "deny")); | |
| 55 | 63 | } |
| 56 | 64 | } |
| 57 | 65 | ... | ... |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java
| ... | ... | @@ -2,9 +2,11 @@ package cn.iocoder.yudao.module.iot.plugin.emqx.upstream.router; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.json.JSONObject; |
| 4 | 4 | import cn.hutool.json.JSONUtil; |
| 5 | +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | |
| 5 | 6 | import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; |
| 6 | 7 | import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceEventReportReqDTO; |
| 7 | 8 | import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; |
| 9 | +import cn.iocoder.yudao.module.iot.plugin.common.pojo.IotStandardResponse; | |
| 8 | 10 | import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; |
| 9 | 11 | import io.netty.handler.codec.mqtt.MqttQoS; |
| 10 | 12 | import io.vertx.core.buffer.Buffer; |
| ... | ... | @@ -14,6 +16,8 @@ import lombok.extern.slf4j.Slf4j; |
| 14 | 16 | |
| 15 | 17 | import java.time.LocalDateTime; |
| 16 | 18 | import java.util.Arrays; |
| 19 | +import java.util.HashMap; | |
| 20 | +import java.util.Map; | |
| 17 | 21 | |
| 18 | 22 | /** |
| 19 | 23 | * IoT 设备 MQTT 消息处理器 |
| ... | ... | @@ -32,16 +36,16 @@ public class IotDeviceMqttMessageHandler { |
| 32 | 36 | // 响应 Topic:/sys/${productKey}/${deviceName}/thing/event/property/post_reply |
| 33 | 37 | |
| 34 | 38 | // 设备上报事件 标准 JSON |
| 35 | - // 请求 Topic:/sys/${productKey}/${deviceName}/thing/event/${tsl.event.identifier}/post | |
| 36 | - // 响应 Topic:/sys/${productKey}/${deviceName}/thing/event/${tsl.event.identifier}/post_reply | |
| 39 | + // 请求 | |
| 40 | + // Topic:/sys/${productKey}/${deviceName}/thing/event/${tsl.event.identifier}/post | |
| 41 | + // 响应 | |
| 42 | + // Topic:/sys/${productKey}/${deviceName}/thing/event/${tsl.event.identifier}/post_reply | |
| 37 | 43 | |
| 38 | 44 | private static final String SYS_TOPIC_PREFIX = "/sys/"; |
| 39 | 45 | private static final String PROPERTY_POST_TOPIC = "/thing/event/property/post"; |
| 40 | 46 | private static final String EVENT_POST_TOPIC_PREFIX = "/thing/event/"; |
| 41 | 47 | private static final String EVENT_POST_TOPIC_SUFFIX = "/post"; |
| 42 | 48 | private static final String REPLY_SUFFIX = "_reply"; |
| 43 | - private static final int SUCCESS_CODE = 200; | |
| 44 | - private static final String SUCCESS_MESSAGE = "success"; | |
| 45 | 49 | private static final String PROPERTY_METHOD = "thing.event.property.post"; |
| 46 | 50 | private static final String EVENT_METHOD_PREFIX = "thing.event."; |
| 47 | 51 | private static final String EVENT_METHOD_SUFFIX = ".post"; |
| ... | ... | @@ -211,27 +215,25 @@ public class IotDeviceMqttMessageHandler { |
| 211 | 215 | * @param method 响应方法 |
| 212 | 216 | * @param customData 自定义数据,可为null |
| 213 | 217 | */ |
| 214 | - private void sendResponse(String topic, JSONObject jsonObject, String method, JSONObject customData) { | |
| 218 | + private void sendResponse(String topic, JSONObject jsonObject, String method, Object customData) { | |
| 215 | 219 | String replyTopic = topic + REPLY_SUFFIX; |
| 216 | - JSONObject data = customData != null ? customData : new JSONObject(); | |
| 217 | 220 | |
| 218 | - JSONObject response = new JSONObject() | |
| 219 | - .set("id", jsonObject.getStr("id")) | |
| 220 | - .set("code", SUCCESS_CODE) | |
| 221 | - .set("data", data) | |
| 222 | - .set("message", SUCCESS_MESSAGE) | |
| 223 | - .set("method", method); | |
| 221 | + // 使用IotStandardResponse实体类构建响应 | |
| 222 | + IotStandardResponse response = IotStandardResponse.success( | |
| 223 | + jsonObject.getStr("id"), | |
| 224 | + method, | |
| 225 | + customData); | |
| 224 | 226 | |
| 225 | 227 | try { |
| 226 | 228 | mqttClient.publish(replyTopic, |
| 227 | - Buffer.buffer(response.toString()), | |
| 229 | + Buffer.buffer(JsonUtils.toJsonString(response)), | |
| 228 | 230 | MqttQoS.AT_LEAST_ONCE, |
| 229 | 231 | false, |
| 230 | 232 | false); |
| 231 | 233 | log.info("[sendResponse][发送响应消息成功][topic: {}]", replyTopic); |
| 232 | 234 | } catch (Exception e) { |
| 233 | 235 | log.error("[sendResponse][发送响应消息失败][topic: {}][response: {}]", |
| 234 | - replyTopic, response.toString(), e); | |
| 236 | + replyTopic, response, e); | |
| 235 | 237 | } |
| 236 | 238 | } |
| 237 | 239 | |
| ... | ... | @@ -249,7 +251,29 @@ public class IotDeviceMqttMessageHandler { |
| 249 | 251 | reportReqDTO.setReportTime(LocalDateTime.now()); |
| 250 | 252 | reportReqDTO.setProductKey(topicParts[2]); |
| 251 | 253 | reportReqDTO.setDeviceName(topicParts[3]); |
| 252 | - reportReqDTO.setProperties(jsonObject.getJSONObject("params")); | |
| 254 | + | |
| 255 | + // 只使用标准JSON格式处理属性数据 | |
| 256 | + JSONObject params = jsonObject.getJSONObject("params"); | |
| 257 | + if (params == null) { | |
| 258 | + log.warn("[buildPropertyReportDTO][消息格式不正确,缺少params字段][jsonObject: {}]", jsonObject); | |
| 259 | + params = new JSONObject(); | |
| 260 | + } | |
| 261 | + | |
| 262 | + // 将标准格式的params转换为平台需要的properties格式 | |
| 263 | + Map<String, Object> properties = new HashMap<>(); | |
| 264 | + for (Map.Entry<String, Object> entry : params.entrySet()) { | |
| 265 | + String key = entry.getKey(); | |
| 266 | + Object valueObj = entry.getValue(); | |
| 267 | + | |
| 268 | + // 如果是复杂结构(包含value和time) | |
| 269 | + if (valueObj instanceof JSONObject valueJson) { | |
| 270 | + properties.put(key, valueJson.getOrDefault("value", valueObj)); | |
| 271 | + } else { | |
| 272 | + properties.put(key, valueObj); | |
| 273 | + } | |
| 274 | + } | |
| 275 | + reportReqDTO.setProperties(properties); | |
| 276 | + | |
| 253 | 277 | return reportReqDTO; |
| 254 | 278 | } |
| 255 | 279 | |
| ... | ... | @@ -268,7 +292,15 @@ public class IotDeviceMqttMessageHandler { |
| 268 | 292 | reportReqDTO.setProductKey(topicParts[2]); |
| 269 | 293 | reportReqDTO.setDeviceName(topicParts[3]); |
| 270 | 294 | reportReqDTO.setIdentifier(topicParts[6]); |
| 271 | - reportReqDTO.setParams(jsonObject.getJSONObject("params")); | |
| 295 | + | |
| 296 | + // 只使用标准JSON格式处理事件参数 | |
| 297 | + JSONObject params = jsonObject.getJSONObject("params"); | |
| 298 | + if (params == null) { | |
| 299 | + log.warn("[buildEventReportDTO][消息格式不正确,缺少params字段][jsonObject: {}]", jsonObject); | |
| 300 | + params = new JSONObject(); | |
| 301 | + } | |
| 302 | + reportReqDTO.setParams(params); | |
| 303 | + | |
| 272 | 304 | return reportReqDTO; |
| 273 | 305 | } |
| 274 | 306 | } |
| 275 | 307 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceWebhookVertxHandler.java
| ... | ... | @@ -18,7 +18,11 @@ import java.util.Collections; |
| 18 | 18 | /** |
| 19 | 19 | * IoT Emqx Webhook 事件处理的 Vert.x Handler |
| 20 | 20 | * |
| 21 | - * <a href="https://docs.emqx.com/zh/emqx/latest/data-integration/webhook.html">EMQXWebhook</a> | |
| 21 | + * <a href= | |
| 22 | + * "https://docs.emqx.com/zh/emqx/latest/data-integration/webhook.html">EMQXWebhook</a> | |
| 23 | + * | |
| 24 | + * 注意:该处理器需要返回特定格式:{"result": "success"} 或 {"result": "error"}, | |
| 25 | + * 以符合 EMQX Webhook 插件的要求,因此不使用 IotStandardResponse 实体类。 | |
| 22 | 26 | * |
| 23 | 27 | * @author haohao |
| 24 | 28 | */ |
| ... | ... | @@ -54,10 +58,12 @@ public class IotDeviceWebhookVertxHandler implements Handler<RoutingContext> { |
| 54 | 58 | } |
| 55 | 59 | |
| 56 | 60 | // 返回成功响应 |
| 57 | - IotPluginCommonUtils.writeJson(routingContext, Collections.singletonMap("result", "success")); | |
| 61 | + // 注意:这里必须返回 {"result": "success"} 格式,以符合 EMQX Webhook 插件的要求 | |
| 62 | + IotPluginCommonUtils.writeJsonResponse(routingContext, Collections.singletonMap("result", "success")); | |
| 58 | 63 | } catch (Exception e) { |
| 59 | 64 | log.error("[handle][处理 Webhook 事件异常]", e); |
| 60 | - IotPluginCommonUtils.writeJson(routingContext, Collections.singletonMap("result", "error")); | |
| 65 | + // 注意:这里必须返回 {"result": "error"} 格式,以符合 EMQX Webhook 插件的要求 | |
| 66 | + IotPluginCommonUtils.writeJsonResponse(routingContext, Collections.singletonMap("result", "error")); | |
| 61 | 67 | } |
| 62 | 68 | } |
| 63 | 69 | ... | ... |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceEventReportVertxHandler.java
| ... | ... | @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; |
| 7 | 7 | import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceEventReportReqDTO; |
| 8 | 8 | import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; |
| 9 | 9 | import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; |
| 10 | +import cn.iocoder.yudao.module.iot.plugin.common.pojo.IotStandardResponse; | |
| 10 | 11 | import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; |
| 11 | 12 | import io.vertx.core.Handler; |
| 12 | 13 | import io.vertx.core.json.JsonObject; |
| ... | ... | @@ -15,6 +16,7 @@ import lombok.RequiredArgsConstructor; |
| 15 | 16 | import lombok.extern.slf4j.Slf4j; |
| 16 | 17 | |
| 17 | 18 | import java.time.LocalDateTime; |
| 19 | +import java.util.HashMap; | |
| 18 | 20 | import java.util.Map; |
| 19 | 21 | |
| 20 | 22 | import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; |
| ... | ... | @@ -28,6 +30,9 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC |
| 28 | 30 | public class IotDeviceEventReportVertxHandler implements Handler<RoutingContext> { |
| 29 | 31 | |
| 30 | 32 | public static final String PATH = "/sys/:productKey/:deviceName/thing/event/:identifier/post"; |
| 33 | + private static final String VERSION = "1.0"; | |
| 34 | + private static final String EVENT_METHOD_PREFIX = "thing.event."; | |
| 35 | + private static final String EVENT_METHOD_SUFFIX = ".post"; | |
| 31 | 36 | |
| 32 | 37 | private final IotDeviceUpstreamApi deviceUpstreamApi; |
| 33 | 38 | |
| ... | ... | @@ -36,40 +41,71 @@ public class IotDeviceEventReportVertxHandler implements Handler<RoutingContext> |
| 36 | 41 | public void handle(RoutingContext routingContext) { |
| 37 | 42 | // 1. 解析参数 |
| 38 | 43 | IotDeviceEventReportReqDTO reportReqDTO; |
| 44 | + String identifier = null; | |
| 45 | + String requestId = IdUtil.fastSimpleUUID(); | |
| 39 | 46 | try { |
| 40 | 47 | String productKey = routingContext.pathParam("productKey"); |
| 41 | 48 | String deviceName = routingContext.pathParam("deviceName"); |
| 42 | - String identifier = routingContext.pathParam("identifier"); | |
| 49 | + identifier = routingContext.pathParam("identifier"); | |
| 43 | 50 | JsonObject body = routingContext.body().asJsonObject(); |
| 44 | - String id = ObjUtil.defaultIfBlank(body.getString("id"), IdUtil.fastSimpleUUID()); | |
| 45 | - Map<String, Object> params = (Map<String, Object>) body.getMap().get("params"); | |
| 46 | - reportReqDTO = ((IotDeviceEventReportReqDTO) | |
| 47 | - new IotDeviceEventReportReqDTO().setRequestId(id) | |
| 48 | - .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) | |
| 49 | - .setProductKey(productKey).setDeviceName(deviceName)) | |
| 51 | + requestId = ObjUtil.defaultIfBlank(body.getString("id"), requestId); | |
| 52 | + | |
| 53 | + // 按照标准JSON格式处理事件参数 | |
| 54 | + Map<String, Object> params; | |
| 55 | + | |
| 56 | + // 优先使用params字段,符合标准 | |
| 57 | + if (body.getJsonObject("params") != null) { | |
| 58 | + params = body.getJsonObject("params").getMap(); | |
| 59 | + } else { | |
| 60 | + // 兼容旧格式 | |
| 61 | + params = new HashMap<>(); | |
| 62 | + } | |
| 63 | + | |
| 64 | + reportReqDTO = ((IotDeviceEventReportReqDTO) new IotDeviceEventReportReqDTO().setRequestId(requestId) | |
| 65 | + .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) | |
| 66 | + .setProductKey(productKey).setDeviceName(deviceName)) | |
| 50 | 67 | .setIdentifier(identifier).setParams(params); |
| 51 | 68 | } catch (Exception e) { |
| 52 | 69 | log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); |
| 53 | - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST)); | |
| 70 | + // 使用IotStandardResponse实体类返回错误 | |
| 71 | + String method = identifier != null ? EVENT_METHOD_PREFIX + identifier + EVENT_METHOD_SUFFIX | |
| 72 | + : "thing.event.unknown.post"; | |
| 73 | + IotStandardResponse errorResponse = IotStandardResponse.error( | |
| 74 | + requestId, method, BAD_REQUEST.getCode(), BAD_REQUEST.getMsg()); | |
| 75 | + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); | |
| 54 | 76 | return; |
| 55 | 77 | } |
| 56 | 78 | |
| 57 | 79 | try { |
| 58 | 80 | // 2. 设备上线 |
| 59 | - deviceUpstreamApi.updateDeviceState(((IotDeviceStateUpdateReqDTO) | |
| 60 | - new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()) | |
| 81 | + deviceUpstreamApi.updateDeviceState( | |
| 82 | + ((IotDeviceStateUpdateReqDTO) new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()) | |
| 61 | 83 | .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) |
| 62 | 84 | .setProductKey(reportReqDTO.getProductKey()).setDeviceName(reportReqDTO.getDeviceName())) |
| 63 | - .setState(IotDeviceStateEnum.ONLINE.getState())); | |
| 85 | + .setState(IotDeviceStateEnum.ONLINE.getState())); | |
| 64 | 86 | |
| 65 | - // 3.1 属性上报 | |
| 87 | + // 3.1 事件上报 | |
| 66 | 88 | CommonResult<Boolean> result = deviceUpstreamApi.reportDeviceEvent(reportReqDTO); |
| 67 | - // 3.2 返回结果 | |
| 68 | - IotPluginCommonUtils.writeJson(routingContext, result); | |
| 89 | + | |
| 90 | + // 3.2 返回结果 - 使用IotStandardResponse实体类 | |
| 91 | + String method = EVENT_METHOD_PREFIX + reportReqDTO.getIdentifier() + EVENT_METHOD_SUFFIX; | |
| 92 | + IotStandardResponse response; | |
| 93 | + if (result.isSuccess()) { | |
| 94 | + response = IotStandardResponse.success(reportReqDTO.getRequestId(), method, result.getData()); | |
| 95 | + } else { | |
| 96 | + response = IotStandardResponse.error( | |
| 97 | + reportReqDTO.getRequestId(), method, result.getCode(), result.getMsg()); | |
| 98 | + } | |
| 99 | + IotPluginCommonUtils.writeJsonResponse(routingContext, response); | |
| 69 | 100 | } catch (Exception e) { |
| 70 | - log.error("[handle][请求参数({}) 时间上报异常]", reportReqDTO, e); | |
| 71 | - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR)); | |
| 101 | + log.error("[handle][请求参数({}) 事件上报异常]", reportReqDTO, e); | |
| 102 | + | |
| 103 | + // 构建错误响应 - 使用IotStandardResponse实体类 | |
| 104 | + String method = EVENT_METHOD_PREFIX + reportReqDTO.getIdentifier() + EVENT_METHOD_SUFFIX; | |
| 105 | + IotStandardResponse errorResponse = IotStandardResponse.error( | |
| 106 | + reportReqDTO.getRequestId(), method, | |
| 107 | + INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); | |
| 108 | + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); | |
| 72 | 109 | } |
| 73 | 110 | } |
| 74 | - | |
| 75 | 111 | } | ... | ... |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java
| ... | ... | @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; |
| 7 | 7 | import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; |
| 8 | 8 | import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; |
| 9 | 9 | import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; |
| 10 | +import cn.iocoder.yudao.module.iot.plugin.common.pojo.IotStandardResponse; | |
| 10 | 11 | import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; |
| 11 | 12 | import io.vertx.core.Handler; |
| 12 | 13 | import io.vertx.core.json.JsonObject; |
| ... | ... | @@ -15,6 +16,7 @@ import lombok.RequiredArgsConstructor; |
| 15 | 16 | import lombok.extern.slf4j.Slf4j; |
| 16 | 17 | |
| 17 | 18 | import java.time.LocalDateTime; |
| 19 | +import java.util.HashMap; | |
| 18 | 20 | import java.util.Map; |
| 19 | 21 | |
| 20 | 22 | import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; |
| ... | ... | @@ -31,6 +33,8 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC |
| 31 | 33 | public class IotDevicePropertyReportVertxHandler implements Handler<RoutingContext> { |
| 32 | 34 | |
| 33 | 35 | public static final String PATH = "/sys/:productKey/:deviceName/thing/event/property/post"; |
| 36 | + private static final String VERSION = "1.0"; | |
| 37 | + private static final String METHOD = "thing.event.property.post"; | |
| 34 | 38 | |
| 35 | 39 | private final IotDeviceUpstreamApi deviceUpstreamApi; |
| 36 | 40 | |
| ... | ... | @@ -39,43 +43,89 @@ public class IotDevicePropertyReportVertxHandler implements Handler<RoutingConte |
| 39 | 43 | public void handle(RoutingContext routingContext) { |
| 40 | 44 | // 1. 解析参数 |
| 41 | 45 | IotDevicePropertyReportReqDTO reportReqDTO; |
| 46 | + String requestId = IdUtil.fastSimpleUUID(); | |
| 42 | 47 | try { |
| 43 | 48 | String productKey = routingContext.pathParam("productKey"); |
| 44 | 49 | String deviceName = routingContext.pathParam("deviceName"); |
| 45 | 50 | JsonObject body = routingContext.body().asJsonObject(); |
| 46 | - String id = ObjUtil.defaultIfBlank(body.getString("id"), IdUtil.fastSimpleUUID()); | |
| 47 | - Map<String, Object> properties = (Map<String, Object>) body.getMap().get("properties"); | |
| 48 | - reportReqDTO = ((IotDevicePropertyReportReqDTO) | |
| 49 | - new IotDevicePropertyReportReqDTO().setRequestId(id) | |
| 50 | - .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) | |
| 51 | - .setProductKey(productKey).setDeviceName(deviceName)) | |
| 51 | + requestId = ObjUtil.defaultIfBlank(body.getString("id"), requestId); | |
| 52 | + | |
| 53 | + // 按照标准JSON格式处理属性数据 | |
| 54 | + Map<String, Object> properties = new HashMap<>(); | |
| 55 | + | |
| 56 | + // 优先使用params字段,符合标准 | |
| 57 | + Map<String, Object> params = body.getJsonObject("params") != null ? body.getJsonObject("params").getMap() | |
| 58 | + : null; | |
| 59 | + | |
| 60 | + if (params != null) { | |
| 61 | + // 将标准格式的params转换为平台需要的properties格式 | |
| 62 | + for (Map.Entry<String, Object> entry : params.entrySet()) { | |
| 63 | + String key = entry.getKey(); | |
| 64 | + Object valueObj = entry.getValue(); | |
| 65 | + | |
| 66 | + // 如果是复杂结构(包含value和time) | |
| 67 | + if (valueObj instanceof Map) { | |
| 68 | + Map<String, Object> valueMap = (Map<String, Object>) valueObj; | |
| 69 | + if (valueMap.containsKey("value")) { | |
| 70 | + properties.put(key, valueMap.get("value")); | |
| 71 | + } else { | |
| 72 | + properties.put(key, valueObj); | |
| 73 | + } | |
| 74 | + } else { | |
| 75 | + properties.put(key, valueObj); | |
| 76 | + } | |
| 77 | + } | |
| 78 | + } else { | |
| 79 | + // 兼容旧格式,直接使用properties字段 | |
| 80 | + properties = body.getJsonObject("properties") != null ? body.getJsonObject("properties").getMap() | |
| 81 | + : new HashMap<>(); | |
| 82 | + } | |
| 83 | + | |
| 84 | + reportReqDTO = ((IotDevicePropertyReportReqDTO) new IotDevicePropertyReportReqDTO().setRequestId(requestId) | |
| 85 | + .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) | |
| 86 | + .setProductKey(productKey).setDeviceName(deviceName)) | |
| 52 | 87 | .setProperties(properties); |
| 53 | 88 | } catch (Exception e) { |
| 54 | 89 | log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); |
| 55 | - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST)); | |
| 90 | + // 使用IotStandardResponse实体类返回错误 | |
| 91 | + IotStandardResponse errorResponse = IotStandardResponse.error( | |
| 92 | + requestId, METHOD, BAD_REQUEST.getCode(), BAD_REQUEST.getMsg()); | |
| 93 | + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); | |
| 56 | 94 | return; |
| 57 | 95 | } |
| 58 | 96 | |
| 59 | 97 | // TODO @芋艿:secret 校验。目前的想法: |
| 60 | - // 方案一:请求的时候,带上 secret 参数,然后进行校验,减少请求的频次。不过可能要看下 mqtt 能不能复用! | |
| 61 | - // 方案二:本地有设备信息的缓存,异步刷新。这样可能 mqtt 的校验,和 http 校验都容易适配。 | |
| 98 | + // 方案一:请求的时候,带上 secret 参数,然后进行校验,减少请求的频次。不过可能要看下 mqtt 能不能复用! | |
| 99 | + // 方案二:本地有设备信息的缓存,异步刷新。这样可能 mqtt 的校验,和 http 校验都容易适配。 | |
| 62 | 100 | |
| 63 | 101 | try { |
| 64 | 102 | // 2. 设备上线 |
| 65 | - deviceUpstreamApi.updateDeviceState(((IotDeviceStateUpdateReqDTO) | |
| 66 | - new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()) | |
| 103 | + deviceUpstreamApi.updateDeviceState( | |
| 104 | + ((IotDeviceStateUpdateReqDTO) new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()) | |
| 67 | 105 | .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) |
| 68 | 106 | .setProductKey(reportReqDTO.getProductKey()).setDeviceName(reportReqDTO.getDeviceName())) |
| 69 | - .setState(IotDeviceStateEnum.ONLINE.getState())); | |
| 107 | + .setState(IotDeviceStateEnum.ONLINE.getState())); | |
| 70 | 108 | |
| 71 | 109 | // 3.1 属性上报 |
| 72 | 110 | CommonResult<Boolean> result = deviceUpstreamApi.reportDeviceProperty(reportReqDTO); |
| 73 | - // 3.2 返回结果 | |
| 74 | - IotPluginCommonUtils.writeJson(routingContext, result); | |
| 111 | + | |
| 112 | + // 3.2 返回结果 - 使用IotStandardResponse实体类 | |
| 113 | + IotStandardResponse response; | |
| 114 | + if (result.isSuccess()) { | |
| 115 | + response = IotStandardResponse.success(reportReqDTO.getRequestId(), METHOD, result.getData()); | |
| 116 | + } else { | |
| 117 | + response = IotStandardResponse.error( | |
| 118 | + reportReqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); | |
| 119 | + } | |
| 120 | + IotPluginCommonUtils.writeJsonResponse(routingContext, response); | |
| 75 | 121 | } catch (Exception e) { |
| 76 | 122 | log.error("[handle][请求参数({}) 属性上报异常]", reportReqDTO, e); |
| 77 | - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR)); | |
| 123 | + | |
| 124 | + // 构建错误响应 - 使用IotStandardResponse实体类 | |
| 125 | + IotStandardResponse errorResponse = IotStandardResponse.error( | |
| 126 | + reportReqDTO.getRequestId(), METHOD, | |
| 127 | + INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); | |
| 128 | + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); | |
| 78 | 129 | } |
| 79 | 130 | } |
| 80 | - | |
| 81 | 131 | } | ... | ... |