Commit b0949c085116819fa76523580ca100f7ebb40692
1 parent
65cd56bc
feat:【IoT 物联网】优化 TCP JSON 编解码器和认证参数解析逻辑
Showing
2 changed files
with
53 additions
and
4 deletions
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/tcp/IotTcpJsonDeviceMessageCodec.java
| ... | ... | @@ -9,6 +9,8 @@ import lombok.Data; |
| 9 | 9 | import lombok.NoArgsConstructor; |
| 10 | 10 | import org.springframework.stereotype.Component; |
| 11 | 11 | |
| 12 | +import java.nio.charset.StandardCharsets; | |
| 13 | + | |
| 12 | 14 | /** |
| 13 | 15 | * TCP JSON 格式 {@link IotDeviceMessage} 编解码器 |
| 14 | 16 | * |
| ... | ... | @@ -93,7 +95,8 @@ public class IotTcpJsonDeviceMessageCodec implements IotDeviceMessageCodec { |
| 93 | 95 | @Override |
| 94 | 96 | @SuppressWarnings("DataFlowIssue") |
| 95 | 97 | public IotDeviceMessage decode(byte[] bytes) { |
| 96 | - TcpJsonMessage tcpJsonMessage = JsonUtils.parseObject(bytes, TcpJsonMessage.class); | |
| 98 | + String jsonStr = new String(bytes, StandardCharsets.UTF_8).trim(); | |
| 99 | + TcpJsonMessage tcpJsonMessage = JsonUtils.parseObject(jsonStr, TcpJsonMessage.class); | |
| 97 | 100 | Assert.notNull(tcpJsonMessage, "消息不能为空"); |
| 98 | 101 | Assert.notBlank(tcpJsonMessage.getMethod(), "消息方法不能为空"); |
| 99 | 102 | return IotDeviceMessage.of( | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpUpstreamHandler.java
| ... | ... | @@ -124,7 +124,14 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> { |
| 124 | 124 | handleBusinessRequest(clientId, message, codecType, socket); |
| 125 | 125 | } |
| 126 | 126 | } catch (Exception e) { |
| 127 | - log.error("[processMessage][处理消息失败,客户端 ID: {}]", clientId, e); | |
| 127 | + log.error("[processMessage][处理消息失败,客户端 ID: {},消息方法: {}]", | |
| 128 | + clientId, message.getMethod(), e); | |
| 129 | + // 发送错误响应,避免客户端一直等待 | |
| 130 | + try { | |
| 131 | + sendErrorResponse(socket, message.getRequestId(), "消息处理失败", codecType); | |
| 132 | + } catch (Exception responseEx) { | |
| 133 | + log.error("[processMessage][发送错误响应失败,客户端 ID: {}]", clientId, responseEx); | |
| 134 | + } | |
| 128 | 135 | } |
| 129 | 136 | } |
| 130 | 137 | |
| ... | ... | @@ -140,9 +147,9 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> { |
| 140 | 147 | NetSocket socket) { |
| 141 | 148 | try { |
| 142 | 149 | // 1.1 解析认证参数 |
| 143 | - IotDeviceAuthReqDTO authParams = JsonUtils.parseObject(message.getParams().toString(), | |
| 144 | - IotDeviceAuthReqDTO.class); | |
| 150 | + IotDeviceAuthReqDTO authParams = parseAuthParams(message.getParams()); | |
| 145 | 151 | if (authParams == null) { |
| 152 | + log.warn("[handleAuthenticationRequest][认证参数解析失败,客户端 ID: {}]", clientId); | |
| 146 | 153 | sendErrorResponse(socket, message.getRequestId(), "认证参数不完整", codecType); |
| 147 | 154 | return; |
| 148 | 155 | } |
| ... | ... | @@ -205,6 +212,8 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> { |
| 205 | 212 | // 3. 发送消息到消息总线 |
| 206 | 213 | deviceMessageService.sendDeviceMessage(message, connectionInfo.getProductKey(), |
| 207 | 214 | connectionInfo.getDeviceName(), serverId); |
| 215 | + log.info("[handleBusinessRequest][发送消息到消息总线,客户端 ID: {},消息: {}", | |
| 216 | + clientId, message.toString()); | |
| 208 | 217 | } catch (Exception e) { |
| 209 | 218 | log.error("[handleBusinessRequest][业务请求处理异常,客户端 ID: {}]", clientId, e); |
| 210 | 219 | } |
| ... | ... | @@ -359,4 +368,41 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> { |
| 359 | 368 | sendResponse(socket, true, message, requestId, codecType); |
| 360 | 369 | } |
| 361 | 370 | |
| 371 | + /** | |
| 372 | + * 解析认证参数 | |
| 373 | + * | |
| 374 | + * @param params 参数对象(通常为 Map 类型) | |
| 375 | + * @return 认证参数 DTO,解析失败时返回 null | |
| 376 | + */ | |
| 377 | + private IotDeviceAuthReqDTO parseAuthParams(Object params) { | |
| 378 | + if (params == null) { | |
| 379 | + return null; | |
| 380 | + } | |
| 381 | + | |
| 382 | + try { | |
| 383 | + // 参数默认为 Map 类型,直接转换 | |
| 384 | + if (params instanceof java.util.Map) { | |
| 385 | + @SuppressWarnings("unchecked") | |
| 386 | + java.util.Map<String, Object> paramMap = (java.util.Map<String, Object>) params; | |
| 387 | + return new IotDeviceAuthReqDTO() | |
| 388 | + .setClientId(MapUtil.getStr(paramMap, "clientId")) | |
| 389 | + .setUsername(MapUtil.getStr(paramMap, "username")) | |
| 390 | + .setPassword(MapUtil.getStr(paramMap, "password")); | |
| 391 | + } | |
| 392 | + | |
| 393 | + // 如果已经是目标类型,直接返回 | |
| 394 | + if (params instanceof IotDeviceAuthReqDTO) { | |
| 395 | + return (IotDeviceAuthReqDTO) params; | |
| 396 | + } | |
| 397 | + | |
| 398 | + // 其他情况尝试 JSON 转换 | |
| 399 | + String jsonStr = JsonUtils.toJsonString(params); | |
| 400 | + return JsonUtils.parseObject(jsonStr, IotDeviceAuthReqDTO.class); | |
| 401 | + | |
| 402 | + } catch (Exception e) { | |
| 403 | + log.error("[parseAuthParams][解析认证参数失败]", e); | |
| 404 | + return null; | |
| 405 | + } | |
| 406 | + } | |
| 407 | + | |
| 362 | 408 | } |
| 363 | 409 | \ No newline at end of file | ... | ... |