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
This commit is contained in:
YunaiV
2026-01-28 00:39:31 +08:00
parent 867ec8c070
commit d01a6e2158
12 changed files with 117 additions and 105 deletions

View File

@@ -44,9 +44,15 @@ public class IotGatewayConfiguration {
@Slf4j @Slf4j
public static class HttpProtocolConfiguration { public static class HttpProtocolConfiguration {
@Bean(name = "httpVertx", destroyMethod = "close")
public Vertx httpVertx() {
return Vertx.vertx();
}
@Bean @Bean
public IotHttpUpstreamProtocol iotHttpUpstreamProtocol(IotGatewayProperties gatewayProperties) { public IotHttpUpstreamProtocol iotHttpUpstreamProtocol(IotGatewayProperties gatewayProperties,
return new IotHttpUpstreamProtocol(gatewayProperties.getProtocol().getHttp()); @Qualifier("httpVertx") Vertx httpVertx) {
return new IotHttpUpstreamProtocol(gatewayProperties.getProtocol().getHttp(), httpVertx);
} }
@Bean @Bean

View File

@@ -1,7 +1,6 @@
package cn.iocoder.yudao.module.iot.gateway.protocol.coap.router; package cn.iocoder.yudao.module.iot.gateway.protocol.coap.router;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.StrPool; import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
@@ -93,7 +92,10 @@ public class IotCoapUpstreamHandler {
// 2.2 解码消息 // 2.2 解码消息
IotDeviceMessage message = deviceMessageService.decodeDeviceMessage(payload, productKey, deviceName); IotDeviceMessage message = deviceMessageService.decodeDeviceMessage(payload, productKey, deviceName);
Assert.equals(method, message.getMethod(), "method 不匹配"); if (ObjUtil.notEqual(method, message.getMethod())) {
IotCoapUtils.respondError(exchange, CoAP.ResponseCode.BAD_REQUEST, "method 不匹配");
return;
}
// 2.3 发送消息到消息总线 // 2.3 发送消息到消息总线
deviceMessageService.sendDeviceMessage(message, productKey, deviceName, protocol.getServerId()); deviceMessageService.sendDeviceMessage(message, productKey, deviceName, protocol.getServerId());

View File

@@ -104,7 +104,7 @@ public class IotEmqxAuthEventHandler {
JsonObject body = null; JsonObject body = null;
try { try {
// 1. 解析请求体 // 1. 解析请求体
body = parseRequestBody(context); body = parseEventRequestBody(context);
if (body == null) { if (body == null) {
return; return;
} }
@@ -153,7 +153,9 @@ public class IotEmqxAuthEventHandler {
} }
/** /**
* 解析请求体 * 解析认证接口请求体
* <p>
* 认证接口解析失败时返回 JSON 格式响应(包含 result 字段)
* *
* @param context 路由上下文 * @param context 路由上下文
* @return 请求体JSON对象解析失败时返回null * @return 请求体JSON对象解析失败时返回null
@@ -174,6 +176,30 @@ public class IotEmqxAuthEventHandler {
} }
} }
/**
* 解析事件接口请求体
* <p>
* 事件接口解析失败时仅返回 200 状态码,无响应体(符合 EMQX Webhook 规范)
*
* @param context 路由上下文
* @return 请求体JSON对象解析失败时返回null
*/
private JsonObject parseEventRequestBody(RoutingContext context) {
try {
JsonObject body = context.body().asJsonObject();
if (body == null) {
log.info("[parseEventRequestBody][请求体为空]");
context.response().setStatusCode(SUCCESS_STATUS_CODE).end();
return null;
}
return body;
} catch (Exception e) {
log.error("[parseEventRequestBody][body({}) 解析请求体失败]", context.body().asString(), e);
context.response().setStatusCode(SUCCESS_STATUS_CODE).end();
return null;
}
}
/** /**
* 执行设备认证 * 执行设备认证
* *

View File

@@ -6,7 +6,6 @@ import cn.iocoder.yudao.module.iot.gateway.protocol.http.router.IotHttpAuthHandl
import cn.iocoder.yudao.module.iot.gateway.protocol.http.router.IotHttpRegisterHandler; import cn.iocoder.yudao.module.iot.gateway.protocol.http.router.IotHttpRegisterHandler;
import cn.iocoder.yudao.module.iot.gateway.protocol.http.router.IotHttpRegisterSubHandler; import cn.iocoder.yudao.module.iot.gateway.protocol.http.router.IotHttpRegisterSubHandler;
import cn.iocoder.yudao.module.iot.gateway.protocol.http.router.IotHttpUpstreamHandler; import cn.iocoder.yudao.module.iot.gateway.protocol.http.router.IotHttpUpstreamHandler;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Vertx; import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServer; import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerOptions; import io.vertx.core.http.HttpServerOptions;
@@ -24,25 +23,26 @@ import lombok.extern.slf4j.Slf4j;
* @author 芋道源码 * @author 芋道源码
*/ */
@Slf4j @Slf4j
public class IotHttpUpstreamProtocol extends AbstractVerticle { public class IotHttpUpstreamProtocol {
private final IotGatewayProperties.HttpProperties httpProperties; private final IotGatewayProperties.HttpProperties httpProperties;
private final Vertx vertx;
private HttpServer httpServer; private HttpServer httpServer;
@Getter @Getter
private final String serverId; private final String serverId;
public IotHttpUpstreamProtocol(IotGatewayProperties.HttpProperties httpProperties) { public IotHttpUpstreamProtocol(IotGatewayProperties.HttpProperties httpProperties, Vertx vertx) {
this.httpProperties = httpProperties; this.httpProperties = httpProperties;
this.vertx = vertx;
this.serverId = IotDeviceMessageUtils.generateServerId(httpProperties.getServerPort()); this.serverId = IotDeviceMessageUtils.generateServerId(httpProperties.getServerPort());
} }
@Override
@PostConstruct @PostConstruct
public void start() { public void start() {
// 创建路由 // 创建路由
Vertx vertx = Vertx.vertx();
Router router = Router.router(vertx); Router router = Router.router(vertx);
router.route().handler(BodyHandler.create()); router.route().handler(BodyHandler.create());
@@ -76,7 +76,6 @@ public class IotHttpUpstreamProtocol extends AbstractVerticle {
} }
} }
@Override
@PreDestroy @PreDestroy
public void stop() { public void stop() {
if (httpServer != null) { if (httpServer != null) {

View File

@@ -51,6 +51,9 @@ public class IotHttpAuthHandler extends IotHttpAbstractHandler {
public CommonResult<Object> handle0(RoutingContext context) { public CommonResult<Object> handle0(RoutingContext context) {
// 1. 解析参数 // 1. 解析参数
JsonObject body = context.body().asJsonObject(); JsonObject body = context.body().asJsonObject();
if (body == null) {
throw invalidParamException("请求体不能为空");
}
String clientId = body.getString("clientId"); String clientId = body.getString("clientId");
if (StrUtil.isEmpty(clientId)) { if (StrUtil.isEmpty(clientId)) {
throw invalidParamException("clientId 不能为空"); throw invalidParamException("clientId 不能为空");

View File

@@ -34,6 +34,9 @@ public class IotHttpRegisterHandler extends IotHttpAbstractHandler {
public CommonResult<Object> handle0(RoutingContext context) { public CommonResult<Object> handle0(RoutingContext context) {
// 1. 解析参数 // 1. 解析参数
JsonObject body = context.body().asJsonObject(); JsonObject body = context.body().asJsonObject();
if (body == null) {
throw invalidParamException("请求体不能为空");
}
String productKey = body.getString("productKey"); String productKey = body.getString("productKey");
if (StrUtil.isEmpty(productKey)) { if (StrUtil.isEmpty(productKey)) {
throw invalidParamException("productKey 不能为空"); throw invalidParamException("productKey 不能为空");

View File

@@ -11,6 +11,7 @@ import io.vertx.ext.web.RoutingContext;
import java.util.List; import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.invalidParamException;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
/** /**
@@ -44,6 +45,12 @@ public class IotHttpRegisterSubHandler extends IotHttpAbstractHandler {
// 2. 解析子设备列表 // 2. 解析子设备列表
JsonObject body = context.body().asJsonObject(); JsonObject body = context.body().asJsonObject();
if (body == null) {
throw invalidParamException("请求体不能为空");
}
if (body.getJsonArray("params") == null) {
throw invalidParamException("params 不能为空");
}
List<cn.iocoder.yudao.module.iot.core.topic.auth.IotSubDeviceRegisterReqDTO> subDevices = JsonUtils.parseArray( List<cn.iocoder.yudao.module.iot.core.topic.auth.IotSubDeviceRegisterReqDTO> subDevices = JsonUtils.parseArray(
body.getJsonArray("params").toString(), cn.iocoder.yudao.module.iot.core.topic.auth.IotSubDeviceRegisterReqDTO.class); body.getJsonArray("params").toString(), cn.iocoder.yudao.module.iot.core.topic.auth.IotSubDeviceRegisterReqDTO.class);

View File

@@ -12,6 +12,8 @@ import io.vertx.ext.web.RoutingContext;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.invalidParamException;
/** /**
* IoT 网关 HTTP 协议的【上行】处理器 * IoT 网关 HTTP 协议的【上行】处理器
* *
@@ -40,6 +42,9 @@ public class IotHttpUpstreamHandler extends IotHttpAbstractHandler {
String method = context.pathParam("*").replaceAll(StrPool.SLASH, StrPool.DOT); String method = context.pathParam("*").replaceAll(StrPool.SLASH, StrPool.DOT);
// 2.1 解析消息 // 2.1 解析消息
if (context.body().buffer() == null) {
throw invalidParamException("请求体不能为空");
}
byte[] bytes = context.body().buffer().getBytes(); byte[] bytes = context.body().buffer().getBytes();
IotDeviceMessage message = deviceMessageService.decodeDeviceMessage(bytes, IotDeviceMessage message = deviceMessageService.decodeDeviceMessage(bytes,
productKey, deviceName); productKey, deviceName);

View File

@@ -330,15 +330,15 @@ public class IotMqttUpstreamHandler {
String clientId = endpoint.clientIdentifier(); String clientId = endpoint.clientIdentifier();
try { try {
// 1. 解析注册参数 // 1. 解析注册参数
IotDeviceRegisterReqDTO registerParams = parseRegisterParams(message.getParams()); IotDeviceRegisterReqDTO params = parseRegisterParams(message.getParams());
if (registerParams == null) { if (params == null) {
log.warn("[handleRegisterRequest][注册参数解析失败,客户端 ID: {}]", clientId); log.warn("[handleRegisterRequest][注册参数解析失败,客户端 ID: {}]", clientId);
sendRegisterErrorResponse(endpoint, productKey, deviceName, message.getRequestId(), "注册参数不完整"); sendRegisterErrorResponse(endpoint, productKey, deviceName, message.getRequestId(), "注册参数不完整");
return; return;
} }
// 2. 调用动态注册 API // 2. 调用动态注册 API
CommonResult<IotDeviceRegisterRespDTO> result = deviceApi.registerDevice(registerParams); CommonResult<IotDeviceRegisterRespDTO> result = deviceApi.registerDevice(params);
if (result.isError()) { if (result.isError()) {
log.warn("[handleRegisterRequest][注册失败,客户端 ID: {},错误: {}]", clientId, result.getMsg()); log.warn("[handleRegisterRequest][注册失败,客户端 ID: {},错误: {}]", clientId, result.getMsg());
sendRegisterErrorResponse(endpoint, productKey, deviceName, message.getRequestId(), result.getMsg()); sendRegisterErrorResponse(endpoint, productKey, deviceName, message.getRequestId(), result.getMsg());
@@ -348,7 +348,7 @@ public class IotMqttUpstreamHandler {
// 3. 发送成功响应(包含 deviceSecret // 3. 发送成功响应(包含 deviceSecret
sendRegisterSuccessResponse(endpoint, productKey, deviceName, message.getRequestId(), result.getData()); sendRegisterSuccessResponse(endpoint, productKey, deviceName, message.getRequestId(), result.getData());
log.info("[handleRegisterRequest][注册成功,设备名: {},客户端 ID: {}]", log.info("[handleRegisterRequest][注册成功,设备名: {},客户端 ID: {}]",
registerParams.getDeviceName(), clientId); params.getDeviceName(), clientId);
} catch (Exception e) { } catch (Exception e) {
log.error("[handleRegisterRequest][注册处理异常,客户端 ID: {}]", clientId, e); log.error("[handleRegisterRequest][注册处理异常,客户端 ID: {}]", clientId, e);
sendRegisterErrorResponse(endpoint, productKey, deviceName, message.getRequestId(), "注册处理异常"); sendRegisterErrorResponse(endpoint, productKey, deviceName, message.getRequestId(), "注册处理异常");
@@ -361,36 +361,27 @@ public class IotMqttUpstreamHandler {
* @param params 参数对象(通常为 Map 类型) * @param params 参数对象(通常为 Map 类型)
* @return 注册参数 DTO解析失败时返回 null * @return 注册参数 DTO解析失败时返回 null
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings({"unchecked", "DuplicatedCode"})
private IotDeviceRegisterReqDTO parseRegisterParams(Object params) { private IotDeviceRegisterReqDTO parseRegisterParams(Object params) {
if (params == null) { if (params == null) {
return null; return null;
} }
try { try {
// 参数默认为 Map 类型,直接转换 // 参数默认为 Map 类型,直接转换
if (params instanceof Map) { if (params instanceof Map) {
Map<String, Object> paramMap = (Map<String, Object>) params; Map<String, Object> paramMap = (Map<String, Object>) params;
String productKey = MapUtil.getStr(paramMap, "productKey");
String deviceName = MapUtil.getStr(paramMap, "deviceName");
String productSecret = MapUtil.getStr(paramMap, "productSecret");
if (StrUtil.hasBlank(productKey, deviceName, productSecret)) {
return null;
}
return new IotDeviceRegisterReqDTO() return new IotDeviceRegisterReqDTO()
.setProductKey(productKey) .setProductKey(MapUtil.getStr(paramMap, "productKey"))
.setDeviceName(deviceName) .setDeviceName(MapUtil.getStr(paramMap, "deviceName"))
.setProductSecret(productSecret); .setProductSecret(MapUtil.getStr(paramMap, "productSecret"));
} }
// 如果已经是目标类型,直接返回 // 如果已经是目标类型,直接返回
if (params instanceof IotDeviceRegisterReqDTO) { if (params instanceof IotDeviceRegisterReqDTO) {
return (IotDeviceRegisterReqDTO) params; return (IotDeviceRegisterReqDTO) params;
} }
// 其他情况尝试 JSON 转换 // 其他情况尝试 JSON 转换
String jsonStr = JsonUtils.toJsonString(params); return JsonUtils.convertObject(params, IotDeviceRegisterReqDTO.class);
return JsonUtils.parseObject(jsonStr, IotDeviceRegisterReqDTO.class);
} catch (Exception e) { } catch (Exception e) {
log.error("[parseRegisterParams][解析注册参数({})失败]", params, e); log.error("[parseRegisterParams][解析注册参数({})失败]", params, e);
return null; return null;

View File

@@ -12,9 +12,9 @@ import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO;
import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceRespDTO; import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceRespDTO;
import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
import cn.iocoder.yudao.module.iot.core.topic.IotDeviceIdentity;
import cn.iocoder.yudao.module.iot.core.topic.auth.IotDeviceRegisterReqDTO; import cn.iocoder.yudao.module.iot.core.topic.auth.IotDeviceRegisterReqDTO;
import cn.iocoder.yudao.module.iot.core.topic.auth.IotDeviceRegisterRespDTO; import cn.iocoder.yudao.module.iot.core.topic.auth.IotDeviceRegisterRespDTO;
import cn.iocoder.yudao.module.iot.core.topic.IotDeviceIdentity;
import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils; import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils;
import cn.iocoder.yudao.module.iot.gateway.codec.tcp.IotTcpBinaryDeviceMessageCodec; import cn.iocoder.yudao.module.iot.gateway.codec.tcp.IotTcpBinaryDeviceMessageCodec;
import cn.iocoder.yudao.module.iot.gateway.codec.tcp.IotTcpJsonDeviceMessageCodec; import cn.iocoder.yudao.module.iot.gateway.codec.tcp.IotTcpJsonDeviceMessageCodec;
@@ -27,6 +27,8 @@ import io.vertx.core.buffer.Buffer;
import io.vertx.core.net.NetSocket; import io.vertx.core.net.NetSocket;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.util.Map;
/** /**
* TCP 上行消息处理器 * TCP 上行消息处理器
* *
@@ -78,6 +80,7 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> {
// 设置消息处理器 // 设置消息处理器
socket.handler(buffer -> { socket.handler(buffer -> {
// TODO @AITODO @芋艿:这里应该有拆粘包的问题;
try { try {
processMessage(clientId, buffer, socket); processMessage(clientId, buffer, socket);
} catch (Exception e) { } catch (Exception e) {
@@ -209,15 +212,15 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> {
NetSocket socket) { NetSocket socket) {
try { try {
// 1. 解析注册参数 // 1. 解析注册参数
IotDeviceRegisterReqDTO registerParams = parseRegisterParams(message.getParams()); IotDeviceRegisterReqDTO params = parseRegisterParams(message.getParams());
if (registerParams == null) { if (params == null) {
log.warn("[handleRegisterRequest][注册参数解析失败,客户端 ID: {}]", clientId); log.warn("[handleRegisterRequest][注册参数解析失败,客户端 ID: {}]", clientId);
sendErrorResponse(socket, message.getRequestId(), "注册参数不完整", codecType); sendErrorResponse(socket, message.getRequestId(), "注册参数不完整", codecType);
return; return;
} }
// 2. 调用动态注册 // 2. 调用动态注册
CommonResult<IotDeviceRegisterRespDTO> result = deviceApi.registerDevice(registerParams); CommonResult<IotDeviceRegisterRespDTO> result = deviceApi.registerDevice(params);
if (result.isError()) { if (result.isError()) {
log.warn("[handleRegisterRequest][注册失败,客户端 ID: {},错误: {}]", clientId, result.getMsg()); log.warn("[handleRegisterRequest][注册失败,客户端 ID: {},错误: {}]", clientId, result.getMsg());
sendErrorResponse(socket, message.getRequestId(), result.getMsg(), codecType); sendErrorResponse(socket, message.getRequestId(), result.getMsg(), codecType);
@@ -227,7 +230,7 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> {
// 3. 发送成功响应(包含 deviceSecret // 3. 发送成功响应(包含 deviceSecret
sendRegisterSuccessResponse(socket, message.getRequestId(), result.getData(), codecType); sendRegisterSuccessResponse(socket, message.getRequestId(), result.getData(), codecType);
log.info("[handleRegisterRequest][注册成功,客户端 ID: {},设备名: {}]", log.info("[handleRegisterRequest][注册成功,客户端 ID: {},设备名: {}]",
clientId, registerParams.getDeviceName()); clientId, params.getDeviceName());
} catch (Exception e) { } catch (Exception e) {
log.error("[handleRegisterRequest][注册处理异常,客户端 ID: {}]", clientId, e); log.error("[handleRegisterRequest][注册处理异常,客户端 ID: {}]", clientId, e);
sendErrorResponse(socket, message.getRequestId(), "注册处理异常", codecType); sendErrorResponse(socket, message.getRequestId(), "注册处理异常", codecType);
@@ -419,30 +422,27 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> {
* @param params 参数对象(通常为 Map 类型) * @param params 参数对象(通常为 Map 类型)
* @return 认证参数 DTO解析失败时返回 null * @return 认证参数 DTO解析失败时返回 null
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings({"unchecked", "DuplicatedCode"})
private IotDeviceAuthReqDTO parseAuthParams(Object params) { private IotDeviceAuthReqDTO parseAuthParams(Object params) {
if (params == null) { if (params == null) {
return null; return null;
} }
try { try {
// 参数默认为 Map 类型,直接转换 // 参数默认为 Map 类型,直接转换
if (params instanceof java.util.Map) { if (params instanceof Map) {
java.util.Map<String, Object> paramMap = (java.util.Map<String, Object>) params; Map<String, Object> paramMap = (Map<String, Object>) params;
return new IotDeviceAuthReqDTO() return new IotDeviceAuthReqDTO()
.setClientId(MapUtil.getStr(paramMap, "clientId")) .setClientId(MapUtil.getStr(paramMap, "clientId"))
.setUsername(MapUtil.getStr(paramMap, "username")) .setUsername(MapUtil.getStr(paramMap, "username"))
.setPassword(MapUtil.getStr(paramMap, "password")); .setPassword(MapUtil.getStr(paramMap, "password"));
} }
// 如果已经是目标类型,直接返回 // 如果已经是目标类型,直接返回
if (params instanceof IotDeviceAuthReqDTO) { if (params instanceof IotDeviceAuthReqDTO) {
return (IotDeviceAuthReqDTO) params; return (IotDeviceAuthReqDTO) params;
} }
// 其他情况尝试 JSON 转换 // 其他情况尝试 JSON 转换
String jsonStr = JsonUtils.toJsonString(params); return JsonUtils.convertObject(params, IotDeviceAuthReqDTO.class);
return JsonUtils.parseObject(jsonStr, IotDeviceAuthReqDTO.class);
} catch (Exception e) { } catch (Exception e) {
log.error("[parseAuthParams][解析认证参数({})失败]", params, e); log.error("[parseAuthParams][解析认证参数({})失败]", params, e);
return null; return null;
@@ -455,28 +455,20 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> {
* @param params 参数对象(通常为 Map 类型) * @param params 参数对象(通常为 Map 类型)
* @return 注册参数 DTO解析失败时返回 null * @return 注册参数 DTO解析失败时返回 null
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings({"unchecked", "DuplicatedCode"})
private IotDeviceRegisterReqDTO parseRegisterParams(Object params) { private IotDeviceRegisterReqDTO parseRegisterParams(Object params) {
if (params == null) { if (params == null) {
return null; return null;
} }
try { try {
// 参数默认为 Map 类型,直接转换 // 参数默认为 Map 类型,直接转换
if (params instanceof java.util.Map) { if (params instanceof Map) {
java.util.Map<String, Object> paramMap = (java.util.Map<String, Object>) params; Map<String, Object> paramMap = (Map<String, Object>) params;
String productKey = MapUtil.getStr(paramMap, "productKey");
String deviceName = MapUtil.getStr(paramMap, "deviceName");
String productSecret = MapUtil.getStr(paramMap, "productSecret");
if (StrUtil.hasBlank(productKey, deviceName, productSecret)) {
return null;
}
return new IotDeviceRegisterReqDTO() return new IotDeviceRegisterReqDTO()
.setProductKey(productKey) .setProductKey(MapUtil.getStr(paramMap, "productKey"))
.setDeviceName(deviceName) .setDeviceName(MapUtil.getStr(paramMap, "deviceName"))
.setProductSecret(productSecret); .setProductSecret(MapUtil.getStr(paramMap, "productSecret"));
} }
// 如果已经是目标类型,直接返回 // 如果已经是目标类型,直接返回
if (params instanceof IotDeviceRegisterReqDTO) { if (params instanceof IotDeviceRegisterReqDTO) {
return (IotDeviceRegisterReqDTO) params; return (IotDeviceRegisterReqDTO) params;

View File

@@ -225,15 +225,15 @@ public class IotUdpUpstreamHandler {
String addressKey = sessionManager.buildAddressKey(senderAddress); String addressKey = sessionManager.buildAddressKey(senderAddress);
try { try {
// 1. 解析注册参数 // 1. 解析注册参数
IotDeviceRegisterReqDTO registerParams = parseRegisterParams(message.getParams()); IotDeviceRegisterReqDTO params = parseRegisterParams(message.getParams());
if (registerParams == null) { if (params == null) {
log.warn("[handleRegisterRequest][注册参数解析失败,来源: {}]", addressKey); log.warn("[handleRegisterRequest][注册参数解析失败,来源: {}]", addressKey);
sendErrorResponse(socket, senderAddress, message.getRequestId(), "注册参数不完整", codecType); sendErrorResponse(socket, senderAddress, message.getRequestId(), "注册参数不完整", codecType);
return; return;
} }
// 2. 调用动态注册 // 2. 调用动态注册
CommonResult<IotDeviceRegisterRespDTO> result = deviceApi.registerDevice(registerParams); CommonResult<IotDeviceRegisterRespDTO> result = deviceApi.registerDevice(params);
if (result.isError()) { if (result.isError()) {
log.warn("[handleRegisterRequest][注册失败,来源: {},错误: {}]", addressKey, result.getMsg()); log.warn("[handleRegisterRequest][注册失败,来源: {},错误: {}]", addressKey, result.getMsg());
sendErrorResponse(socket, senderAddress, message.getRequestId(), result.getMsg(), codecType); sendErrorResponse(socket, senderAddress, message.getRequestId(), result.getMsg(), codecType);
@@ -243,7 +243,7 @@ public class IotUdpUpstreamHandler {
// 3. 发送成功响应(包含 deviceSecret // 3. 发送成功响应(包含 deviceSecret
sendRegisterSuccessResponse(socket, senderAddress, message.getRequestId(), result.getData(), codecType); sendRegisterSuccessResponse(socket, senderAddress, message.getRequestId(), result.getData(), codecType);
log.info("[handleRegisterRequest][注册成功,设备名: {},来源: {}]", log.info("[handleRegisterRequest][注册成功,设备名: {},来源: {}]",
registerParams.getDeviceName(), addressKey); params.getDeviceName(), addressKey);
} catch (Exception e) { } catch (Exception e) {
log.error("[handleRegisterRequest][注册处理异常,来源: {}]", addressKey, e); log.error("[handleRegisterRequest][注册处理异常,来源: {}]", addressKey, e);
sendErrorResponse(socket, senderAddress, message.getRequestId(), "注册处理异常", codecType); sendErrorResponse(socket, senderAddress, message.getRequestId(), "注册处理异常", codecType);
@@ -484,7 +484,6 @@ public class IotUdpUpstreamHandler {
if (params == null) { if (params == null) {
return null; return null;
} }
try { try {
// 参数默认为 Map 类型,直接转换 // 参数默认为 Map 类型,直接转换
if (params instanceof Map) { if (params instanceof Map) {
@@ -494,15 +493,13 @@ public class IotUdpUpstreamHandler {
.setUsername(MapUtil.getStr(paramMap, "username")) .setUsername(MapUtil.getStr(paramMap, "username"))
.setPassword(MapUtil.getStr(paramMap, "password")); .setPassword(MapUtil.getStr(paramMap, "password"));
} }
// 如果已经是目标类型,直接返回 // 如果已经是目标类型,直接返回
if (params instanceof IotDeviceAuthReqDTO) { if (params instanceof IotDeviceAuthReqDTO) {
return (IotDeviceAuthReqDTO) params; return (IotDeviceAuthReqDTO) params;
} }
// 其他情况尝试 JSON 转换 // 其他情况尝试 JSON 转换
String jsonStr = JsonUtils.toJsonString(params); return JsonUtils.convertObject(params, IotDeviceAuthReqDTO.class);
return JsonUtils.parseObject(jsonStr, IotDeviceAuthReqDTO.class);
} catch (Exception e) { } catch (Exception e) {
log.error("[parseAuthParams][解析认证参数({})失败]", params, e); log.error("[parseAuthParams][解析认证参数({})失败]", params, e);
return null; return null;
@@ -515,36 +512,27 @@ public class IotUdpUpstreamHandler {
* @param params 参数对象(通常为 Map 类型) * @param params 参数对象(通常为 Map 类型)
* @return 注册参数 DTO解析失败时返回 null * @return 注册参数 DTO解析失败时返回 null
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings({"unchecked", "DuplicatedCode"})
private IotDeviceRegisterReqDTO parseRegisterParams(Object params) { private IotDeviceRegisterReqDTO parseRegisterParams(Object params) {
if (params == null) { if (params == null) {
return null; return null;
} }
try { try {
// 参数默认为 Map 类型,直接转换 // 参数默认为 Map 类型,直接转换
if (params instanceof Map) { if (params instanceof Map) {
Map<String, Object> paramMap = (Map<String, Object>) params; Map<String, Object> paramMap = (Map<String, Object>) params;
String productKey = MapUtil.getStr(paramMap, "productKey");
String deviceName = MapUtil.getStr(paramMap, "deviceName");
String productSecret = MapUtil.getStr(paramMap, "productSecret");
if (StrUtil.hasBlank(productKey, deviceName, productSecret)) {
return null;
}
return new IotDeviceRegisterReqDTO() return new IotDeviceRegisterReqDTO()
.setProductKey(productKey) .setProductKey(MapUtil.getStr(paramMap, "productKey"))
.setDeviceName(deviceName) .setDeviceName(MapUtil.getStr(paramMap, "deviceName"))
.setProductSecret(productSecret); .setProductSecret(MapUtil.getStr(paramMap, "productSecret"));
} }
// 如果已经是目标类型,直接返回 // 如果已经是目标类型,直接返回
if (params instanceof IotDeviceRegisterReqDTO) { if (params instanceof IotDeviceRegisterReqDTO) {
return (IotDeviceRegisterReqDTO) params; return (IotDeviceRegisterReqDTO) params;
} }
// 其他情况尝试 JSON 转换 // 其他情况尝试 JSON 转换
String jsonStr = JsonUtils.toJsonString(params); return JsonUtils.convertObject(params, IotDeviceRegisterReqDTO.class);
return JsonUtils.parseObject(jsonStr, IotDeviceRegisterReqDTO.class);
} catch (Exception e) { } catch (Exception e) {
log.error("[parseRegisterParams][解析注册参数({})失败]", params, e); log.error("[parseRegisterParams][解析注册参数({})失败]", params, e);
return null; return null;

View File

@@ -25,6 +25,8 @@ import io.vertx.core.Handler;
import io.vertx.core.http.ServerWebSocket; import io.vertx.core.http.ServerWebSocket;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.util.Map;
/** /**
* WebSocket 上行消息处理器 * WebSocket 上行消息处理器
@@ -204,15 +206,16 @@ public class IotWebSocketUpstreamHandler implements Handler<ServerWebSocket> {
private void handleRegisterRequest(String clientId, IotDeviceMessage message, ServerWebSocket socket) { private void handleRegisterRequest(String clientId, IotDeviceMessage message, ServerWebSocket socket) {
try { try {
// 1. 解析注册参数 // 1. 解析注册参数
IotDeviceRegisterReqDTO registerParams = parseRegisterParams(message.getParams()); IotDeviceRegisterReqDTO params = parseRegisterParams(message.getParams());
if (registerParams == null) { if (params == null
|| StrUtil.hasEmpty(params.getProductKey(), params.getDeviceName(), params.getProductSecret())) {
log.warn("[handleRegisterRequest][注册参数解析失败,客户端 ID: {}]", clientId); log.warn("[handleRegisterRequest][注册参数解析失败,客户端 ID: {}]", clientId);
sendErrorResponse(socket, message.getRequestId(), "注册参数不完整"); sendErrorResponse(socket, message.getRequestId(), "注册参数不完整");
return; return;
} }
// 2. 调用动态注册 // 2. 调用动态注册
CommonResult<IotDeviceRegisterRespDTO> result = deviceApi.registerDevice(registerParams); CommonResult<IotDeviceRegisterRespDTO> result = deviceApi.registerDevice(params);
if (result.isError()) { if (result.isError()) {
log.warn("[handleRegisterRequest][注册失败,客户端 ID: {},错误: {}]", clientId, result.getMsg()); log.warn("[handleRegisterRequest][注册失败,客户端 ID: {},错误: {}]", clientId, result.getMsg());
sendErrorResponse(socket, message.getRequestId(), result.getMsg()); sendErrorResponse(socket, message.getRequestId(), result.getMsg());
@@ -222,7 +225,7 @@ public class IotWebSocketUpstreamHandler implements Handler<ServerWebSocket> {
// 3. 发送成功响应(包含 deviceSecret // 3. 发送成功响应(包含 deviceSecret
sendRegisterSuccessResponse(socket, message.getRequestId(), result.getData()); sendRegisterSuccessResponse(socket, message.getRequestId(), result.getData());
log.info("[handleRegisterRequest][注册成功,客户端 ID: {},设备名: {}]", log.info("[handleRegisterRequest][注册成功,客户端 ID: {},设备名: {}]",
clientId, registerParams.getDeviceName()); clientId, params.getDeviceName());
} catch (Exception e) { } catch (Exception e) {
log.error("[handleRegisterRequest][注册处理异常,客户端 ID: {}]", clientId, e); log.error("[handleRegisterRequest][注册处理异常,客户端 ID: {}]", clientId, e);
sendErrorResponse(socket, message.getRequestId(), "注册处理异常"); sendErrorResponse(socket, message.getRequestId(), "注册处理异常");
@@ -384,31 +387,27 @@ public class IotWebSocketUpstreamHandler implements Handler<ServerWebSocket> {
* @param params 参数对象(通常为 Map 类型) * @param params 参数对象(通常为 Map 类型)
* @return 认证参数 DTO解析失败时返回 null * @return 认证参数 DTO解析失败时返回 null
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings({"unchecked", "DuplicatedCode"})
private IotDeviceAuthReqDTO parseAuthParams(Object params) { private IotDeviceAuthReqDTO parseAuthParams(Object params) {
if (params == null) { if (params == null) {
return null; return null;
} }
try { try {
// 参数默认为 Map 类型,直接转换 // 参数默认为 Map 类型,直接转换
if (params instanceof java.util.Map) { if (params instanceof Map) {
java.util.Map<String, Object> paramMap = (java.util.Map<String, Object>) params; Map<String, Object> paramMap = (Map<String, Object>) params;
return new IotDeviceAuthReqDTO() return new IotDeviceAuthReqDTO()
.setClientId(MapUtil.getStr(paramMap, "clientId")) .setClientId(MapUtil.getStr(paramMap, "clientId"))
.setUsername(MapUtil.getStr(paramMap, "username")) .setUsername(MapUtil.getStr(paramMap, "username"))
.setPassword(MapUtil.getStr(paramMap, "password")); .setPassword(MapUtil.getStr(paramMap, "password"));
} }
// 如果已经是目标类型,直接返回 // 如果已经是目标类型,直接返回
if (params instanceof IotDeviceAuthReqDTO) { if (params instanceof IotDeviceAuthReqDTO) {
return (IotDeviceAuthReqDTO) params; return (IotDeviceAuthReqDTO) params;
} }
// 其他情况尝试 JSON 转换 // 其他情况尝试 JSON 转换
// TODO @芋艿:要不要优化下; return JsonUtils.convertObject(params, IotDeviceAuthReqDTO.class);
String jsonStr = JsonUtils.toJsonString(params);
return JsonUtils.convertObject(jsonStr, IotDeviceAuthReqDTO.class);
} catch (Exception e) { } catch (Exception e) {
log.error("[parseAuthParams][解析认证参数({})失败]", params, e); log.error("[parseAuthParams][解析认证参数({})失败]", params, e);
return null; return null;
@@ -426,31 +425,22 @@ public class IotWebSocketUpstreamHandler implements Handler<ServerWebSocket> {
if (params == null) { if (params == null) {
return null; return null;
} }
try { try {
// 参数默认为 Map 类型,直接转换 // 参数默认为 Map 类型,直接转换
if (params instanceof java.util.Map) { if (params instanceof Map) {
java.util.Map<String, Object> paramMap = (java.util.Map<String, Object>) params; Map<String, Object> paramMap = (Map<String, Object>) params;
String productKey = MapUtil.getStr(paramMap, "productKey");
String deviceName = MapUtil.getStr(paramMap, "deviceName");
String productSecret = MapUtil.getStr(paramMap, "productSecret");
if (StrUtil.hasBlank(productKey, deviceName, productSecret)) {
return null;
}
return new IotDeviceRegisterReqDTO() return new IotDeviceRegisterReqDTO()
.setProductKey(productKey) .setProductKey(MapUtil.getStr(paramMap, "productKey"))
.setDeviceName(deviceName) .setDeviceName(MapUtil.getStr(paramMap, "deviceName"))
.setProductSecret(productSecret); .setProductSecret(MapUtil.getStr(paramMap, "productSecret"));
} }
// 如果已经是目标类型,直接返回 // 如果已经是目标类型,直接返回
if (params instanceof IotDeviceRegisterReqDTO) { if (params instanceof IotDeviceRegisterReqDTO) {
return (IotDeviceRegisterReqDTO) params; return (IotDeviceRegisterReqDTO) params;
} }
// 其他情况尝试 JSON 转换 // 其他情况尝试 JSON 转换
String jsonStr = JsonUtils.toJsonString(params); return JsonUtils.convertObject(params, IotDeviceRegisterReqDTO.class);
return JsonUtils.parseObject(jsonStr, IotDeviceRegisterReqDTO.class);
} catch (Exception e) { } catch (Exception e) {
log.error("[parseRegisterParams][解析注册参数({})失败]", params, e); log.error("[parseRegisterParams][解析注册参数({})失败]", params, e);
return null; return null;