Commit 2512f2dde8a0df4fd8f3f4d87bfcc65eaaed69cf
1 parent
7f0de1e3
【代码优化】IoT:优化 http 插件 IotDevicePropertyReportVertxHandler 的代码
Showing
4 changed files
with
51 additions
and
79 deletions
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDevicePropertyGetReqDTO.java
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/upstream/IotDeviceUpstreamClient.java
| @@ -6,10 +6,11 @@ import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceEven | @@ -6,10 +6,11 @@ import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceEven | ||
| 6 | import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; | 6 | import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; |
| 7 | import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; | 7 | import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; |
| 8 | import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotPluginInstanceHeartbeatReqDTO; | 8 | import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotPluginInstanceHeartbeatReqDTO; |
| 9 | +import lombok.RequiredArgsConstructor; | ||
| 9 | import lombok.extern.slf4j.Slf4j; | 10 | import lombok.extern.slf4j.Slf4j; |
| 10 | import org.springframework.web.client.RestTemplate; | 11 | import org.springframework.web.client.RestTemplate; |
| 11 | 12 | ||
| 12 | -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 13 | +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; |
| 13 | 14 | ||
| 14 | /** | 15 | /** |
| 15 | * 设备数据 Upstream 上行客户端 | 16 | * 设备数据 Upstream 上行客户端 |
| @@ -18,60 +19,51 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | @@ -18,60 +19,51 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||
| 18 | * | 19 | * |
| 19 | * @author haohao | 20 | * @author haohao |
| 20 | */ | 21 | */ |
| 22 | +@RequiredArgsConstructor | ||
| 21 | @Slf4j | 23 | @Slf4j |
| 22 | public class IotDeviceUpstreamClient implements IotDeviceUpstreamApi { | 24 | public class IotDeviceUpstreamClient implements IotDeviceUpstreamApi { |
| 23 | 25 | ||
| 24 | public static final String URL_PREFIX = "/rpc-api/iot/device/upstream"; | 26 | public static final String URL_PREFIX = "/rpc-api/iot/device/upstream"; |
| 25 | 27 | ||
| 26 | private final RestTemplate restTemplate; | 28 | private final RestTemplate restTemplate; |
| 27 | - private final String deviceDataUrl; | ||
| 28 | 29 | ||
| 29 | - // 可以通过构造器把 RestTemplate 和 baseUrl 注入进来 | ||
| 30 | - // TODO @haohao:可以用 lombok 简化 | ||
| 31 | - public IotDeviceUpstreamClient(RestTemplate restTemplate, String deviceDataUrl) { | ||
| 32 | - this.restTemplate = restTemplate; | ||
| 33 | - this.deviceDataUrl = deviceDataUrl; | ||
| 34 | - } | 30 | + // TODO @芋艿:改个名字 |
| 31 | + private final String deviceDataUrl; | ||
| 35 | 32 | ||
| 36 | - // TODO @haohao:返回结果,不用 CommonResult 哈。 | ||
| 37 | @Override | 33 | @Override |
| 38 | public CommonResult<Boolean> updateDeviceState(IotDeviceStateUpdateReqDTO updateReqDTO) { | 34 | public CommonResult<Boolean> updateDeviceState(IotDeviceStateUpdateReqDTO updateReqDTO) { |
| 39 | String url = deviceDataUrl + URL_PREFIX + "/update-state"; | 35 | String url = deviceDataUrl + URL_PREFIX + "/update-state"; |
| 40 | - return doPost(url, updateReqDTO, "updateDeviceState"); | 36 | + return doPost(url, updateReqDTO); |
| 41 | } | 37 | } |
| 42 | 38 | ||
| 43 | @Override | 39 | @Override |
| 44 | public CommonResult<Boolean> reportDeviceEvent(IotDeviceEventReportReqDTO reportReqDTO) { | 40 | public CommonResult<Boolean> reportDeviceEvent(IotDeviceEventReportReqDTO reportReqDTO) { |
| 45 | String url = deviceDataUrl + URL_PREFIX + "/report-event"; | 41 | String url = deviceDataUrl + URL_PREFIX + "/report-event"; |
| 46 | - return doPost(url, reportReqDTO, "reportDeviceEventData"); | 42 | + return doPost(url, reportReqDTO); |
| 47 | } | 43 | } |
| 48 | 44 | ||
| 49 | @Override | 45 | @Override |
| 50 | public CommonResult<Boolean> reportDeviceProperty(IotDevicePropertyReportReqDTO reportReqDTO) { | 46 | public CommonResult<Boolean> reportDeviceProperty(IotDevicePropertyReportReqDTO reportReqDTO) { |
| 51 | String url = deviceDataUrl + URL_PREFIX + "/report-property"; | 47 | String url = deviceDataUrl + URL_PREFIX + "/report-property"; |
| 52 | - return doPost(url, reportReqDTO, "reportDevicePropertyData"); | 48 | + return doPost(url, reportReqDTO); |
| 53 | } | 49 | } |
| 54 | 50 | ||
| 55 | @Override | 51 | @Override |
| 56 | public CommonResult<Boolean> heartbeatPluginInstance(IotPluginInstanceHeartbeatReqDTO heartbeatReqDTO) { | 52 | public CommonResult<Boolean> heartbeatPluginInstance(IotPluginInstanceHeartbeatReqDTO heartbeatReqDTO) { |
| 57 | String url = deviceDataUrl + URL_PREFIX + "/heartbeat-plugin-instance"; | 53 | String url = deviceDataUrl + URL_PREFIX + "/heartbeat-plugin-instance"; |
| 58 | - return doPost(url, heartbeatReqDTO, "heartbeatPluginInstance"); | 54 | + return doPost(url, heartbeatReqDTO); |
| 59 | } | 55 | } |
| 60 | 56 | ||
| 61 | - // TODO @haohao:未来可能有 get 类型哈 | ||
| 62 | - /** | ||
| 63 | - * 将与远程服务交互的通用逻辑抽取成一个私有方法 | ||
| 64 | - */ | ||
| 65 | - private <T> CommonResult<Boolean> doPost(String url, T requestBody, String actionName) { | ||
| 66 | - log.info("[{}] Sending request to URL: {}", actionName, url); | 57 | + @SuppressWarnings("unchecked") |
| 58 | + private <T> CommonResult<Boolean> doPost(String url, T requestBody) { | ||
| 67 | try { | 59 | try { |
| 68 | - // 这里指定返回类型为 CommonResult<?>,根据后台服务返回的实际结构做调整 | ||
| 69 | - restTemplate.postForObject(url, requestBody, CommonResult.class); | ||
| 70 | - // TODO @haohao:check 结果,是否成功 | ||
| 71 | - return success(true); | 60 | + CommonResult<Boolean> result = restTemplate.postForObject(url, requestBody, |
| 61 | + (Class<CommonResult<Boolean>>) (Class<?>) CommonResult.class); | ||
| 62 | + log.info("[doPost][url({}) requestBody({}) result({})]", url, requestBody, result); | ||
| 63 | + return result; | ||
| 72 | } catch (Exception e) { | 64 | } catch (Exception e) { |
| 73 | - log.error("[{}] Error sending request to URL: {}", actionName, url, e); | ||
| 74 | - return CommonResult.error(400, "Request error: " + e.getMessage()); | 65 | + log.error("[doPost][url({}) requestBody({}) 发生异常]", url, requestBody, e); |
| 66 | + return CommonResult.error(INTERNAL_SERVER_ERROR); | ||
| 75 | } | 67 | } |
| 76 | } | 68 | } |
| 77 | 69 |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/IotDeviceUpstreamServer.java
| @@ -31,7 +31,7 @@ public class IotDeviceUpstreamServer { | @@ -31,7 +31,7 @@ public class IotDeviceUpstreamServer { | ||
| 31 | Router router = Router.router(vertx); | 31 | Router router = Router.router(vertx); |
| 32 | router.route().handler(BodyHandler.create()); // 处理 Body | 32 | router.route().handler(BodyHandler.create()); // 处理 Body |
| 33 | router.post(IotDevicePropertyReportVertxHandler.PATH) | 33 | router.post(IotDevicePropertyReportVertxHandler.PATH) |
| 34 | - .handler(new IotDevicePropertyReportVertxHandler(deviceUpstreamApi)); // 处理设备属性上报 | 34 | + .handler(new IotDevicePropertyReportVertxHandler(deviceUpstreamApi)); |
| 35 | // 创建 HttpServer 实例 | 35 | // 创建 HttpServer 实例 |
| 36 | this.server = vertx.createHttpServer().requestHandler(router); | 36 | this.server = vertx.createHttpServer().requestHandler(router); |
| 37 | } | 37 | } |
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
| 1 | package cn.iocoder.yudao.module.iot.plugin.http.upstream.router; | 1 | package cn.iocoder.yudao.module.iot.plugin.http.upstream.router; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.util.IdUtil; | 3 | import cn.hutool.core.util.IdUtil; |
| 4 | -import cn.hutool.json.JSONObject; | ||
| 5 | -import cn.hutool.json.JSONUtil; | 4 | +import cn.hutool.core.util.ObjUtil; |
| 5 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 6 | import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; | 6 | import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; |
| 7 | import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; | 7 | import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; |
| 8 | import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; | 8 | import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; |
| 9 | import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; | 9 | import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; |
| 10 | import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; | 10 | import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; |
| 11 | import io.vertx.core.Handler; | 11 | import io.vertx.core.Handler; |
| 12 | -import io.vertx.ext.web.RequestBody; | 12 | +import io.vertx.core.json.JsonObject; |
| 13 | import io.vertx.ext.web.RoutingContext; | 13 | import io.vertx.ext.web.RoutingContext; |
| 14 | import lombok.RequiredArgsConstructor; | 14 | import lombok.RequiredArgsConstructor; |
| 15 | import lombok.extern.slf4j.Slf4j; | 15 | import lombok.extern.slf4j.Slf4j; |
| @@ -17,8 +17,13 @@ import lombok.extern.slf4j.Slf4j; | @@ -17,8 +17,13 @@ import lombok.extern.slf4j.Slf4j; | ||
| 17 | import java.time.LocalDateTime; | 17 | import java.time.LocalDateTime; |
| 18 | import java.util.Map; | 18 | import java.util.Map; |
| 19 | 19 | ||
| 20 | +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; | ||
| 21 | +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; | ||
| 22 | + | ||
| 20 | /** | 23 | /** |
| 21 | * IoT 设备属性上报的 Vert.x Handler | 24 | * IoT 设备属性上报的 Vert.x Handler |
| 25 | + * | ||
| 26 | + * @author haohao | ||
| 22 | */ | 27 | */ |
| 23 | @RequiredArgsConstructor | 28 | @RequiredArgsConstructor |
| 24 | @Slf4j | 29 | @Slf4j |
| @@ -29,69 +34,43 @@ public class IotDevicePropertyReportVertxHandler implements Handler<RoutingConte | @@ -29,69 +34,43 @@ public class IotDevicePropertyReportVertxHandler implements Handler<RoutingConte | ||
| 29 | private final IotDeviceUpstreamApi deviceUpstreamApi; | 34 | private final IotDeviceUpstreamApi deviceUpstreamApi; |
| 30 | 35 | ||
| 31 | @Override | 36 | @Override |
| 32 | - public void handle(RoutingContext ctx) { | ||
| 33 | - String productKey = ctx.pathParam("productKey"); | ||
| 34 | - String deviceName = ctx.pathParam("deviceName"); | ||
| 35 | - | ||
| 36 | - // TODO @haohao:requestBody.asJsonObject() 貌似天然就是 json 对象哈? | ||
| 37 | - RequestBody requestBody = ctx.body(); | ||
| 38 | - JSONObject jsonData; | 37 | + @SuppressWarnings("unchecked") |
| 38 | + public void handle(RoutingContext routingContext) { | ||
| 39 | + // 1. 解析参数 | ||
| 40 | + IotDevicePropertyReportReqDTO reportReqDTO; | ||
| 39 | try { | 41 | try { |
| 40 | - jsonData = JSONUtil.parseObj(requestBody.asJsonObject()); | 42 | + String productKey = routingContext.pathParam("productKey"); |
| 43 | + String deviceName = routingContext.pathParam("deviceName"); | ||
| 44 | + JsonObject body = routingContext.body().asJsonObject(); | ||
| 45 | + String id = ObjUtil.defaultIfBlank(body.getString("id"), IdUtil.fastSimpleUUID()); | ||
| 46 | + Map<String, Object> properties = (Map<String, Object>) body.getMap().get("properties"); | ||
| 47 | + reportReqDTO = ((IotDevicePropertyReportReqDTO) | ||
| 48 | + new IotDevicePropertyReportReqDTO().setRequestId(id) | ||
| 49 | + .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) | ||
| 50 | + .setProductKey(productKey).setDeviceName(deviceName)) | ||
| 51 | + .setProperties(properties); | ||
| 41 | } catch (Exception e) { | 52 | } catch (Exception e) { |
| 42 | - log.error("[HttpVertxHandler] 请求数据解析失败", e); | ||
| 43 | - ctx.response().setStatusCode(400) | ||
| 44 | - .putHeader("Content-Type", "application/json; charset=UTF-8") | ||
| 45 | - .end(createResponseJson(400, null, null, | ||
| 46 | - "请求数据不是合法的 JSON 格式: " + e.getMessage(), | ||
| 47 | - "thing.event.property.post", "1.0").toString()); | 53 | + log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); |
| 54 | + IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST)); | ||
| 48 | return; | 55 | return; |
| 49 | } | 56 | } |
| 50 | 57 | ||
| 51 | - String id = jsonData.getStr("id"); | ||
| 52 | - | ||
| 53 | try { | 58 | try { |
| 54 | - // 设备上线 | 59 | + // 2. 设备上线 |
| 55 | deviceUpstreamApi.updateDeviceState(((IotDeviceStateUpdateReqDTO) | 60 | deviceUpstreamApi.updateDeviceState(((IotDeviceStateUpdateReqDTO) |
| 56 | new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()) | 61 | new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()) |
| 57 | .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) | 62 | .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) |
| 58 | - .setProductKey(productKey).setDeviceName(deviceName)) | 63 | + .setProductKey(reportReqDTO.getProductKey()).setDeviceName(reportReqDTO.getDeviceName())) |
| 59 | .setState(IotDeviceStateEnum.ONLINE.getState())); | 64 | .setState(IotDeviceStateEnum.ONLINE.getState())); |
| 60 | 65 | ||
| 61 | - // 属性上报 | ||
| 62 | - deviceUpstreamApi.reportDeviceProperty(((IotDevicePropertyReportReqDTO) | ||
| 63 | - new IotDevicePropertyReportReqDTO().setRequestId(IdUtil.fastSimpleUUID()) | ||
| 64 | - .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) | ||
| 65 | - .setProductKey(productKey).setDeviceName(deviceName)) | ||
| 66 | - .setProperties((Map<String, Object>) requestBody.asJsonObject().getMap().get("properties"))); | ||
| 67 | - | ||
| 68 | - ctx.response() | ||
| 69 | - .setStatusCode(200) | ||
| 70 | - .putHeader("Content-Type", "application/json; charset=UTF-8") | ||
| 71 | - .end(createResponseJson(200, new JSONObject(), id, "success", | ||
| 72 | - "thing.event.property.post", "1.0").toString()); | 66 | + // 3.1 属性上报 |
| 67 | + CommonResult<Boolean> result = deviceUpstreamApi.reportDeviceProperty(reportReqDTO); | ||
| 68 | + // 3.2 返回结果 | ||
| 69 | + IotPluginCommonUtils.writeJson(routingContext, result); | ||
| 73 | } catch (Exception e) { | 70 | } catch (Exception e) { |
| 74 | - log.error("[HttpVertxHandler] 上报属性数据失败", e); | ||
| 75 | - ctx.response() | ||
| 76 | - .setStatusCode(500) | ||
| 77 | - .putHeader("Content-Type", "application/json; charset=UTF-8") | ||
| 78 | - .end(createResponseJson(500, new JSONObject(), id, | ||
| 79 | - "The format of result is error!", | ||
| 80 | - "thing.event.property.post", "1.0").toString()); | 71 | + log.error("[handle][请求参数({}) 属性获取异常]", reportReqDTO, e); |
| 72 | + IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR)); | ||
| 81 | } | 73 | } |
| 82 | } | 74 | } |
| 83 | 75 | ||
| 84 | - // TODO @芋艿:抽一个 IotPluginCommonResult 出来?等 mqtt、websocket 出来后,再考虑优化! | ||
| 85 | - private JSONObject createResponseJson(int code, JSONObject data, String id, | ||
| 86 | - String message, String method, String version) { | ||
| 87 | - JSONObject res = new JSONObject(); | ||
| 88 | - res.set("code", code); | ||
| 89 | - res.set("data", data != null ? data : new JSONObject()); | ||
| 90 | - res.set("id", id); | ||
| 91 | - res.set("message", message); | ||
| 92 | - res.set("method", method); | ||
| 93 | - res.set("version", version); | ||
| 94 | - return res; | ||
| 95 | - } | ||
| 96 | - | ||
| 97 | } | 76 | } |