diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/tcp/IotTcpJsonDeviceMessageCodec.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/tcp/IotTcpJsonDeviceMessageCodec.java index 8f31305f17..368130d98c 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/tcp/IotTcpJsonDeviceMessageCodec.java +++ b/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; import lombok.NoArgsConstructor; import org.springframework.stereotype.Component; +import java.nio.charset.StandardCharsets; + /** * TCP JSON 格式 {@link IotDeviceMessage} 编解码器 * @@ -93,7 +95,8 @@ public class IotTcpJsonDeviceMessageCodec implements IotDeviceMessageCodec { @Override @SuppressWarnings("DataFlowIssue") public IotDeviceMessage decode(byte[] bytes) { - TcpJsonMessage tcpJsonMessage = JsonUtils.parseObject(bytes, TcpJsonMessage.class); + String jsonStr = new String(bytes, StandardCharsets.UTF_8).trim(); + TcpJsonMessage tcpJsonMessage = JsonUtils.parseObject(jsonStr, TcpJsonMessage.class); Assert.notNull(tcpJsonMessage, "消息不能为空"); Assert.notBlank(tcpJsonMessage.getMethod(), "消息方法不能为空"); return IotDeviceMessage.of( diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpUpstreamHandler.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpUpstreamHandler.java index d290d99468..1659890189 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpUpstreamHandler.java +++ b/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 { handleBusinessRequest(clientId, message, codecType, socket); } } catch (Exception e) { - log.error("[processMessage][处理消息失败,客户端 ID: {}]", clientId, e); + log.error("[processMessage][处理消息失败,客户端 ID: {},消息方法: {}]", + clientId, message.getMethod(), e); + // 发送错误响应,避免客户端一直等待 + try { + sendErrorResponse(socket, message.getRequestId(), "消息处理失败", codecType); + } catch (Exception responseEx) { + log.error("[processMessage][发送错误响应失败,客户端 ID: {}]", clientId, responseEx); + } } } @@ -140,9 +147,9 @@ public class IotTcpUpstreamHandler implements Handler { NetSocket socket) { try { // 1.1 解析认证参数 - IotDeviceAuthReqDTO authParams = JsonUtils.parseObject(message.getParams().toString(), - IotDeviceAuthReqDTO.class); + IotDeviceAuthReqDTO authParams = parseAuthParams(message.getParams()); if (authParams == null) { + log.warn("[handleAuthenticationRequest][认证参数解析失败,客户端 ID: {}]", clientId); sendErrorResponse(socket, message.getRequestId(), "认证参数不完整", codecType); return; } @@ -205,6 +212,8 @@ public class IotTcpUpstreamHandler implements Handler { // 3. 发送消息到消息总线 deviceMessageService.sendDeviceMessage(message, connectionInfo.getProductKey(), connectionInfo.getDeviceName(), serverId); + log.info("[handleBusinessRequest][发送消息到消息总线,客户端 ID: {},消息: {}", + clientId, message.toString()); } catch (Exception e) { log.error("[handleBusinessRequest][业务请求处理异常,客户端 ID: {}]", clientId, e); } @@ -359,4 +368,41 @@ public class IotTcpUpstreamHandler implements Handler { sendResponse(socket, true, message, requestId, codecType); } + /** + * 解析认证参数 + * + * @param params 参数对象(通常为 Map 类型) + * @return 认证参数 DTO,解析失败时返回 null + */ + private IotDeviceAuthReqDTO parseAuthParams(Object params) { + if (params == null) { + return null; + } + + try { + // 参数默认为 Map 类型,直接转换 + if (params instanceof java.util.Map) { + @SuppressWarnings("unchecked") + java.util.Map paramMap = (java.util.Map) params; + return new IotDeviceAuthReqDTO() + .setClientId(MapUtil.getStr(paramMap, "clientId")) + .setUsername(MapUtil.getStr(paramMap, "username")) + .setPassword(MapUtil.getStr(paramMap, "password")); + } + + // 如果已经是目标类型,直接返回 + if (params instanceof IotDeviceAuthReqDTO) { + return (IotDeviceAuthReqDTO) params; + } + + // 其他情况尝试 JSON 转换 + String jsonStr = JsonUtils.toJsonString(params); + return JsonUtils.parseObject(jsonStr, IotDeviceAuthReqDTO.class); + + } catch (Exception e) { + log.error("[parseAuthParams][解析认证参数失败]", e); + return null; + } + } + } \ No newline at end of file