Commit d01a6e215894a4d27130528131ae9e646ce3a4c3

Authored by YunaiV
1 parent 867ec8c0

fix(iot): 修复多协议处理器的空值校验和错误码问题

1. HTTP: 增加请求体空值保护,避免 NPE 导致 500
2. HTTP: 修复 Vertx 资源泄漏,改为 Spring 管理生命周期
3. UDP/MQTT/WS/TCP: 增加动态注册参数必填字段校验
4. EMQX: 事件接口解析失败时返回空响应体,符合 Webhook 规范
5. CoAP: method 不匹配返回 4.00 而非 5.00
Showing 12 changed files with 117 additions and 105 deletions
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayConfiguration.java
... ... @@ -44,9 +44,15 @@ public class IotGatewayConfiguration {
44 44 @Slf4j
45 45 public static class HttpProtocolConfiguration {
46 46  
  47 + @Bean(name = "httpVertx", destroyMethod = "close")
  48 + public Vertx httpVertx() {
  49 + return Vertx.vertx();
  50 + }
  51 +
47 52 @Bean
48   - public IotHttpUpstreamProtocol iotHttpUpstreamProtocol(IotGatewayProperties gatewayProperties) {
49   - return new IotHttpUpstreamProtocol(gatewayProperties.getProtocol().getHttp());
  53 + public IotHttpUpstreamProtocol iotHttpUpstreamProtocol(IotGatewayProperties gatewayProperties,
  54 + @Qualifier("httpVertx") Vertx httpVertx) {
  55 + return new IotHttpUpstreamProtocol(gatewayProperties.getProtocol().getHttp(), httpVertx);
50 56 }
51 57  
52 58 @Bean
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/coap/router/IotCoapUpstreamHandler.java
1 1 package cn.iocoder.yudao.module.iot.gateway.protocol.coap.router;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4   -import cn.hutool.core.lang.Assert;
5 4 import cn.hutool.core.map.MapUtil;
6 5 import cn.hutool.core.text.StrPool;
7 6 import cn.hutool.core.util.ArrayUtil;
... ... @@ -93,7 +92,10 @@ public class IotCoapUpstreamHandler {
93 92  
94 93 // 2.2 解码消息
95 94 IotDeviceMessage message = deviceMessageService.decodeDeviceMessage(payload, productKey, deviceName);
96   - Assert.equals(method, message.getMethod(), "method 不匹配");
  95 + if (ObjUtil.notEqual(method, message.getMethod())) {
  96 + IotCoapUtils.respondError(exchange, CoAP.ResponseCode.BAD_REQUEST, "method 不匹配");
  97 + return;
  98 + }
97 99 // 2.3 发送消息到消息总线
98 100 deviceMessageService.sendDeviceMessage(message, productKey, deviceName, protocol.getServerId());
99 101  
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxAuthEventHandler.java
... ... @@ -104,7 +104,7 @@ public class IotEmqxAuthEventHandler {
104 104 JsonObject body = null;
105 105 try {
106 106 // 1. 解析请求体
107   - body = parseRequestBody(context);
  107 + body = parseEventRequestBody(context);
108 108 if (body == null) {
109 109 return;
110 110 }
... ... @@ -153,7 +153,9 @@ public class IotEmqxAuthEventHandler {
153 153 }
154 154  
155 155 /**
156   - * 解析请求体
  156 + * 解析认证接口请求体
  157 + * <p>
  158 + * 认证接口解析失败时返回 JSON 格式响应(包含 result 字段)
157 159 *
158 160 * @param context 路由上下文
159 161 * @return 请求体JSON对象,解析失败时返回null
... ... @@ -175,6 +177,30 @@ public class IotEmqxAuthEventHandler {
175 177 }
176 178  
177 179 /**
  180 + * 解析事件接口请求体
  181 + * <p>
  182 + * 事件接口解析失败时仅返回 200 状态码,无响应体(符合 EMQX Webhook 规范)
  183 + *
  184 + * @param context 路由上下文
  185 + * @return 请求体JSON对象,解析失败时返回null
  186 + */
  187 + private JsonObject parseEventRequestBody(RoutingContext context) {
  188 + try {
  189 + JsonObject body = context.body().asJsonObject();
  190 + if (body == null) {
  191 + log.info("[parseEventRequestBody][请求体为空]");
  192 + context.response().setStatusCode(SUCCESS_STATUS_CODE).end();
  193 + return null;
  194 + }
  195 + return body;
  196 + } catch (Exception e) {
  197 + log.error("[parseEventRequestBody][body({}) 解析请求体失败]", context.body().asString(), e);
  198 + context.response().setStatusCode(SUCCESS_STATUS_CODE).end();
  199 + return null;
  200 + }
  201 + }
  202 +
  203 + /**
178 204 * 执行设备认证
179 205 *
180 206 * @param clientId 客户端ID
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/IotHttpUpstreamProtocol.java
... ... @@ -6,7 +6,6 @@ import cn.iocoder.yudao.module.iot.gateway.protocol.http.router.IotHttpAuthHandl
6 6 import cn.iocoder.yudao.module.iot.gateway.protocol.http.router.IotHttpRegisterHandler;
7 7 import cn.iocoder.yudao.module.iot.gateway.protocol.http.router.IotHttpRegisterSubHandler;
8 8 import cn.iocoder.yudao.module.iot.gateway.protocol.http.router.IotHttpUpstreamHandler;
9   -import io.vertx.core.AbstractVerticle;
10 9 import io.vertx.core.Vertx;
11 10 import io.vertx.core.http.HttpServer;
12 11 import io.vertx.core.http.HttpServerOptions;
... ... @@ -24,25 +23,26 @@ import lombok.extern.slf4j.Slf4j;
24 23 * @author 芋道源码
25 24 */
26 25 @Slf4j
27   -public class IotHttpUpstreamProtocol extends AbstractVerticle {
  26 +public class IotHttpUpstreamProtocol {
28 27  
29 28 private final IotGatewayProperties.HttpProperties httpProperties;
30 29  
  30 + private final Vertx vertx;
  31 +
31 32 private HttpServer httpServer;
32 33  
33 34 @Getter
34 35 private final String serverId;
35 36  
36   - public IotHttpUpstreamProtocol(IotGatewayProperties.HttpProperties httpProperties) {
  37 + public IotHttpUpstreamProtocol(IotGatewayProperties.HttpProperties httpProperties, Vertx vertx) {
37 38 this.httpProperties = httpProperties;
  39 + this.vertx = vertx;
38 40 this.serverId = IotDeviceMessageUtils.generateServerId(httpProperties.getServerPort());
39 41 }
40 42  
41   - @Override
42 43 @PostConstruct
43 44 public void start() {
44 45 // 创建路由
45   - Vertx vertx = Vertx.vertx();
46 46 Router router = Router.router(vertx);
47 47 router.route().handler(BodyHandler.create());
48 48  
... ... @@ -76,7 +76,6 @@ public class IotHttpUpstreamProtocol extends AbstractVerticle {
76 76 }
77 77 }
78 78  
79   - @Override
80 79 @PreDestroy
81 80 public void stop() {
82 81 if (httpServer != null) {
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/router/IotHttpAuthHandler.java
... ... @@ -51,6 +51,9 @@ public class IotHttpAuthHandler extends IotHttpAbstractHandler {
51 51 public CommonResult<Object> handle0(RoutingContext context) {
52 52 // 1. 解析参数
53 53 JsonObject body = context.body().asJsonObject();
  54 + if (body == null) {
  55 + throw invalidParamException("请求体不能为空");
  56 + }
54 57 String clientId = body.getString("clientId");
55 58 if (StrUtil.isEmpty(clientId)) {
56 59 throw invalidParamException("clientId 不能为空");
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/router/IotHttpRegisterHandler.java
... ... @@ -34,6 +34,9 @@ public class IotHttpRegisterHandler extends IotHttpAbstractHandler {
34 34 public CommonResult<Object> handle0(RoutingContext context) {
35 35 // 1. 解析参数
36 36 JsonObject body = context.body().asJsonObject();
  37 + if (body == null) {
  38 + throw invalidParamException("请求体不能为空");
  39 + }
37 40 String productKey = body.getString("productKey");
38 41 if (StrUtil.isEmpty(productKey)) {
39 42 throw invalidParamException("productKey 不能为空");
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/router/IotHttpRegisterSubHandler.java
... ... @@ -11,6 +11,7 @@ import io.vertx.ext.web.RoutingContext;
11 11  
12 12 import java.util.List;
13 13  
  14 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.invalidParamException;
14 15 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
15 16  
16 17 /**
... ... @@ -44,6 +45,12 @@ public class IotHttpRegisterSubHandler extends IotHttpAbstractHandler {
44 45  
45 46 // 2. 解析子设备列表
46 47 JsonObject body = context.body().asJsonObject();
  48 + if (body == null) {
  49 + throw invalidParamException("请求体不能为空");
  50 + }
  51 + if (body.getJsonArray("params") == null) {
  52 + throw invalidParamException("params 不能为空");
  53 + }
47 54 List<cn.iocoder.yudao.module.iot.core.topic.auth.IotSubDeviceRegisterReqDTO> subDevices = JsonUtils.parseArray(
48 55 body.getJsonArray("params").toString(), cn.iocoder.yudao.module.iot.core.topic.auth.IotSubDeviceRegisterReqDTO.class);
49 56  
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/router/IotHttpUpstreamHandler.java
... ... @@ -12,6 +12,8 @@ import io.vertx.ext.web.RoutingContext;
12 12 import lombok.RequiredArgsConstructor;
13 13 import lombok.extern.slf4j.Slf4j;
14 14  
  15 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.invalidParamException;
  16 +
15 17 /**
16 18 * IoT 网关 HTTP 协议的【上行】处理器
17 19 *
... ... @@ -40,6 +42,9 @@ public class IotHttpUpstreamHandler extends IotHttpAbstractHandler {
40 42 String method = context.pathParam("*").replaceAll(StrPool.SLASH, StrPool.DOT);
41 43  
42 44 // 2.1 解析消息
  45 + if (context.body().buffer() == null) {
  46 + throw invalidParamException("请求体不能为空");
  47 + }
43 48 byte[] bytes = context.body().buffer().getBytes();
44 49 IotDeviceMessage message = deviceMessageService.decodeDeviceMessage(bytes,
45 50 productKey, deviceName);
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/mqtt/router/IotMqttUpstreamHandler.java
... ... @@ -330,15 +330,15 @@ public class IotMqttUpstreamHandler {
330 330 String clientId = endpoint.clientIdentifier();
331 331 try {
332 332 // 1. 解析注册参数
333   - IotDeviceRegisterReqDTO registerParams = parseRegisterParams(message.getParams());
334   - if (registerParams == null) {
  333 + IotDeviceRegisterReqDTO params = parseRegisterParams(message.getParams());
  334 + if (params == null) {
335 335 log.warn("[handleRegisterRequest][注册参数解析失败,客户端 ID: {}]", clientId);
336 336 sendRegisterErrorResponse(endpoint, productKey, deviceName, message.getRequestId(), "注册参数不完整");
337 337 return;
338 338 }
339 339  
340 340 // 2. 调用动态注册 API
341   - CommonResult<IotDeviceRegisterRespDTO> result = deviceApi.registerDevice(registerParams);
  341 + CommonResult<IotDeviceRegisterRespDTO> result = deviceApi.registerDevice(params);
342 342 if (result.isError()) {
343 343 log.warn("[handleRegisterRequest][注册失败,客户端 ID: {},错误: {}]", clientId, result.getMsg());
344 344 sendRegisterErrorResponse(endpoint, productKey, deviceName, message.getRequestId(), result.getMsg());
... ... @@ -348,7 +348,7 @@ public class IotMqttUpstreamHandler {
348 348 // 3. 发送成功响应(包含 deviceSecret)
349 349 sendRegisterSuccessResponse(endpoint, productKey, deviceName, message.getRequestId(), result.getData());
350 350 log.info("[handleRegisterRequest][注册成功,设备名: {},客户端 ID: {}]",
351   - registerParams.getDeviceName(), clientId);
  351 + params.getDeviceName(), clientId);
352 352 } catch (Exception e) {
353 353 log.error("[handleRegisterRequest][注册处理异常,客户端 ID: {}]", clientId, e);
354 354 sendRegisterErrorResponse(endpoint, productKey, deviceName, message.getRequestId(), "注册处理异常");
... ... @@ -361,36 +361,27 @@ public class IotMqttUpstreamHandler {
361 361 * @param params 参数对象(通常为 Map 类型)
362 362 * @return 注册参数 DTO,解析失败时返回 null
363 363 */
364   - @SuppressWarnings("unchecked")
  364 + @SuppressWarnings({"unchecked", "DuplicatedCode"})
365 365 private IotDeviceRegisterReqDTO parseRegisterParams(Object params) {
366 366 if (params == null) {
367 367 return null;
368 368 }
369   -
370 369 try {
371 370 // 参数默认为 Map 类型,直接转换
372 371 if (params instanceof Map) {
373 372 Map<String, Object> paramMap = (Map<String, Object>) params;
374   - String productKey = MapUtil.getStr(paramMap, "productKey");
375   - String deviceName = MapUtil.getStr(paramMap, "deviceName");
376   - String productSecret = MapUtil.getStr(paramMap, "productSecret");
377   - if (StrUtil.hasBlank(productKey, deviceName, productSecret)) {
378   - return null;
379   - }
380 373 return new IotDeviceRegisterReqDTO()
381   - .setProductKey(productKey)
382   - .setDeviceName(deviceName)
383   - .setProductSecret(productSecret);
  374 + .setProductKey(MapUtil.getStr(paramMap, "productKey"))
  375 + .setDeviceName(MapUtil.getStr(paramMap, "deviceName"))
  376 + .setProductSecret(MapUtil.getStr(paramMap, "productSecret"));
384 377 }
385   -
386 378 // 如果已经是目标类型,直接返回
387 379 if (params instanceof IotDeviceRegisterReqDTO) {
388 380 return (IotDeviceRegisterReqDTO) params;
389 381 }
390 382  
391 383 // 其他情况尝试 JSON 转换
392   - String jsonStr = JsonUtils.toJsonString(params);
393   - return JsonUtils.parseObject(jsonStr, IotDeviceRegisterReqDTO.class);
  384 + return JsonUtils.convertObject(params, IotDeviceRegisterReqDTO.class);
394 385 } catch (Exception e) {
395 386 log.error("[parseRegisterParams][解析注册参数({})失败]", params, e);
396 387 return null;
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpUpstreamHandler.java
... ... @@ -12,9 +12,9 @@ import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO;
12 12 import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceRespDTO;
13 13 import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
14 14 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
  15 +import cn.iocoder.yudao.module.iot.core.topic.IotDeviceIdentity;
15 16 import cn.iocoder.yudao.module.iot.core.topic.auth.IotDeviceRegisterReqDTO;
16 17 import cn.iocoder.yudao.module.iot.core.topic.auth.IotDeviceRegisterRespDTO;
17   -import cn.iocoder.yudao.module.iot.core.topic.IotDeviceIdentity;
18 18 import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils;
19 19 import cn.iocoder.yudao.module.iot.gateway.codec.tcp.IotTcpBinaryDeviceMessageCodec;
20 20 import cn.iocoder.yudao.module.iot.gateway.codec.tcp.IotTcpJsonDeviceMessageCodec;
... ... @@ -27,6 +27,8 @@ import io.vertx.core.buffer.Buffer;
27 27 import io.vertx.core.net.NetSocket;
28 28 import lombok.extern.slf4j.Slf4j;
29 29  
  30 +import java.util.Map;
  31 +
30 32 /**
31 33 * TCP 上行消息处理器
32 34 *
... ... @@ -78,6 +80,7 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
78 80  
79 81 // 设置消息处理器
80 82 socket.handler(buffer -> {
  83 + // TODO @AI:TODO @芋艿:这里应该有拆粘包的问题;
81 84 try {
82 85 processMessage(clientId, buffer, socket);
83 86 } catch (Exception e) {
... ... @@ -209,15 +212,15 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
209 212 NetSocket socket) {
210 213 try {
211 214 // 1. 解析注册参数
212   - IotDeviceRegisterReqDTO registerParams = parseRegisterParams(message.getParams());
213   - if (registerParams == null) {
  215 + IotDeviceRegisterReqDTO params = parseRegisterParams(message.getParams());
  216 + if (params == null) {
214 217 log.warn("[handleRegisterRequest][注册参数解析失败,客户端 ID: {}]", clientId);
215 218 sendErrorResponse(socket, message.getRequestId(), "注册参数不完整", codecType);
216 219 return;
217 220 }
218 221  
219 222 // 2. 调用动态注册
220   - CommonResult<IotDeviceRegisterRespDTO> result = deviceApi.registerDevice(registerParams);
  223 + CommonResult<IotDeviceRegisterRespDTO> result = deviceApi.registerDevice(params);
221 224 if (result.isError()) {
222 225 log.warn("[handleRegisterRequest][注册失败,客户端 ID: {},错误: {}]", clientId, result.getMsg());
223 226 sendErrorResponse(socket, message.getRequestId(), result.getMsg(), codecType);
... ... @@ -227,7 +230,7 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
227 230 // 3. 发送成功响应(包含 deviceSecret)
228 231 sendRegisterSuccessResponse(socket, message.getRequestId(), result.getData(), codecType);
229 232 log.info("[handleRegisterRequest][注册成功,客户端 ID: {},设备名: {}]",
230   - clientId, registerParams.getDeviceName());
  233 + clientId, params.getDeviceName());
231 234 } catch (Exception e) {
232 235 log.error("[handleRegisterRequest][注册处理异常,客户端 ID: {}]", clientId, e);
233 236 sendErrorResponse(socket, message.getRequestId(), "注册处理异常", codecType);
... ... @@ -419,30 +422,27 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
419 422 * @param params 参数对象(通常为 Map 类型)
420 423 * @return 认证参数 DTO,解析失败时返回 null
421 424 */
422   - @SuppressWarnings("unchecked")
  425 + @SuppressWarnings({"unchecked", "DuplicatedCode"})
423 426 private IotDeviceAuthReqDTO parseAuthParams(Object params) {
424 427 if (params == null) {
425 428 return null;
426 429 }
427   -
428 430 try {
429 431 // 参数默认为 Map 类型,直接转换
430   - if (params instanceof java.util.Map) {
431   - java.util.Map<String, Object> paramMap = (java.util.Map<String, Object>) params;
  432 + if (params instanceof Map) {
  433 + Map<String, Object> paramMap = (Map<String, Object>) params;
432 434 return new IotDeviceAuthReqDTO()
433 435 .setClientId(MapUtil.getStr(paramMap, "clientId"))
434 436 .setUsername(MapUtil.getStr(paramMap, "username"))
435 437 .setPassword(MapUtil.getStr(paramMap, "password"));
436 438 }
437   -
438 439 // 如果已经是目标类型,直接返回
439 440 if (params instanceof IotDeviceAuthReqDTO) {
440 441 return (IotDeviceAuthReqDTO) params;
441 442 }
442 443  
443 444 // 其他情况尝试 JSON 转换
444   - String jsonStr = JsonUtils.toJsonString(params);
445   - return JsonUtils.parseObject(jsonStr, IotDeviceAuthReqDTO.class);
  445 + return JsonUtils.convertObject(params, IotDeviceAuthReqDTO.class);
446 446 } catch (Exception e) {
447 447 log.error("[parseAuthParams][解析认证参数({})失败]", params, e);
448 448 return null;
... ... @@ -455,28 +455,20 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
455 455 * @param params 参数对象(通常为 Map 类型)
456 456 * @return 注册参数 DTO,解析失败时返回 null
457 457 */
458   - @SuppressWarnings("unchecked")
  458 + @SuppressWarnings({"unchecked", "DuplicatedCode"})
459 459 private IotDeviceRegisterReqDTO parseRegisterParams(Object params) {
460 460 if (params == null) {
461 461 return null;
462 462 }
463   -
464 463 try {
465 464 // 参数默认为 Map 类型,直接转换
466   - if (params instanceof java.util.Map) {
467   - java.util.Map<String, Object> paramMap = (java.util.Map<String, Object>) params;
468   - String productKey = MapUtil.getStr(paramMap, "productKey");
469   - String deviceName = MapUtil.getStr(paramMap, "deviceName");
470   - String productSecret = MapUtil.getStr(paramMap, "productSecret");
471   - if (StrUtil.hasBlank(productKey, deviceName, productSecret)) {
472   - return null;
473   - }
  465 + if (params instanceof Map) {
  466 + Map<String, Object> paramMap = (Map<String, Object>) params;
474 467 return new IotDeviceRegisterReqDTO()
475   - .setProductKey(productKey)
476   - .setDeviceName(deviceName)
477   - .setProductSecret(productSecret);
  468 + .setProductKey(MapUtil.getStr(paramMap, "productKey"))
  469 + .setDeviceName(MapUtil.getStr(paramMap, "deviceName"))
  470 + .setProductSecret(MapUtil.getStr(paramMap, "productSecret"));
478 471 }
479   -
480 472 // 如果已经是目标类型,直接返回
481 473 if (params instanceof IotDeviceRegisterReqDTO) {
482 474 return (IotDeviceRegisterReqDTO) params;
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/udp/router/IotUdpUpstreamHandler.java
... ... @@ -225,15 +225,15 @@ public class IotUdpUpstreamHandler {
225 225 String addressKey = sessionManager.buildAddressKey(senderAddress);
226 226 try {
227 227 // 1. 解析注册参数
228   - IotDeviceRegisterReqDTO registerParams = parseRegisterParams(message.getParams());
229   - if (registerParams == null) {
  228 + IotDeviceRegisterReqDTO params = parseRegisterParams(message.getParams());
  229 + if (params == null) {
230 230 log.warn("[handleRegisterRequest][注册参数解析失败,来源: {}]", addressKey);
231 231 sendErrorResponse(socket, senderAddress, message.getRequestId(), "注册参数不完整", codecType);
232 232 return;
233 233 }
234 234  
235 235 // 2. 调用动态注册
236   - CommonResult<IotDeviceRegisterRespDTO> result = deviceApi.registerDevice(registerParams);
  236 + CommonResult<IotDeviceRegisterRespDTO> result = deviceApi.registerDevice(params);
237 237 if (result.isError()) {
238 238 log.warn("[handleRegisterRequest][注册失败,来源: {},错误: {}]", addressKey, result.getMsg());
239 239 sendErrorResponse(socket, senderAddress, message.getRequestId(), result.getMsg(), codecType);
... ... @@ -243,7 +243,7 @@ public class IotUdpUpstreamHandler {
243 243 // 3. 发送成功响应(包含 deviceSecret)
244 244 sendRegisterSuccessResponse(socket, senderAddress, message.getRequestId(), result.getData(), codecType);
245 245 log.info("[handleRegisterRequest][注册成功,设备名: {},来源: {}]",
246   - registerParams.getDeviceName(), addressKey);
  246 + params.getDeviceName(), addressKey);
247 247 } catch (Exception e) {
248 248 log.error("[handleRegisterRequest][注册处理异常,来源: {}]", addressKey, e);
249 249 sendErrorResponse(socket, senderAddress, message.getRequestId(), "注册处理异常", codecType);
... ... @@ -484,7 +484,6 @@ public class IotUdpUpstreamHandler {
484 484 if (params == null) {
485 485 return null;
486 486 }
487   -
488 487 try {
489 488 // 参数默认为 Map 类型,直接转换
490 489 if (params instanceof Map) {
... ... @@ -494,15 +493,13 @@ public class IotUdpUpstreamHandler {
494 493 .setUsername(MapUtil.getStr(paramMap, "username"))
495 494 .setPassword(MapUtil.getStr(paramMap, "password"));
496 495 }
497   -
498 496 // 如果已经是目标类型,直接返回
499 497 if (params instanceof IotDeviceAuthReqDTO) {
500 498 return (IotDeviceAuthReqDTO) params;
501 499 }
502 500  
503 501 // 其他情况尝试 JSON 转换
504   - String jsonStr = JsonUtils.toJsonString(params);
505   - return JsonUtils.parseObject(jsonStr, IotDeviceAuthReqDTO.class);
  502 + return JsonUtils.convertObject(params, IotDeviceAuthReqDTO.class);
506 503 } catch (Exception e) {
507 504 log.error("[parseAuthParams][解析认证参数({})失败]", params, e);
508 505 return null;
... ... @@ -515,36 +512,27 @@ public class IotUdpUpstreamHandler {
515 512 * @param params 参数对象(通常为 Map 类型)
516 513 * @return 注册参数 DTO,解析失败时返回 null
517 514 */
518   - @SuppressWarnings("unchecked")
  515 + @SuppressWarnings({"unchecked", "DuplicatedCode"})
519 516 private IotDeviceRegisterReqDTO parseRegisterParams(Object params) {
520 517 if (params == null) {
521 518 return null;
522 519 }
523   -
524 520 try {
525 521 // 参数默认为 Map 类型,直接转换
526 522 if (params instanceof Map) {
527 523 Map<String, Object> paramMap = (Map<String, Object>) params;
528   - String productKey = MapUtil.getStr(paramMap, "productKey");
529   - String deviceName = MapUtil.getStr(paramMap, "deviceName");
530   - String productSecret = MapUtil.getStr(paramMap, "productSecret");
531   - if (StrUtil.hasBlank(productKey, deviceName, productSecret)) {
532   - return null;
533   - }
534 524 return new IotDeviceRegisterReqDTO()
535   - .setProductKey(productKey)
536   - .setDeviceName(deviceName)
537   - .setProductSecret(productSecret);
  525 + .setProductKey(MapUtil.getStr(paramMap, "productKey"))
  526 + .setDeviceName(MapUtil.getStr(paramMap, "deviceName"))
  527 + .setProductSecret(MapUtil.getStr(paramMap, "productSecret"));
538 528 }
539   -
540 529 // 如果已经是目标类型,直接返回
541 530 if (params instanceof IotDeviceRegisterReqDTO) {
542 531 return (IotDeviceRegisterReqDTO) params;
543 532 }
544 533  
545 534 // 其他情况尝试 JSON 转换
546   - String jsonStr = JsonUtils.toJsonString(params);
547   - return JsonUtils.parseObject(jsonStr, IotDeviceRegisterReqDTO.class);
  535 + return JsonUtils.convertObject(params, IotDeviceRegisterReqDTO.class);
548 536 } catch (Exception e) {
549 537 log.error("[parseRegisterParams][解析注册参数({})失败]", params, e);
550 538 return null;
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/websocket/router/IotWebSocketUpstreamHandler.java
... ... @@ -25,6 +25,8 @@ import io.vertx.core.Handler;
25 25 import io.vertx.core.http.ServerWebSocket;
26 26 import lombok.extern.slf4j.Slf4j;
27 27  
  28 +import java.util.Map;
  29 +
28 30  
29 31 /**
30 32 * WebSocket 上行消息处理器
... ... @@ -204,15 +206,16 @@ public class IotWebSocketUpstreamHandler implements Handler&lt;ServerWebSocket&gt; {
204 206 private void handleRegisterRequest(String clientId, IotDeviceMessage message, ServerWebSocket socket) {
205 207 try {
206 208 // 1. 解析注册参数
207   - IotDeviceRegisterReqDTO registerParams = parseRegisterParams(message.getParams());
208   - if (registerParams == null) {
  209 + IotDeviceRegisterReqDTO params = parseRegisterParams(message.getParams());
  210 + if (params == null
  211 + || StrUtil.hasEmpty(params.getProductKey(), params.getDeviceName(), params.getProductSecret())) {
209 212 log.warn("[handleRegisterRequest][注册参数解析失败,客户端 ID: {}]", clientId);
210 213 sendErrorResponse(socket, message.getRequestId(), "注册参数不完整");
211 214 return;
212 215 }
213 216  
214 217 // 2. 调用动态注册
215   - CommonResult<IotDeviceRegisterRespDTO> result = deviceApi.registerDevice(registerParams);
  218 + CommonResult<IotDeviceRegisterRespDTO> result = deviceApi.registerDevice(params);
216 219 if (result.isError()) {
217 220 log.warn("[handleRegisterRequest][注册失败,客户端 ID: {},错误: {}]", clientId, result.getMsg());
218 221 sendErrorResponse(socket, message.getRequestId(), result.getMsg());
... ... @@ -222,7 +225,7 @@ public class IotWebSocketUpstreamHandler implements Handler&lt;ServerWebSocket&gt; {
222 225 // 3. 发送成功响应(包含 deviceSecret)
223 226 sendRegisterSuccessResponse(socket, message.getRequestId(), result.getData());
224 227 log.info("[handleRegisterRequest][注册成功,客户端 ID: {},设备名: {}]",
225   - clientId, registerParams.getDeviceName());
  228 + clientId, params.getDeviceName());
226 229 } catch (Exception e) {
227 230 log.error("[handleRegisterRequest][注册处理异常,客户端 ID: {}]", clientId, e);
228 231 sendErrorResponse(socket, message.getRequestId(), "注册处理异常");
... ... @@ -384,31 +387,27 @@ public class IotWebSocketUpstreamHandler implements Handler&lt;ServerWebSocket&gt; {
384 387 * @param params 参数对象(通常为 Map 类型)
385 388 * @return 认证参数 DTO,解析失败时返回 null
386 389 */
387   - @SuppressWarnings("unchecked")
  390 + @SuppressWarnings({"unchecked", "DuplicatedCode"})
388 391 private IotDeviceAuthReqDTO parseAuthParams(Object params) {
389 392 if (params == null) {
390 393 return null;
391 394 }
392   -
393 395 try {
394 396 // 参数默认为 Map 类型,直接转换
395   - if (params instanceof java.util.Map) {
396   - java.util.Map<String, Object> paramMap = (java.util.Map<String, Object>) params;
  397 + if (params instanceof Map) {
  398 + Map<String, Object> paramMap = (Map<String, Object>) params;
397 399 return new IotDeviceAuthReqDTO()
398 400 .setClientId(MapUtil.getStr(paramMap, "clientId"))
399 401 .setUsername(MapUtil.getStr(paramMap, "username"))
400 402 .setPassword(MapUtil.getStr(paramMap, "password"));
401 403 }
402   -
403 404 // 如果已经是目标类型,直接返回
404 405 if (params instanceof IotDeviceAuthReqDTO) {
405 406 return (IotDeviceAuthReqDTO) params;
406 407 }
407 408  
408 409 // 其他情况尝试 JSON 转换
409   - // TODO @芋艿:要不要优化下;
410   - String jsonStr = JsonUtils.toJsonString(params);
411   - return JsonUtils.convertObject(jsonStr, IotDeviceAuthReqDTO.class);
  410 + return JsonUtils.convertObject(params, IotDeviceAuthReqDTO.class);
412 411 } catch (Exception e) {
413 412 log.error("[parseAuthParams][解析认证参数({})失败]", params, e);
414 413 return null;
... ... @@ -426,31 +425,22 @@ public class IotWebSocketUpstreamHandler implements Handler&lt;ServerWebSocket&gt; {
426 425 if (params == null) {
427 426 return null;
428 427 }
429   -
430 428 try {
431 429 // 参数默认为 Map 类型,直接转换
432   - if (params instanceof java.util.Map) {
433   - java.util.Map<String, Object> paramMap = (java.util.Map<String, Object>) params;
434   - String productKey = MapUtil.getStr(paramMap, "productKey");
435   - String deviceName = MapUtil.getStr(paramMap, "deviceName");
436   - String productSecret = MapUtil.getStr(paramMap, "productSecret");
437   - if (StrUtil.hasBlank(productKey, deviceName, productSecret)) {
438   - return null;
439   - }
  430 + if (params instanceof Map) {
  431 + Map<String, Object> paramMap = (Map<String, Object>) params;
440 432 return new IotDeviceRegisterReqDTO()
441   - .setProductKey(productKey)
442   - .setDeviceName(deviceName)
443   - .setProductSecret(productSecret);
  433 + .setProductKey(MapUtil.getStr(paramMap, "productKey"))
  434 + .setDeviceName(MapUtil.getStr(paramMap, "deviceName"))
  435 + .setProductSecret(MapUtil.getStr(paramMap, "productSecret"));
444 436 }
445   -
446 437 // 如果已经是目标类型,直接返回
447 438 if (params instanceof IotDeviceRegisterReqDTO) {
448 439 return (IotDeviceRegisterReqDTO) params;
449 440 }
450 441  
451 442 // 其他情况尝试 JSON 转换
452   - String jsonStr = JsonUtils.toJsonString(params);
453   - return JsonUtils.parseObject(jsonStr, IotDeviceRegisterReqDTO.class);
  443 + return JsonUtils.convertObject(params, IotDeviceRegisterReqDTO.class);
454 444 } catch (Exception e) {
455 445 log.error("[parseRegisterParams][解析注册参数({})失败]", params, e);
456 446 return null;
... ...