Commit f70f578ac59fd6b357245499adac6b6e3557e304

Authored by YunaiV
1 parent bd8052f5

fix:【IoT 物联网】code review tcp 实现

yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/tcp/IotTcpBinaryDeviceMessageCodec.java
@@ -10,11 +10,12 @@ import lombok.Data; @@ -10,11 +10,12 @@ import lombok.Data;
10 import lombok.extern.slf4j.Slf4j; 10 import lombok.extern.slf4j.Slf4j;
11 import org.springframework.stereotype.Component; 11 import org.springframework.stereotype.Component;
12 12
  13 +// TODO @haohao:设备地址(变长) 是不是非必要哈?因为认证后,不需要每次都带呀。
13 /** 14 /**
14 * TCP 二进制格式 {@link IotDeviceMessage} 编解码器 15 * TCP 二进制格式 {@link IotDeviceMessage} 编解码器
15 * 16 *
16 * 使用自定义二进制协议格式: 17 * 使用自定义二进制协议格式:
17 - * 包头(4字节) | 地址长度(2字节) | 设备地址(变长) | 功能码(2字节) | 消息序号(2字节) | 包体数据(变长) 18 + * 包头(4 字节) | 地址长度(2 字节) | 设备地址(变长) | 功能码(2 字节) | 消息序号(2 字节) | 包体数据(变长)
18 * 19 *
19 * @author 芋道源码 20 * @author 芋道源码
20 */ 21 */
@@ -27,6 +28,7 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec { @@ -27,6 +28,7 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
27 */ 28 */
28 public static final String TYPE = "TCP_BINARY"; 29 public static final String TYPE = "TCP_BINARY";
29 30
  31 + // TODO @haohao:这个注释不太对。
30 // ==================== 常量定义 ==================== 32 // ==================== 常量定义 ====================
31 33
32 @Override 34 @Override
@@ -67,10 +69,11 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec { @@ -67,10 +69,11 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
67 TcpDataPackage dataPackage = decodeTcpDataPackage(Buffer.buffer(bytes)); 69 TcpDataPackage dataPackage = decodeTcpDataPackage(Buffer.buffer(bytes));
68 70
69 // 2. 根据功能码确定方法 71 // 2. 根据功能码确定方法
  72 + // TODO @haohao:会不会有事件上报哈。
70 String method = (dataPackage.getCode() == TcpDataPackage.CODE_HEARTBEAT) ? 73 String method = (dataPackage.getCode() == TcpDataPackage.CODE_HEARTBEAT) ?
71 MessageMethod.STATE_ONLINE : MessageMethod.PROPERTY_POST; 74 MessageMethod.STATE_ONLINE : MessageMethod.PROPERTY_POST;
72 75
73 - // 3. 解析负载数据和请求ID 76 + // 3. 解析负载数据和请求 ID
74 PayloadInfo payloadInfo = parsePayloadInfo(dataPackage.getPayload()); 77 PayloadInfo payloadInfo = parsePayloadInfo(dataPackage.getPayload());
75 78
76 // 4. 构建 IoT 设备消息(设置完整的必要参数) 79 // 4. 构建 IoT 设备消息(设置完整的必要参数)
@@ -78,13 +81,16 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec { @@ -78,13 +81,16 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
78 payloadInfo.getRequestId(), method, payloadInfo.getParams()); 81 payloadInfo.getRequestId(), method, payloadInfo.getParams());
79 82
80 // 5. 设置设备相关信息 83 // 5. 设置设备相关信息
  84 + // TODO @haohao:serverId 不是这里解析的哈。
81 Long deviceId = parseDeviceId(dataPackage.getAddr()); 85 Long deviceId = parseDeviceId(dataPackage.getAddr());
82 message.setDeviceId(deviceId); 86 message.setDeviceId(deviceId);
83 87
84 - // 6. 设置TCP协议相关信息 88 + // 6. 设置 TCP 协议相关信息
  89 + // TODO @haohao:serverId 不是这里解析的哈。
85 message.setServerId(generateServerId(dataPackage)); 90 message.setServerId(generateServerId(dataPackage));
86 91
87 - // 7. 设置租户ID(TODO: 后续可以从设备信息中获取) 92 + // 7. 设置租户 ID(TODO: 后续可以从设备信息中获取)
  93 + // TODO @haohao:租户 id 不是这里解析的哈。
88 // message.setTenantId(getTenantIdByDeviceId(deviceId)); 94 // message.setTenantId(getTenantIdByDeviceId(deviceId));
89 95
90 if (log.isDebugEnabled()) { 96 if (log.isDebugEnabled()) {
@@ -104,6 +110,7 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec { @@ -104,6 +110,7 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
104 return TYPE; 110 return TYPE;
105 } 111 }
106 112
  113 + // TODO @haohao:这种简单解析,中间不用空格哈。
107 /** 114 /**
108 * 构建完整负载 115 * 构建完整负载
109 */ 116 */
@@ -130,12 +137,10 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec { @@ -130,12 +137,10 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
130 return payload.toString(); 137 return payload.toString();
131 } 138 }
132 139
133 -  
134 -  
135 // ==================== 编解码方法 ==================== 140 // ==================== 编解码方法 ====================
136 141
137 /** 142 /**
138 - * 解析负载信息(包含requestId和params) 143 + * 解析负载信息(包含 requestId 和 params)
139 */ 144 */
140 private PayloadInfo parsePayloadInfo(String payload) { 145 private PayloadInfo parsePayloadInfo(String payload) {
141 if (StrUtil.isEmpty(payload)) { 146 if (StrUtil.isEmpty(payload)) {
@@ -143,6 +148,7 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec { @@ -143,6 +148,7 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
143 } 148 }
144 149
145 try { 150 try {
  151 + // TODO @haohao:使用 jsonUtils
146 JSONObject jsonObject = JSONUtil.parseObj(payload); 152 JSONObject jsonObject = JSONUtil.parseObj(payload);
147 String requestId = jsonObject.getStr(PayloadField.REQUEST_ID); 153 String requestId = jsonObject.getStr(PayloadField.REQUEST_ID);
148 if (StrUtil.isEmpty(requestId)) { 154 if (StrUtil.isEmpty(requestId)) {
@@ -185,7 +191,7 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec { @@ -185,7 +191,7 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
185 * @return 服务ID 191 * @return 服务ID
186 */ 192 */
187 private String generateServerId(TcpDataPackage dataPackage) { 193 private String generateServerId(TcpDataPackage dataPackage) {
188 - // 使用协议类型 + 设备地址 + 消息序号生成唯一的服务ID 194 + // 使用协议类型 + 设备地址 + 消息序号生成唯一的服务 ID
189 return String.format("tcp_%s_%d", dataPackage.getAddr(), dataPackage.getMid()); 195 return String.format("tcp_%s_%d", dataPackage.getAddr(), dataPackage.getMid());
190 } 196 }
191 197
@@ -300,23 +306,28 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec { @@ -300,23 +306,28 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
300 * 消息方法常量 306 * 消息方法常量
301 */ 307 */
302 public static class MessageMethod { 308 public static class MessageMethod {
  309 +
303 public static final String PROPERTY_POST = "thing.property.post"; // 数据上报 310 public static final String PROPERTY_POST = "thing.property.post"; // 数据上报
304 public static final String STATE_ONLINE = "thing.state.online"; // 心跳 311 public static final String STATE_ONLINE = "thing.state.online"; // 心跳
  312 +
305 } 313 }
306 314
307 /** 315 /**
308 * 负载字段名 316 * 负载字段名
309 */ 317 */
310 private static class PayloadField { 318 private static class PayloadField {
  319 +
311 public static final String METHOD = "method"; 320 public static final String METHOD = "method";
312 public static final String PARAMS = "params"; 321 public static final String PARAMS = "params";
313 public static final String TIMESTAMP = "timestamp"; 322 public static final String TIMESTAMP = "timestamp";
314 public static final String REQUEST_ID = "requestId"; 323 public static final String REQUEST_ID = "requestId";
315 public static final String MESSAGE_ID = "msgId"; 324 public static final String MESSAGE_ID = "msgId";
  325 +
316 } 326 }
317 327
318 // ==================== TCP 数据包编解码方法 ==================== 328 // ==================== TCP 数据包编解码方法 ====================
319 329
  330 + // TODO @haohao:lombok 简化
320 /** 331 /**
321 * 负载信息类 332 * 负载信息类
322 */ 333 */
@@ -361,11 +372,13 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec { @@ -361,11 +372,13 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
361 372
362 // ==================== 自定义异常 ==================== 373 // ==================== 自定义异常 ====================
363 374
  375 + // TODO @haohao:可以搞个全局的;
364 /** 376 /**
365 * TCP 编解码异常 377 * TCP 编解码异常
366 */ 378 */
367 public static class TcpCodecException extends RuntimeException { 379 public static class TcpCodecException extends RuntimeException {
368 380
  381 + // TODO @haohao:非必要构造方法,可以去掉哈。
369 public TcpCodecException(String message) { 382 public TcpCodecException(String message) {
370 super(message); 383 super(message);
371 } 384 }
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/tcp/IotTcpCodecManager.java
@@ -8,11 +8,11 @@ import org.springframework.stereotype.Component; @@ -8,11 +8,11 @@ import org.springframework.stereotype.Component;
8 8
9 /** 9 /**
10 * TCP编解码器管理器(简化版) 10 * TCP编解码器管理器(简化版)
11 - * 11 + *
12 * 核心功能: 12 * 核心功能:
13 * - 自动协议检测(二进制 vs JSON) 13 * - 自动协议检测(二进制 vs JSON)
14 * - 统一编解码接口 14 * - 统一编解码接口
15 - * - 默认使用JSON协议 15 + * - 默认使用 JSON 协议
16 * 16 *
17 * @author 芋道源码 17 * @author 芋道源码
18 */ 18 */
@@ -22,6 +22,8 @@ public class IotTcpCodecManager implements IotDeviceMessageCodec { @@ -22,6 +22,8 @@ public class IotTcpCodecManager implements IotDeviceMessageCodec {
22 22
23 public static final String TYPE = "TCP"; 23 public static final String TYPE = "TCP";
24 24
  25 + // TODO @haohao:@Resource
  26 +
25 @Autowired 27 @Autowired
26 private IotTcpBinaryDeviceMessageCodec binaryCodec; 28 private IotTcpBinaryDeviceMessageCodec binaryCodec;
27 29
@@ -40,21 +42,22 @@ public class IotTcpCodecManager implements IotDeviceMessageCodec { @@ -40,21 +42,22 @@ public class IotTcpCodecManager implements IotDeviceMessageCodec {
40 42
41 @Override 43 @Override
42 public byte[] encode(IotDeviceMessage message) { 44 public byte[] encode(IotDeviceMessage message) {
43 - // 默认使用JSON协议编码 45 + // 默认使用 JSON 协议编码
44 return jsonCodec.encode(message); 46 return jsonCodec.encode(message);
45 } 47 }
46 48
  49 + // TODO @haohao:要不还是不自动检测,用户手动配置哈。简化一些。。。
47 @Override 50 @Override
48 public IotDeviceMessage decode(byte[] bytes) { 51 public IotDeviceMessage decode(byte[] bytes) {
49 // 自动检测协议类型并解码 52 // 自动检测协议类型并解码
50 if (isJsonFormat(bytes)) { 53 if (isJsonFormat(bytes)) {
51 if (log.isDebugEnabled()) { 54 if (log.isDebugEnabled()) {
52 - log.debug("[decode][检测到JSON协议] 数据长度: {}字节", bytes.length); 55 + log.debug("[decode][检测到 JSON 协议,数据长度: {} 字节]", bytes.length);
53 } 56 }
54 return jsonCodec.decode(bytes); 57 return jsonCodec.decode(bytes);
55 } else { 58 } else {
56 if (log.isDebugEnabled()) { 59 if (log.isDebugEnabled()) {
57 - log.debug("[decode][检测到二进制协议] 数据长度: {}字节", bytes.length); 60 + log.debug("[decode][检测到二进制协议,数据长度: {} 字节]", bytes.length);
58 } 61 }
59 return binaryCodec.decode(bytes); 62 return binaryCodec.decode(bytes);
60 } 63 }
@@ -63,7 +66,7 @@ public class IotTcpCodecManager implements IotDeviceMessageCodec { @@ -63,7 +66,7 @@ public class IotTcpCodecManager implements IotDeviceMessageCodec {
63 // ==================== 便捷方法 ==================== 66 // ==================== 便捷方法 ====================
64 67
65 /** 68 /**
66 - * 使用JSON协议编码 69 + * 使用 JSON 协议编码
67 */ 70 */
68 public byte[] encodeJson(IotDeviceMessage message) { 71 public byte[] encodeJson(IotDeviceMessage message) {
69 return jsonCodec.encode(message); 72 return jsonCodec.encode(message);
@@ -95,42 +98,46 @@ public class IotTcpCodecManager implements IotDeviceMessageCodec { @@ -95,42 +98,46 @@ public class IotTcpCodecManager implements IotDeviceMessageCodec {
95 98
96 /** 99 /**
97 * 检测是否为JSON格式 100 * 检测是否为JSON格式
98 - * 101 + *
99 * 检测规则: 102 * 检测规则:
100 * 1. 数据以 '{' 开头 103 * 1. 数据以 '{' 开头
101 * 2. 包含 "method" 或 "id" 字段 104 * 2. 包含 "method" 或 "id" 字段
102 */ 105 */
103 private boolean isJsonFormat(byte[] bytes) { 106 private boolean isJsonFormat(byte[] bytes) {
  107 + // TODO @haohao:ArrayUtil.isEmpty(bytes) 可以简化下
104 if (bytes == null || bytes.length == 0) { 108 if (bytes == null || bytes.length == 0) {
105 return useJsonByDefault; 109 return useJsonByDefault;
106 } 110 }
107 111
108 try { 112 try {
109 - // 检测JSON格式:以 '{' 开头 113 + // 检测 JSON 格式:以 '{' 开头
110 if (bytes[0] == '{') { 114 if (bytes[0] == '{') {
111 - // 进一步验证是否为有效JSON 115 + // TODO @haohao:不一定按照顺序写,这个可能要看下。
  116 + // 进一步验证是否为有效 JSON
112 String jsonStr = new String(bytes, 0, Math.min(bytes.length, 100)); 117 String jsonStr = new String(bytes, 0, Math.min(bytes.length, 100));
113 return jsonStr.contains("\"method\"") || jsonStr.contains("\"id\""); 118 return jsonStr.contains("\"method\"") || jsonStr.contains("\"id\"");
114 } 119 }
115 120
116 // 检测二进制格式:长度 >= 8 且符合二进制协议结构 121 // 检测二进制格式:长度 >= 8 且符合二进制协议结构
117 if (bytes.length >= 8) { 122 if (bytes.length >= 8) {
118 - // 读取包头(前4字节表示后续数据长度) 123 + // 读取包头(前 4 字节表示后续数据长度)
119 int expectedLength = ((bytes[0] & 0xFF) << 24) | 124 int expectedLength = ((bytes[0] & 0xFF) << 24) |
120 ((bytes[1] & 0xFF) << 16) | 125 ((bytes[1] & 0xFF) << 16) |
121 ((bytes[2] & 0xFF) << 8) | 126 ((bytes[2] & 0xFF) << 8) |
122 (bytes[3] & 0xFF); 127 (bytes[3] & 0xFF);
123 - 128 +
124 // 验证长度是否合理 129 // 验证长度是否合理
  130 + // TODO @haohao:expectedLength > 0 多余的貌似;
125 if (expectedLength == bytes.length - 4 && expectedLength > 0 && expectedLength < 1024 * 1024) { 131 if (expectedLength == bytes.length - 4 && expectedLength > 0 && expectedLength < 1024 * 1024) {
126 return false; // 二进制格式 132 return false; // 二进制格式
127 } 133 }
128 } 134 }
129 } catch (Exception e) { 135 } catch (Exception e) {
130 - log.warn("[isJsonFormat][协议检测异常] 使用默认协议: {}", getDefaultProtocol(), e); 136 + log.warn("[isJsonFormat][协议检测异常,使用默认协议: {}]", getDefaultProtocol(), e);
131 } 137 }
132 138
133 // 默认使用当前设置的协议类型 139 // 默认使用当前设置的协议类型
134 return useJsonByDefault; 140 return useJsonByDefault;
135 } 141 }
  142 +
136 } 143 }
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/tcp/IotTcpJsonDeviceMessageCodec.java
@@ -12,16 +12,16 @@ import org.springframework.stereotype.Component; @@ -12,16 +12,16 @@ import org.springframework.stereotype.Component;
12 import java.nio.charset.StandardCharsets; 12 import java.nio.charset.StandardCharsets;
13 13
14 /** 14 /**
15 - * TCP JSON格式 {@link IotDeviceMessage} 编解码器  
16 - *  
17 - * 采用纯JSON格式传输,参考EMQX和HTTP模块的数据格式  
18 - * 15 + * TCP JSON 格式 {@link IotDeviceMessage} 编解码器
  16 + *
  17 + * 采用纯 JSON 格式传输,参考 EMQX 和 HTTP 模块的数据格式
  18 + *
19 * JSON消息格式: 19 * JSON消息格式:
20 * { 20 * {
21 - * "id": "消息ID", 21 + * "id": "消息 ID",
22 * "method": "消息方法", 22 * "method": "消息方法",
23 - * "deviceId": "设备ID",  
24 - * "productKey": "产品Key", 23 + * "deviceId": "设备 ID",
  24 + * "productKey": "产品 Key",
25 * "deviceName": "设备名称", 25 * "deviceName": "设备名称",
26 * "params": {...}, 26 * "params": {...},
27 * "timestamp": 时间戳 27 * "timestamp": 时间戳
@@ -35,6 +35,7 @@ public class IotTcpJsonDeviceMessageCodec implements IotDeviceMessageCodec { @@ -35,6 +35,7 @@ public class IotTcpJsonDeviceMessageCodec implements IotDeviceMessageCodec {
35 35
36 public static final String TYPE = "TCP_JSON"; 36 public static final String TYPE = "TCP_JSON";
37 37
  38 + // TODO @haohao:变量不太对;
38 // ==================== 常量定义 ==================== 39 // ==================== 常量定义 ====================
39 40
40 @Override 41 @Override
@@ -77,14 +78,15 @@ public class IotTcpJsonDeviceMessageCodec implements IotDeviceMessageCodec { @@ -77,14 +78,15 @@ public class IotTcpJsonDeviceMessageCodec implements IotDeviceMessageCodec {
77 } 78 }
78 79
79 try { 80 try {
80 - // 转换为JSON字符串 81 + // 转换为 JSON 字符串
81 String jsonString = new String(bytes, StandardCharsets.UTF_8); 82 String jsonString = new String(bytes, StandardCharsets.UTF_8);
82 83
83 if (log.isDebugEnabled()) { 84 if (log.isDebugEnabled()) {
84 log.debug("[decode][开始解码] JSON长度: {}字节, 内容: {}", bytes.length, jsonString); 85 log.debug("[decode][开始解码] JSON长度: {}字节, 内容: {}", bytes.length, jsonString);
85 } 86 }
86 87
87 - // 解析JSON消息 88 + // 解析 JSON 消息
  89 + // TODO @haohao:JsonUtils
88 JSONObject jsonMessage = JSONUtil.parseObj(jsonString); 90 JSONObject jsonMessage = JSONUtil.parseObj(jsonString);
89 91
90 // 构建IoT设备消息 92 // 构建IoT设备消息
@@ -129,7 +131,7 @@ public class IotTcpJsonDeviceMessageCodec implements IotDeviceMessageCodec { @@ -129,7 +131,7 @@ public class IotTcpJsonDeviceMessageCodec implements IotDeviceMessageCodec {
129 } 131 }
130 132
131 /** 133 /**
132 - * 构建JSON消息 134 + * 构建 JSON 消息
133 */ 135 */
134 private JSONObject buildJsonMessage(IotDeviceMessage message) { 136 private JSONObject buildJsonMessage(IotDeviceMessage message) {
135 JSONObject jsonMessage = new JSONObject(); 137 JSONObject jsonMessage = new JSONObject();
@@ -189,7 +191,7 @@ public class IotTcpJsonDeviceMessageCodec implements IotDeviceMessageCodec { @@ -189,7 +191,7 @@ public class IotTcpJsonDeviceMessageCodec implements IotDeviceMessageCodec {
189 message.setMsg(msg); 191 message.setMsg(msg);
190 } 192 }
191 193
192 - // 设置服务ID(基于JSON格式) 194 + // 设置服务 ID(基于 JSON 格式)
193 message.setServerId(generateServerId(jsonMessage)); 195 message.setServerId(generateServerId(jsonMessage));
194 196
195 return message; 197 return message;
@@ -216,22 +218,26 @@ public class IotTcpJsonDeviceMessageCodec implements IotDeviceMessageCodec { @@ -216,22 +218,26 @@ public class IotTcpJsonDeviceMessageCodec implements IotDeviceMessageCodec {
216 StrUtil.isNotEmpty(id) ? id.substring(0, Math.min(8, id.length())) : "noId"); 218 StrUtil.isNotEmpty(id) ? id.substring(0, Math.min(8, id.length())) : "noId");
217 } 219 }
218 220
  221 + // TODO @haohao:注释格式不对;
219 /** 222 /**
220 * 消息方法常量 223 * 消息方法常量
221 */ 224 */
222 public static class MessageMethod { 225 public static class MessageMethod {
  226 +
223 public static final String PROPERTY_POST = "thing.property.post"; // 数据上报 227 public static final String PROPERTY_POST = "thing.property.post"; // 数据上报
224 public static final String STATE_ONLINE = "thing.state.online"; // 心跳 228 public static final String STATE_ONLINE = "thing.state.online"; // 心跳
225 public static final String EVENT_POST = "thing.event.post"; // 事件上报 229 public static final String EVENT_POST = "thing.event.post"; // 事件上报
226 public static final String PROPERTY_SET = "thing.property.set"; // 属性设置 230 public static final String PROPERTY_SET = "thing.property.set"; // 属性设置
227 public static final String PROPERTY_GET = "thing.property.get"; // 属性获取 231 public static final String PROPERTY_GET = "thing.property.get"; // 属性获取
228 public static final String SERVICE_INVOKE = "thing.service.invoke"; // 服务调用 232 public static final String SERVICE_INVOKE = "thing.service.invoke"; // 服务调用
  233 +
229 } 234 }
230 235
231 /** 236 /**
232 * JSON字段名(参考EMQX和HTTP模块格式) 237 * JSON字段名(参考EMQX和HTTP模块格式)
233 */ 238 */
234 private static class JsonField { 239 private static class JsonField {
  240 +
235 public static final String ID = "id"; 241 public static final String ID = "id";
236 public static final String METHOD = "method"; 242 public static final String METHOD = "method";
237 public static final String DEVICE_ID = "deviceId"; 243 public static final String DEVICE_ID = "deviceId";
@@ -241,5 +247,6 @@ public class IotTcpJsonDeviceMessageCodec implements IotDeviceMessageCodec { @@ -241,5 +247,6 @@ public class IotTcpJsonDeviceMessageCodec implements IotDeviceMessageCodec {
241 public static final String TIMESTAMP = "timestamp"; 247 public static final String TIMESTAMP = "timestamp";
242 public static final String CODE = "code"; 248 public static final String CODE = "code";
243 public static final String MESSAGE = "message"; 249 public static final String MESSAGE = "message";
  250 +
244 } 251 }
245 } 252 }
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotTcpUpstreamProtocol.java
@@ -30,6 +30,7 @@ public class IotTcpUpstreamProtocol { @@ -30,6 +30,7 @@ public class IotTcpUpstreamProtocol {
30 30
31 private final IotDeviceMessageService messageService; 31 private final IotDeviceMessageService messageService;
32 32
  33 + // TODO @haohao:不用的变量,可以删除;
33 private final IotDeviceCommonApi deviceApi; 34 private final IotDeviceCommonApi deviceApi;
34 35
35 private final IotTcpCodecManager codecManager; 36 private final IotTcpCodecManager codecManager;
@@ -58,6 +59,7 @@ public class IotTcpUpstreamProtocol { @@ -58,6 +59,7 @@ public class IotTcpUpstreamProtocol {
58 59
59 @PostConstruct 60 @PostConstruct
60 public void start() { 61 public void start() {
  62 + // TODO @haohao:类似下面 62 到 75 是处理 options 的,因为中间写了注释,其实可以不用空行;然后 77 到 91 可以中间空喊去掉,更紧凑一点;
61 // 创建服务器选项 63 // 创建服务器选项
62 NetServerOptions options = new NetServerOptions() 64 NetServerOptions options = new NetServerOptions()
63 .setPort(tcpProperties.getPort()) 65 .setPort(tcpProperties.getPort())
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpDownstreamHandler.java
1 package cn.iocoder.yudao.module.iot.gateway.protocol.tcp.router; 1 package cn.iocoder.yudao.module.iot.gateway.protocol.tcp.router;
2 2
3 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; 3 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
4 -import cn.iocoder.yudao.module.iot.gateway.codec.tcp.IotTcpDeviceMessageCodec;  
5 import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService; 4 import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService;
6 import lombok.extern.slf4j.Slf4j; 5 import lombok.extern.slf4j.Slf4j;
7 6
@@ -24,11 +23,12 @@ public class IotTcpDownstreamHandler { @@ -24,11 +23,12 @@ public class IotTcpDownstreamHandler {
24 23
25 private final IotDeviceMessageService messageService; 24 private final IotDeviceMessageService messageService;
26 25
27 - private final IotTcpDeviceMessageCodec codec; 26 + // TODO @haohao:代码没提交全,有报错。
  27 +// private final IotTcpDeviceMessageCodec codec;
28 28
29 public IotTcpDownstreamHandler(IotDeviceMessageService messageService) { 29 public IotTcpDownstreamHandler(IotDeviceMessageService messageService) {
30 this.messageService = messageService; 30 this.messageService = messageService;
31 - this.codec = new IotTcpDeviceMessageCodec(); 31 +// this.codec = new IotTcpDeviceMessageCodec();
32 } 32 }
33 33
34 /** 34 /**
@@ -42,7 +42,8 @@ public class IotTcpDownstreamHandler { @@ -42,7 +42,8 @@ public class IotTcpDownstreamHandler {
42 message.getDeviceId(), message.getMethod(), message.getId()); 42 message.getDeviceId(), message.getMethod(), message.getId());
43 43
44 // 编码消息用于日志记录和验证 44 // 编码消息用于日志记录和验证
45 - byte[] encodedMessage = codec.encode(message); 45 + byte[] encodedMessage = null;
  46 +// codec.encode(message);
46 log.debug("[handle][消息编码成功] 设备ID: {}, 编码后长度: {} 字节", 47 log.debug("[handle][消息编码成功] 设备ID: {}, 编码后长度: {} 字节",
47 message.getDeviceId(), encodedMessage.length); 48 message.getDeviceId(), encodedMessage.length);
48 49
yudao-module-iot/yudao-module-iot-gateway/src/test/java/cn/iocoder/yudao/module/iot/gateway/codec/tcp/TcpBinaryDataPacketExamples.java
@@ -6,6 +6,7 @@ import lombok.extern.slf4j.Slf4j; @@ -6,6 +6,7 @@ import lombok.extern.slf4j.Slf4j;
6 import java.util.HashMap; 6 import java.util.HashMap;
7 import java.util.Map; 7 import java.util.Map;
8 8
  9 +// TODO @haohao:这种写成单测,会好点
9 /** 10 /**
10 * TCP二进制格式数据包示例 11 * TCP二进制格式数据包示例
11 * 12 *
@@ -21,13 +22,13 @@ public class TcpBinaryDataPacketExamples { @@ -21,13 +22,13 @@ public class TcpBinaryDataPacketExamples {
21 22
22 public static void main(String[] args) { 23 public static void main(String[] args) {
23 IotTcpBinaryDeviceMessageCodec codec = new IotTcpBinaryDeviceMessageCodec(); 24 IotTcpBinaryDeviceMessageCodec codec = new IotTcpBinaryDeviceMessageCodec();
24 - 25 +
25 // 1. 数据上报包示例 26 // 1. 数据上报包示例
26 demonstrateDataReport(codec); 27 demonstrateDataReport(codec);
27 - 28 +
28 // 2. 心跳包示例 29 // 2. 心跳包示例
29 demonstrateHeartbeat(codec); 30 demonstrateHeartbeat(codec);
30 - 31 +
31 // 3. 复杂数据上报示例 32 // 3. 复杂数据上报示例
32 demonstrateComplexDataReport(codec); 33 demonstrateComplexDataReport(codec);
33 } 34 }
@@ -37,23 +38,23 @@ public class TcpBinaryDataPacketExamples { @@ -37,23 +38,23 @@ public class TcpBinaryDataPacketExamples {
37 */ 38 */
38 private static void demonstrateDataReport(IotTcpBinaryDeviceMessageCodec codec) { 39 private static void demonstrateDataReport(IotTcpBinaryDeviceMessageCodec codec) {
39 log.info("=== 二进制格式数据上报包示例 ==="); 40 log.info("=== 二进制格式数据上报包示例 ===");
40 - 41 +
41 // 创建传感器数据 42 // 创建传感器数据
42 Map<String, Object> sensorData = new HashMap<>(); 43 Map<String, Object> sensorData = new HashMap<>();
43 sensorData.put("temperature", 25.5); 44 sensorData.put("temperature", 25.5);
44 sensorData.put("humidity", 60.2); 45 sensorData.put("humidity", 60.2);
45 sensorData.put("pressure", 1013.25); 46 sensorData.put("pressure", 1013.25);
46 sensorData.put("battery", 85); 47 sensorData.put("battery", 85);
47 - 48 +
48 // 创建设备消息 49 // 创建设备消息
49 IotDeviceMessage message = IotDeviceMessage.requestOf("thing.property.post", sensorData); 50 IotDeviceMessage message = IotDeviceMessage.requestOf("thing.property.post", sensorData);
50 message.setDeviceId(123456L); 51 message.setDeviceId(123456L);
51 - 52 +
52 // 编码 53 // 编码
53 byte[] packet = codec.encode(message); 54 byte[] packet = codec.encode(message);
54 log.info("编码后数据包长度: {} 字节", packet.length); 55 log.info("编码后数据包长度: {} 字节", packet.length);
55 log.info("编码后数据包(HEX): {}", bytesToHex(packet)); 56 log.info("编码后数据包(HEX): {}", bytesToHex(packet));
56 - 57 +
57 // 解码验证 58 // 解码验证
58 IotDeviceMessage decoded = codec.decode(packet); 59 IotDeviceMessage decoded = codec.decode(packet);
59 log.info("解码后消息ID: {}", decoded.getId()); 60 log.info("解码后消息ID: {}", decoded.getId());
@@ -63,7 +64,7 @@ public class TcpBinaryDataPacketExamples { @@ -63,7 +64,7 @@ public class TcpBinaryDataPacketExamples {
63 log.info("解码后服务ID: {}", decoded.getServerId()); 64 log.info("解码后服务ID: {}", decoded.getServerId());
64 log.info("解码后上报时间: {}", decoded.getReportTime()); 65 log.info("解码后上报时间: {}", decoded.getReportTime());
65 log.info("解码后参数: {}", decoded.getParams()); 66 log.info("解码后参数: {}", decoded.getParams());
66 - 67 +
67 System.out.println(); 68 System.out.println();
68 } 69 }
69 70
@@ -72,16 +73,16 @@ public class TcpBinaryDataPacketExamples { @@ -72,16 +73,16 @@ public class TcpBinaryDataPacketExamples {
72 */ 73 */
73 private static void demonstrateHeartbeat(IotTcpBinaryDeviceMessageCodec codec) { 74 private static void demonstrateHeartbeat(IotTcpBinaryDeviceMessageCodec codec) {
74 log.info("=== 二进制格式心跳包示例 ==="); 75 log.info("=== 二进制格式心跳包示例 ===");
75 - 76 +
76 // 创建心跳消息 77 // 创建心跳消息
77 IotDeviceMessage heartbeat = IotDeviceMessage.requestOf("thing.state.online", null); 78 IotDeviceMessage heartbeat = IotDeviceMessage.requestOf("thing.state.online", null);
78 heartbeat.setDeviceId(123456L); 79 heartbeat.setDeviceId(123456L);
79 - 80 +
80 // 编码 81 // 编码
81 byte[] packet = codec.encode(heartbeat); 82 byte[] packet = codec.encode(heartbeat);
82 log.info("心跳包长度: {} 字节", packet.length); 83 log.info("心跳包长度: {} 字节", packet.length);
83 log.info("心跳包(HEX): {}", bytesToHex(packet)); 84 log.info("心跳包(HEX): {}", bytesToHex(packet));
84 - 85 +
85 // 解码验证 86 // 解码验证
86 IotDeviceMessage decoded = codec.decode(packet); 87 IotDeviceMessage decoded = codec.decode(packet);
87 log.info("解码后消息ID: {}", decoded.getId()); 88 log.info("解码后消息ID: {}", decoded.getId());
@@ -90,7 +91,7 @@ public class TcpBinaryDataPacketExamples { @@ -90,7 +91,7 @@ public class TcpBinaryDataPacketExamples {
90 log.info("解码后设备ID: {}", decoded.getDeviceId()); 91 log.info("解码后设备ID: {}", decoded.getDeviceId());
91 log.info("解码后服务ID: {}", decoded.getServerId()); 92 log.info("解码后服务ID: {}", decoded.getServerId());
92 log.info("解码后参数: {}", decoded.getParams()); 93 log.info("解码后参数: {}", decoded.getParams());
93 - 94 +
94 System.out.println(); 95 System.out.println();
95 } 96 }
96 97
@@ -99,40 +100,40 @@ public class TcpBinaryDataPacketExamples { @@ -99,40 +100,40 @@ public class TcpBinaryDataPacketExamples {
99 */ 100 */
100 private static void demonstrateComplexDataReport(IotTcpBinaryDeviceMessageCodec codec) { 101 private static void demonstrateComplexDataReport(IotTcpBinaryDeviceMessageCodec codec) {
101 log.info("=== 二进制格式复杂数据上报示例 ==="); 102 log.info("=== 二进制格式复杂数据上报示例 ===");
102 - 103 +
103 // 创建复杂设备数据 104 // 创建复杂设备数据
104 Map<String, Object> deviceData = new HashMap<>(); 105 Map<String, Object> deviceData = new HashMap<>();
105 - 106 +
106 // 环境数据 107 // 环境数据
107 Map<String, Object> environment = new HashMap<>(); 108 Map<String, Object> environment = new HashMap<>();
108 environment.put("temperature", 23.8); 109 environment.put("temperature", 23.8);
109 environment.put("humidity", 55.0); 110 environment.put("humidity", 55.0);
110 environment.put("co2", 420); 111 environment.put("co2", 420);
111 deviceData.put("environment", environment); 112 deviceData.put("environment", environment);
112 - 113 +
113 // GPS数据 114 // GPS数据
114 Map<String, Object> location = new HashMap<>(); 115 Map<String, Object> location = new HashMap<>();
115 location.put("latitude", 39.9042); 116 location.put("latitude", 39.9042);
116 location.put("longitude", 116.4074); 117 location.put("longitude", 116.4074);
117 location.put("altitude", 43.5); 118 location.put("altitude", 43.5);
118 deviceData.put("location", location); 119 deviceData.put("location", location);
119 - 120 +
120 // 设备状态 121 // 设备状态
121 Map<String, Object> status = new HashMap<>(); 122 Map<String, Object> status = new HashMap<>();
122 status.put("battery", 78); 123 status.put("battery", 78);
123 status.put("signal", -65); 124 status.put("signal", -65);
124 status.put("online", true); 125 status.put("online", true);
125 deviceData.put("status", status); 126 deviceData.put("status", status);
126 - 127 +
127 // 创建设备消息 128 // 创建设备消息
128 IotDeviceMessage message = IotDeviceMessage.requestOf("thing.property.post", deviceData); 129 IotDeviceMessage message = IotDeviceMessage.requestOf("thing.property.post", deviceData);
129 message.setDeviceId(789012L); 130 message.setDeviceId(789012L);
130 - 131 +
131 // 编码 132 // 编码
132 byte[] packet = codec.encode(message); 133 byte[] packet = codec.encode(message);
133 log.info("复杂数据包长度: {} 字节", packet.length); 134 log.info("复杂数据包长度: {} 字节", packet.length);
134 log.info("复杂数据包(HEX): {}", bytesToHex(packet)); 135 log.info("复杂数据包(HEX): {}", bytesToHex(packet));
135 - 136 +
136 // 解码验证 137 // 解码验证
137 IotDeviceMessage decoded = codec.decode(packet); 138 IotDeviceMessage decoded = codec.decode(packet);
138 log.info("解码后消息ID: {}", decoded.getId()); 139 log.info("解码后消息ID: {}", decoded.getId());
@@ -141,7 +142,7 @@ public class TcpBinaryDataPacketExamples { @@ -141,7 +142,7 @@ public class TcpBinaryDataPacketExamples {
141 log.info("解码后设备ID: {}", decoded.getDeviceId()); 142 log.info("解码后设备ID: {}", decoded.getDeviceId());
142 log.info("解码后服务ID: {}", decoded.getServerId()); 143 log.info("解码后服务ID: {}", decoded.getServerId());
143 log.info("解码后参数: {}", decoded.getParams()); 144 log.info("解码后参数: {}", decoded.getParams());
144 - 145 +
145 System.out.println(); 146 System.out.println();
146 } 147 }
147 148
@@ -164,9 +165,9 @@ public class TcpBinaryDataPacketExamples { @@ -164,9 +165,9 @@ public class TcpBinaryDataPacketExamples {
164 log.error("数据包长度不足"); 165 log.error("数据包长度不足");
165 return; 166 return;
166 } 167 }
167 - 168 +
168 int index = 0; 169 int index = 0;
169 - 170 +
170 // 解析包头(4字节) - 后续数据长度 171 // 解析包头(4字节) - 后续数据长度
171 int totalLength = ((packet[index] & 0xFF) << 24) | 172 int totalLength = ((packet[index] & 0xFF) << 24) |
172 ((packet[index + 1] & 0xFF) << 16) | 173 ((packet[index + 1] & 0xFF) << 16) |
@@ -174,27 +175,27 @@ public class TcpBinaryDataPacketExamples { @@ -174,27 +175,27 @@ public class TcpBinaryDataPacketExamples {
174 (packet[index + 3] & 0xFF); 175 (packet[index + 3] & 0xFF);
175 index += 4; 176 index += 4;
176 log.info("包头 - 后续数据长度: {} 字节", totalLength); 177 log.info("包头 - 后续数据长度: {} 字节", totalLength);
177 - 178 +
178 // 解析设备地址长度(2字节) 179 // 解析设备地址长度(2字节)
179 int addrLength = ((packet[index] & 0xFF) << 8) | (packet[index + 1] & 0xFF); 180 int addrLength = ((packet[index] & 0xFF) << 8) | (packet[index + 1] & 0xFF);
180 index += 2; 181 index += 2;
181 log.info("设备地址长度: {} 字节", addrLength); 182 log.info("设备地址长度: {} 字节", addrLength);
182 - 183 +
183 // 解析设备地址 184 // 解析设备地址
184 String deviceAddr = new String(packet, index, addrLength); 185 String deviceAddr = new String(packet, index, addrLength);
185 index += addrLength; 186 index += addrLength;
186 log.info("设备地址: {}", deviceAddr); 187 log.info("设备地址: {}", deviceAddr);
187 - 188 +
188 // 解析功能码(2字节) 189 // 解析功能码(2字节)
189 int functionCode = ((packet[index] & 0xFF) << 8) | (packet[index + 1] & 0xFF); 190 int functionCode = ((packet[index] & 0xFF) << 8) | (packet[index + 1] & 0xFF);
190 index += 2; 191 index += 2;
191 log.info("功能码: {} ({})", functionCode, getFunctionCodeName(functionCode)); 192 log.info("功能码: {} ({})", functionCode, getFunctionCodeName(functionCode));
192 - 193 +
193 // 解析消息序号(2字节) 194 // 解析消息序号(2字节)
194 int messageId = ((packet[index] & 0xFF) << 8) | (packet[index + 1] & 0xFF); 195 int messageId = ((packet[index] & 0xFF) << 8) | (packet[index + 1] & 0xFF);
195 index += 2; 196 index += 2;
196 log.info("消息序号: {}", messageId); 197 log.info("消息序号: {}", messageId);
197 - 198 +
198 // 解析包体数据 199 // 解析包体数据
199 if (index < packet.length) { 200 if (index < packet.length) {
200 String payload = new String(packet, index, packet.length - index); 201 String payload = new String(packet, index, packet.length - index);
yudao-module-iot/yudao-module-iot-gateway/src/test/java/cn/iocoder/yudao/module/iot/gateway/codec/tcp/TcpJsonDataPacketExamples.java
@@ -7,9 +7,10 @@ import java.nio.charset.StandardCharsets; @@ -7,9 +7,10 @@ import java.nio.charset.StandardCharsets;
7 import java.util.HashMap; 7 import java.util.HashMap;
8 import java.util.Map; 8 import java.util.Map;
9 9
  10 +// TODO @haohao:这种写成单测,会好点
10 /** 11 /**
11 * TCP JSON格式数据包示例 12 * TCP JSON格式数据包示例
12 - * 13 + *
13 * 演示如何使用新的JSON格式进行TCP消息编解码 14 * 演示如何使用新的JSON格式进行TCP消息编解码
14 * 15 *
15 * @author 芋道源码 16 * @author 芋道源码
@@ -19,22 +20,22 @@ public class TcpJsonDataPacketExamples { @@ -19,22 +20,22 @@ public class TcpJsonDataPacketExamples {
19 20
20 public static void main(String[] args) { 21 public static void main(String[] args) {
21 IotTcpJsonDeviceMessageCodec codec = new IotTcpJsonDeviceMessageCodec(); 22 IotTcpJsonDeviceMessageCodec codec = new IotTcpJsonDeviceMessageCodec();
22 - 23 +
23 // 1. 数据上报示例 24 // 1. 数据上报示例
24 demonstrateDataReport(codec); 25 demonstrateDataReport(codec);
25 - 26 +
26 // 2. 心跳示例 27 // 2. 心跳示例
27 demonstrateHeartbeat(codec); 28 demonstrateHeartbeat(codec);
28 - 29 +
29 // 3. 事件上报示例 30 // 3. 事件上报示例
30 demonstrateEventReport(codec); 31 demonstrateEventReport(codec);
31 - 32 +
32 // 4. 复杂数据上报示例 33 // 4. 复杂数据上报示例
33 demonstrateComplexDataReport(codec); 34 demonstrateComplexDataReport(codec);
34 - 35 +
35 // 5. 便捷方法示例 36 // 5. 便捷方法示例
36 demonstrateConvenienceMethods(); 37 demonstrateConvenienceMethods();
37 - 38 +
38 // 6. EMQX兼容性示例 39 // 6. EMQX兼容性示例
39 demonstrateEmqxCompatibility(); 40 demonstrateEmqxCompatibility();
40 } 41 }
@@ -44,24 +45,24 @@ public class TcpJsonDataPacketExamples { @@ -44,24 +45,24 @@ public class TcpJsonDataPacketExamples {
44 */ 45 */
45 private static void demonstrateDataReport(IotTcpJsonDeviceMessageCodec codec) { 46 private static void demonstrateDataReport(IotTcpJsonDeviceMessageCodec codec) {
46 log.info("=== JSON格式数据上报示例 ==="); 47 log.info("=== JSON格式数据上报示例 ===");
47 - 48 +
48 // 创建传感器数据 49 // 创建传感器数据
49 Map<String, Object> sensorData = new HashMap<>(); 50 Map<String, Object> sensorData = new HashMap<>();
50 sensorData.put("temperature", 25.5); 51 sensorData.put("temperature", 25.5);
51 sensorData.put("humidity", 60.2); 52 sensorData.put("humidity", 60.2);
52 sensorData.put("pressure", 1013.25); 53 sensorData.put("pressure", 1013.25);
53 sensorData.put("battery", 85); 54 sensorData.put("battery", 85);
54 - 55 +
55 // 创建设备消息 56 // 创建设备消息
56 IotDeviceMessage message = IotDeviceMessage.requestOf("thing.property.post", sensorData); 57 IotDeviceMessage message = IotDeviceMessage.requestOf("thing.property.post", sensorData);
57 message.setDeviceId(123456L); 58 message.setDeviceId(123456L);
58 - 59 +
59 // 编码 60 // 编码
60 byte[] packet = codec.encode(message); 61 byte[] packet = codec.encode(message);
61 String jsonString = new String(packet, StandardCharsets.UTF_8); 62 String jsonString = new String(packet, StandardCharsets.UTF_8);
62 log.info("编码后JSON: {}", jsonString); 63 log.info("编码后JSON: {}", jsonString);
63 log.info("数据包长度: {} 字节", packet.length); 64 log.info("数据包长度: {} 字节", packet.length);
64 - 65 +
65 // 解码验证 66 // 解码验证
66 IotDeviceMessage decoded = codec.decode(packet); 67 IotDeviceMessage decoded = codec.decode(packet);
67 log.info("解码后消息ID: {}", decoded.getId()); 68 log.info("解码后消息ID: {}", decoded.getId());
@@ -69,7 +70,7 @@ public class TcpJsonDataPacketExamples { @@ -69,7 +70,7 @@ public class TcpJsonDataPacketExamples {
69 log.info("解码后设备ID: {}", decoded.getDeviceId()); 70 log.info("解码后设备ID: {}", decoded.getDeviceId());
70 log.info("解码后服务ID: {}", decoded.getServerId()); 71 log.info("解码后服务ID: {}", decoded.getServerId());
71 log.info("解码后参数: {}", decoded.getParams()); 72 log.info("解码后参数: {}", decoded.getParams());
72 - 73 +
73 System.out.println(); 74 System.out.println();
74 } 75 }
75 76
@@ -78,24 +79,24 @@ public class TcpJsonDataPacketExamples { @@ -78,24 +79,24 @@ public class TcpJsonDataPacketExamples {
78 */ 79 */
79 private static void demonstrateHeartbeat(IotTcpJsonDeviceMessageCodec codec) { 80 private static void demonstrateHeartbeat(IotTcpJsonDeviceMessageCodec codec) {
80 log.info("=== JSON格式心跳示例 ==="); 81 log.info("=== JSON格式心跳示例 ===");
81 - 82 +
82 // 创建心跳消息 83 // 创建心跳消息
83 IotDeviceMessage heartbeat = IotDeviceMessage.requestOf("thing.state.online", null); 84 IotDeviceMessage heartbeat = IotDeviceMessage.requestOf("thing.state.online", null);
84 heartbeat.setDeviceId(123456L); 85 heartbeat.setDeviceId(123456L);
85 - 86 +
86 // 编码 87 // 编码
87 byte[] packet = codec.encode(heartbeat); 88 byte[] packet = codec.encode(heartbeat);
88 String jsonString = new String(packet, StandardCharsets.UTF_8); 89 String jsonString = new String(packet, StandardCharsets.UTF_8);
89 log.info("编码后JSON: {}", jsonString); 90 log.info("编码后JSON: {}", jsonString);
90 log.info("心跳包长度: {} 字节", packet.length); 91 log.info("心跳包长度: {} 字节", packet.length);
91 - 92 +
92 // 解码验证 93 // 解码验证
93 IotDeviceMessage decoded = codec.decode(packet); 94 IotDeviceMessage decoded = codec.decode(packet);
94 log.info("解码后消息ID: {}", decoded.getId()); 95 log.info("解码后消息ID: {}", decoded.getId());
95 log.info("解码后方法: {}", decoded.getMethod()); 96 log.info("解码后方法: {}", decoded.getMethod());
96 log.info("解码后设备ID: {}", decoded.getDeviceId()); 97 log.info("解码后设备ID: {}", decoded.getDeviceId());
97 log.info("解码后服务ID: {}", decoded.getServerId()); 98 log.info("解码后服务ID: {}", decoded.getServerId());
98 - 99 +
99 System.out.println(); 100 System.out.println();
100 } 101 }
101 102
@@ -104,31 +105,31 @@ public class TcpJsonDataPacketExamples { @@ -104,31 +105,31 @@ public class TcpJsonDataPacketExamples {
104 */ 105 */
105 private static void demonstrateEventReport(IotTcpJsonDeviceMessageCodec codec) { 106 private static void demonstrateEventReport(IotTcpJsonDeviceMessageCodec codec) {
106 log.info("=== JSON格式事件上报示例 ==="); 107 log.info("=== JSON格式事件上报示例 ===");
107 - 108 +
108 // 创建事件数据 109 // 创建事件数据
109 Map<String, Object> eventData = new HashMap<>(); 110 Map<String, Object> eventData = new HashMap<>();
110 eventData.put("eventType", "alarm"); 111 eventData.put("eventType", "alarm");
111 eventData.put("level", "warning"); 112 eventData.put("level", "warning");
112 eventData.put("description", "温度过高"); 113 eventData.put("description", "温度过高");
113 eventData.put("value", 45.8); 114 eventData.put("value", 45.8);
114 - 115 +
115 // 创建事件消息 116 // 创建事件消息
116 IotDeviceMessage event = IotDeviceMessage.requestOf("thing.event.post", eventData); 117 IotDeviceMessage event = IotDeviceMessage.requestOf("thing.event.post", eventData);
117 event.setDeviceId(123456L); 118 event.setDeviceId(123456L);
118 - 119 +
119 // 编码 120 // 编码
120 byte[] packet = codec.encode(event); 121 byte[] packet = codec.encode(event);
121 String jsonString = new String(packet, StandardCharsets.UTF_8); 122 String jsonString = new String(packet, StandardCharsets.UTF_8);
122 log.info("编码后JSON: {}", jsonString); 123 log.info("编码后JSON: {}", jsonString);
123 log.info("事件包长度: {} 字节", packet.length); 124 log.info("事件包长度: {} 字节", packet.length);
124 - 125 +
125 // 解码验证 126 // 解码验证
126 IotDeviceMessage decoded = codec.decode(packet); 127 IotDeviceMessage decoded = codec.decode(packet);
127 log.info("解码后消息ID: {}", decoded.getId()); 128 log.info("解码后消息ID: {}", decoded.getId());
128 log.info("解码后方法: {}", decoded.getMethod()); 129 log.info("解码后方法: {}", decoded.getMethod());
129 log.info("解码后设备ID: {}", decoded.getDeviceId()); 130 log.info("解码后设备ID: {}", decoded.getDeviceId());
130 log.info("解码后参数: {}", decoded.getParams()); 131 log.info("解码后参数: {}", decoded.getParams());
131 - 132 +
132 System.out.println(); 133 System.out.println();
133 } 134 }
134 135
@@ -137,10 +138,10 @@ public class TcpJsonDataPacketExamples { @@ -137,10 +138,10 @@ public class TcpJsonDataPacketExamples {
137 */ 138 */
138 private static void demonstrateComplexDataReport(IotTcpJsonDeviceMessageCodec codec) { 139 private static void demonstrateComplexDataReport(IotTcpJsonDeviceMessageCodec codec) {
139 log.info("=== JSON格式复杂数据上报示例 ==="); 140 log.info("=== JSON格式复杂数据上报示例 ===");
140 - 141 +
141 // 创建复杂设备数据(类似EMQX格式) 142 // 创建复杂设备数据(类似EMQX格式)
142 Map<String, Object> deviceData = new HashMap<>(); 143 Map<String, Object> deviceData = new HashMap<>();
143 - 144 +
144 // 环境数据 145 // 环境数据
145 Map<String, Object> environment = new HashMap<>(); 146 Map<String, Object> environment = new HashMap<>();
146 environment.put("temperature", 23.8); 147 environment.put("temperature", 23.8);
@@ -148,7 +149,7 @@ public class TcpJsonDataPacketExamples { @@ -148,7 +149,7 @@ public class TcpJsonDataPacketExamples {
148 environment.put("co2", 420); 149 environment.put("co2", 420);
149 environment.put("pm25", 35); 150 environment.put("pm25", 35);
150 deviceData.put("environment", environment); 151 deviceData.put("environment", environment);
151 - 152 +
152 // GPS数据 153 // GPS数据
153 Map<String, Object> location = new HashMap<>(); 154 Map<String, Object> location = new HashMap<>();
154 location.put("latitude", 39.9042); 155 location.put("latitude", 39.9042);
@@ -156,7 +157,7 @@ public class TcpJsonDataPacketExamples { @@ -156,7 +157,7 @@ public class TcpJsonDataPacketExamples {
156 location.put("altitude", 43.5); 157 location.put("altitude", 43.5);
157 location.put("speed", 0.0); 158 location.put("speed", 0.0);
158 deviceData.put("location", location); 159 deviceData.put("location", location);
159 - 160 +
160 // 设备状态 161 // 设备状态
161 Map<String, Object> status = new HashMap<>(); 162 Map<String, Object> status = new HashMap<>();
162 status.put("battery", 78); 163 status.put("battery", 78);
@@ -164,24 +165,24 @@ public class TcpJsonDataPacketExamples { @@ -164,24 +165,24 @@ public class TcpJsonDataPacketExamples {
164 status.put("online", true); 165 status.put("online", true);
165 status.put("version", "1.2.3"); 166 status.put("version", "1.2.3");
166 deviceData.put("status", status); 167 deviceData.put("status", status);
167 - 168 +
168 // 创建设备消息 169 // 创建设备消息
169 IotDeviceMessage message = IotDeviceMessage.requestOf("thing.property.post", deviceData); 170 IotDeviceMessage message = IotDeviceMessage.requestOf("thing.property.post", deviceData);
170 message.setDeviceId(789012L); 171 message.setDeviceId(789012L);
171 - 172 +
172 // 编码 173 // 编码
173 byte[] packet = codec.encode(message); 174 byte[] packet = codec.encode(message);
174 String jsonString = new String(packet, StandardCharsets.UTF_8); 175 String jsonString = new String(packet, StandardCharsets.UTF_8);
175 log.info("编码后JSON: {}", jsonString); 176 log.info("编码后JSON: {}", jsonString);
176 log.info("复杂数据包长度: {} 字节", packet.length); 177 log.info("复杂数据包长度: {} 字节", packet.length);
177 - 178 +
178 // 解码验证 179 // 解码验证
179 IotDeviceMessage decoded = codec.decode(packet); 180 IotDeviceMessage decoded = codec.decode(packet);
180 log.info("解码后消息ID: {}", decoded.getId()); 181 log.info("解码后消息ID: {}", decoded.getId());
181 log.info("解码后方法: {}", decoded.getMethod()); 182 log.info("解码后方法: {}", decoded.getMethod());
182 log.info("解码后设备ID: {}", decoded.getDeviceId()); 183 log.info("解码后设备ID: {}", decoded.getDeviceId());
183 log.info("解码后参数: {}", decoded.getParams()); 184 log.info("解码后参数: {}", decoded.getParams());
184 - 185 +
185 System.out.println(); 186 System.out.println();
186 } 187 }
187 188
@@ -190,9 +191,9 @@ public class TcpJsonDataPacketExamples { @@ -190,9 +191,9 @@ public class TcpJsonDataPacketExamples {
190 */ 191 */
191 private static void demonstrateConvenienceMethods() { 192 private static void demonstrateConvenienceMethods() {
192 log.info("=== 便捷方法示例 ==="); 193 log.info("=== 便捷方法示例 ===");
193 - 194 +
194 IotTcpJsonDeviceMessageCodec codec = new IotTcpJsonDeviceMessageCodec(); 195 IotTcpJsonDeviceMessageCodec codec = new IotTcpJsonDeviceMessageCodec();
195 - 196 +
196 // 使用便捷方法编码数据上报 197 // 使用便捷方法编码数据上报
197 Map<String, Object> sensorData = Map.of( 198 Map<String, Object> sensorData = Map.of(
198 "temperature", 26.5, 199 "temperature", 26.5,
@@ -200,11 +201,11 @@ public class TcpJsonDataPacketExamples { @@ -200,11 +201,11 @@ public class TcpJsonDataPacketExamples {
200 ); 201 );
201 byte[] dataPacket = codec.encodeDataReport(sensorData, 123456L, "smart_sensor", "device_001"); 202 byte[] dataPacket = codec.encodeDataReport(sensorData, 123456L, "smart_sensor", "device_001");
202 log.info("便捷方法编码数据上报: {}", new String(dataPacket, StandardCharsets.UTF_8)); 203 log.info("便捷方法编码数据上报: {}", new String(dataPacket, StandardCharsets.UTF_8));
203 - 204 +
204 // 使用便捷方法编码心跳 205 // 使用便捷方法编码心跳
205 byte[] heartbeatPacket = codec.encodeHeartbeat(123456L, "smart_sensor", "device_001"); 206 byte[] heartbeatPacket = codec.encodeHeartbeat(123456L, "smart_sensor", "device_001");
206 log.info("便捷方法编码心跳: {}", new String(heartbeatPacket, StandardCharsets.UTF_8)); 207 log.info("便捷方法编码心跳: {}", new String(heartbeatPacket, StandardCharsets.UTF_8));
207 - 208 +
208 // 使用便捷方法编码事件 209 // 使用便捷方法编码事件
209 Map<String, Object> eventData = Map.of( 210 Map<String, Object> eventData = Map.of(
210 "eventType", "maintenance", 211 "eventType", "maintenance",
@@ -212,7 +213,7 @@ public class TcpJsonDataPacketExamples { @@ -212,7 +213,7 @@ public class TcpJsonDataPacketExamples {
212 ); 213 );
213 byte[] eventPacket = codec.encodeEventReport(eventData, 123456L, "smart_sensor", "device_001"); 214 byte[] eventPacket = codec.encodeEventReport(eventData, 123456L, "smart_sensor", "device_001");
214 log.info("便捷方法编码事件: {}", new String(eventPacket, StandardCharsets.UTF_8)); 215 log.info("便捷方法编码事件: {}", new String(eventPacket, StandardCharsets.UTF_8));
215 - 216 +
216 System.out.println(); 217 System.out.println();
217 } 218 }
218 219
@@ -221,7 +222,7 @@ public class TcpJsonDataPacketExamples { @@ -221,7 +222,7 @@ public class TcpJsonDataPacketExamples {
221 */ 222 */
222 private static void demonstrateEmqxCompatibility() { 223 private static void demonstrateEmqxCompatibility() {
223 log.info("=== EMQX格式兼容性示例 ==="); 224 log.info("=== EMQX格式兼容性示例 ===");
224 - 225 +
225 // 模拟EMQX风格的消息格式 226 // 模拟EMQX风格的消息格式
226 String emqxStyleJson = """ 227 String emqxStyleJson = """
227 { 228 {
@@ -235,19 +236,19 @@ public class TcpJsonDataPacketExamples { @@ -235,19 +236,19 @@ public class TcpJsonDataPacketExamples {
235 "timestamp": 1642781234567 236 "timestamp": 1642781234567
236 } 237 }
237 """; 238 """;
238 - 239 +
239 IotTcpJsonDeviceMessageCodec codec = new IotTcpJsonDeviceMessageCodec(); 240 IotTcpJsonDeviceMessageCodec codec = new IotTcpJsonDeviceMessageCodec();
240 - 241 +
241 // 解码EMQX风格的消息 242 // 解码EMQX风格的消息
242 byte[] emqxBytes = emqxStyleJson.getBytes(StandardCharsets.UTF_8); 243 byte[] emqxBytes = emqxStyleJson.getBytes(StandardCharsets.UTF_8);
243 IotDeviceMessage decoded = codec.decode(emqxBytes); 244 IotDeviceMessage decoded = codec.decode(emqxBytes);
244 - 245 +
245 log.info("EMQX风格消息解码成功:"); 246 log.info("EMQX风格消息解码成功:");
246 log.info("消息ID: {}", decoded.getId()); 247 log.info("消息ID: {}", decoded.getId());
247 log.info("方法: {}", decoded.getMethod()); 248 log.info("方法: {}", decoded.getMethod());
248 log.info("设备ID: {}", decoded.getDeviceId()); 249 log.info("设备ID: {}", decoded.getDeviceId());
249 log.info("参数: {}", decoded.getParams()); 250 log.info("参数: {}", decoded.getParams());
250 - 251 +
251 System.out.println(); 252 System.out.println();
252 } 253 }
253 } 254 }