Commit 2512f2dde8a0df4fd8f3f4d87bfcc65eaaed69cf

Authored by YunaiV
1 parent 7f0de1e3

【代码优化】IoT:优化 http 插件 IotDevicePropertyReportVertxHandler 的代码

yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDevicePropertyGetReqDTO.java
... ... @@ -5,6 +5,7 @@ import lombok.Data;
5 5  
6 6 import java.util.List;
7 7  
  8 +// TODO @芋艿:从 server => plugin => device 是否有必要?从阿里云 iot 来看,没有这个功能?!
8 9 /**
9 10 * IoT 设备【属性】获取 Request DTO
10 11 *
... ...
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 6 import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO;
7 7 import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO;
8 8 import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotPluginInstanceHeartbeatReqDTO;
  9 +import lombok.RequiredArgsConstructor;
9 10 import lombok.extern.slf4j.Slf4j;
10 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 16 * 设备数据 Upstream 上行客户端
... ... @@ -18,60 +19,51 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
18 19 *
19 20 * @author haohao
20 21 */
  22 +@RequiredArgsConstructor
21 23 @Slf4j
22 24 public class IotDeviceUpstreamClient implements IotDeviceUpstreamApi {
23 25  
24 26 public static final String URL_PREFIX = "/rpc-api/iot/device/upstream";
25 27  
26 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 33 @Override
38 34 public CommonResult<Boolean> updateDeviceState(IotDeviceStateUpdateReqDTO updateReqDTO) {
39 35 String url = deviceDataUrl + URL_PREFIX + "/update-state";
40   - return doPost(url, updateReqDTO, "updateDeviceState");
  36 + return doPost(url, updateReqDTO);
41 37 }
42 38  
43 39 @Override
44 40 public CommonResult<Boolean> reportDeviceEvent(IotDeviceEventReportReqDTO reportReqDTO) {
45 41 String url = deviceDataUrl + URL_PREFIX + "/report-event";
46   - return doPost(url, reportReqDTO, "reportDeviceEventData");
  42 + return doPost(url, reportReqDTO);
47 43 }
48 44  
49 45 @Override
50 46 public CommonResult<Boolean> reportDeviceProperty(IotDevicePropertyReportReqDTO reportReqDTO) {
51 47 String url = deviceDataUrl + URL_PREFIX + "/report-property";
52   - return doPost(url, reportReqDTO, "reportDevicePropertyData");
  48 + return doPost(url, reportReqDTO);
53 49 }
54 50  
55 51 @Override
56 52 public CommonResult<Boolean> heartbeatPluginInstance(IotPluginInstanceHeartbeatReqDTO heartbeatReqDTO) {
57 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 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 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 31 Router router = Router.router(vertx);
32 32 router.route().handler(BodyHandler.create()); // 处理 Body
33 33 router.post(IotDevicePropertyReportVertxHandler.PATH)
34   - .handler(new IotDevicePropertyReportVertxHandler(deviceUpstreamApi)); // 处理设备属性上报
  34 + .handler(new IotDevicePropertyReportVertxHandler(deviceUpstreamApi));
35 35 // 创建 HttpServer 实例
36 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 1 package cn.iocoder.yudao.module.iot.plugin.http.upstream.router;
2 2  
3 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 6 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 10 import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils;
11 11 import io.vertx.core.Handler;
12   -import io.vertx.ext.web.RequestBody;
  12 +import io.vertx.core.json.JsonObject;
13 13 import io.vertx.ext.web.RoutingContext;
14 14 import lombok.RequiredArgsConstructor;
15 15 import lombok.extern.slf4j.Slf4j;
... ... @@ -17,8 +17,13 @@ import lombok.extern.slf4j.Slf4j;
17 17 import java.time.LocalDateTime;
18 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 24 * IoT 设备属性上报的 Vert.x Handler
  25 + *
  26 + * @author haohao
22 27 */
23 28 @RequiredArgsConstructor
24 29 @Slf4j
... ... @@ -29,69 +34,43 @@ public class IotDevicePropertyReportVertxHandler implements Handler&lt;RoutingConte
29 34 private final IotDeviceUpstreamApi deviceUpstreamApi;
30 35  
31 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 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 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 55 return;
49 56 }
50 57  
51   - String id = jsonData.getStr("id");
52   -
53 58 try {
54   - // 设备上线
  59 + // 2. 设备上线
55 60 deviceUpstreamApi.updateDeviceState(((IotDeviceStateUpdateReqDTO)
56 61 new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID())
57 62 .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now())
58   - .setProductKey(productKey).setDeviceName(deviceName))
  63 + .setProductKey(reportReqDTO.getProductKey()).setDeviceName(reportReqDTO.getDeviceName()))
59 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 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 }
... ...