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,6 +5,7 @@ import lombok.Data;
5 5
6 import java.util.List; 6 import java.util.List;
7 7
  8 +// TODO @芋艿:从 server => plugin => device 是否有必要?从阿里云 iot 来看,没有这个功能?!
8 /** 9 /**
9 * IoT 设备【属性】获取 Request DTO 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,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&lt;RoutingConte @@ -29,69 +34,43 @@ public class IotDevicePropertyReportVertxHandler implements Handler&lt;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 }