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