fix:重要!子设备无法添加bug

This commit is contained in:
Join
2025-11-01 14:30:49 +08:00
parent d091fd4926
commit 8e005a041b
2 changed files with 232 additions and 39 deletions
@@ -34,7 +34,8 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* HTTP协议转换器 将UnifiedDownlinkCommand转换为HttpDownRequest
* HTTP协议转换器
* 将UnifiedDownlinkCommand转换为HttpDownRequest
*
* @version 1.0
* @since 2025/10/25
@@ -71,15 +72,27 @@ public class HttpDownRequestConverter extends AbstratIoTService
}
}
/** 转换网关子设备请求 */
/**
* 转换网关子设备请求
*/
private HttpDownRequest convertGatewaySubDevice(
UnifiedDownlinkCommand command, IoTProduct subProduct, DownlinkContext<?> context) {
log.info(
"[HTTP转换器] 检测到网关子设备, productKey={}, deviceId={}",
"[HTTP转换器] 检测到网关子设备, productKey={}, deviceId={}, cmd={}",
command.getProductKey(),
command.getDeviceId());
command.getDeviceId(),
command.getCmd());
// 1. 加载子设备信息
// 1. 判断是否需要网关代理
boolean needGatewayProxy = isNeedGatewayProxy(command.getCmd());
if (!needGatewayProxy) {
// 对于不需要网关代理的命令(如DEV_ADD等设备管理命令),直接使用子设备信息
log.info("[HTTP转换器] 命令{}不需要网关代理,直接使用子设备信息", command.getCmd());
return convertSubDeviceDirectly(command, subProduct, context);
}
// 2. 加载子设备信息(需要网关代理时必须存在)
IoTDeviceDTO subDevice =
getIoTDeviceDTO(
IoTDeviceQuery.builder()
@@ -88,26 +101,29 @@ public class HttpDownRequestConverter extends AbstratIoTService
.iotId(command.getIotId())
.build());
if (subDevice == null && command.getCmd() != DownCmd.DEV_ADD) {
if (subDevice == null) {
throw new IllegalArgumentException(
"子设备不存在: productKey=" + command.getProductKey() + ", deviceId=" + command.getDeviceId());
}
// 2. 查询网关设备信息
// 3. 验证网关绑定信息
if (StrUtil.isBlank(subDevice.getGwProductKey())
|| StrUtil.isBlank(subDevice.getExtDeviceId())) {
throw new IllegalArgumentException(
"网关子设备缺少网关信息: gwProductKey="
"网关子设备缺少网关绑定信息: gwProductKey="
+ subDevice.getGwProductKey()
+ ", extDeviceId="
+ subDevice.getExtDeviceId());
+ subDevice.getExtDeviceId()
+ ", 请先完成子设备与网关的绑定");
}
// 4. 查询网关产品信息
IoTProduct gatewayProduct = getProduct(subDevice.getGwProductKey());
if (gatewayProduct == null) {
throw new IllegalArgumentException("网关产品不存在: " + subDevice.getGwProductKey());
}
// 5. 查询网关设备信息
IoTDeviceDTO gatewayDevice =
getIoTDeviceDTO(
IoTDeviceQuery.builder()
@@ -123,7 +139,7 @@ public class HttpDownRequestConverter extends AbstratIoTService
+ subDevice.getExtDeviceId());
}
// 3. 构建请求对象
// 6. 构建请求对象(通过网关代理)
HttpDownRequest request = new HttpDownRequest();
BeanUtil.copyProperties(command, request, "extensions", "metadata");
@@ -136,13 +152,13 @@ public class HttpDownRequestConverter extends AbstratIoTService
request.setSubProductKey(command.getProductKey());
request.setIsGatewayProxy(true);
// 4. 获取网关产品配置
// 7. 获取网关产品配置
JSONObject config = JSONUtil.parseObj(gatewayProduct.getConfiguration());
String down = config.getStr("down");
// 5. 处理功能下发场景:使用子设备ProductKey编解码
// 8. 处理功能下发场景:使用子设备ProductKey编解码
if ((StrUtil.isNotBlank(down)
&& ListUtil.of(down.split(",")).contains(command.getCmd().getValue()))
&& ListUtil.of(down.split(",")).contains(command.getCmd().getValue()))
|| CollectionUtil.isNotEmpty(command.getFunction())) {
String payload = encodeFunction(command);
request.setDownResult(payload);
@@ -151,12 +167,12 @@ public class HttpDownRequestConverter extends AbstratIoTService
log.debug("[HTTP转换器] 子设备编解码完成, deviceId={}, payload={}", command.getDeviceId(), payload);
}
// 6. 处理扩展字段
// 9. 处理扩展字段
if (command.getExtensions() != null && !command.getExtensions().isEmpty()) {
request.setData(JSONUtil.parseObj(command.getExtensions()));
}
// 7. 设置消息ID
// 10. 设置消息ID
if (StrUtil.isBlank(request.getMsgId())) {
request.setMsgId(generateMsgId());
}
@@ -169,7 +185,86 @@ public class HttpDownRequestConverter extends AbstratIoTService
return request;
}
/** 转换普通设备请求 */
/**
* 判断命令是否需要网关代理
* @param cmd 下行命令
* @return true-需要网关代理, false-直接使用子设备信息
*/
private boolean isNeedGatewayProxy(DownCmd cmd) {
if (cmd == null) {
return false;
}
// 设备管理类命令不需要网关代理,直接操作子设备
return switch (cmd) {
case DEV_ADD, DEV_ADDS, // 设备新增
DEV_DEL, DEVICE_DELETE, // 设备删除
DEV_UPDATE, DEVICE_UPDATE // 设备更新
-> false;
// 其他命令(功能调用、状态查询等)需要通过网关代理
default -> true;
};
}
/**
* 直接使用子设备信息转换(不需要网关代理的场景)
* @param command 下行命令
* @param subProduct 子设备产品信息
* @param context 下行上下文
* @return HTTP下行请求
*/
private HttpDownRequest convertSubDeviceDirectly(
UnifiedDownlinkCommand command, IoTProduct subProduct, DownlinkContext<?> context) {
// 1. 创建请求对象
HttpDownRequest request = new HttpDownRequest();
BeanUtil.copyProperties(command, request, "extensions", "metadata");
// 2. 设置子设备产品信息
request.setIoTProduct(subProduct);
// 3. 尝试加载子设备信息(DEV_ADD时可能不存在)
IoTDeviceDTO subDevice = null;
if (command.getCmd() != DownCmd.DEV_ADD && command.getCmd() != DownCmd.DEV_ADDS) {
subDevice = getIoTDeviceDTO(
IoTDeviceQuery.builder()
.productKey(command.getProductKey())
.deviceId(command.getDeviceId())
.iotId(command.getIotId())
.build());
if (subDevice == null) {
throw new IllegalArgumentException(
"子设备不存在: productKey=" + command.getProductKey() + ", deviceId=" + command.getDeviceId());
}
}
request.setIoTDeviceDTO(subDevice);
// 4. 处理扩展字段
if (command.getExtensions() != null && !command.getExtensions().isEmpty()) {
request.setData(JSONUtil.parseObj(command.getExtensions()));
}
// 5. 设置消息ID
if (StrUtil.isBlank(request.getMsgId())) {
request.setMsgId(generateMsgId());
}
// 6. 标记为子设备(但不通过网关代理)
request.setIsGatewayProxy(false);
log.info(
"[HTTP转换器] 子设备直接转换完成(无需网关代理): productKey={}, deviceId={}, cmd={}",
command.getProductKey(),
command.getDeviceId(),
command.getCmd());
return request;
}
/**
* 转换普通设备请求
*/
private HttpDownRequest convertNormalDevice(
UnifiedDownlinkCommand command, IoTProduct ioTProduct, DownlinkContext<?> context) {
// 1. 创建请求对象
@@ -202,12 +297,13 @@ public class HttpDownRequestConverter extends AbstratIoTService
// 6. 处理功能下发场景:编解码
if ((StrUtil.isNotBlank(down)
&& ListUtil.of(down.split(",")).contains(command.getCmd().getValue()))
&& ListUtil.of(down.split(",")).contains(command.getCmd().getValue()))
|| CollectionUtil.isNotEmpty(command.getFunction())) {
String payload = encodeFunction(command);
request.setDownResult(payload);
request.setPayload(payload);
log.debug("[HTTP转换器] 功能下发编解码完成, deviceId={}, payload={}", command.getDeviceId(), payload);
log.debug(
"[HTTP转换器] 功能下发编解码完成, deviceId={}, payload={}", command.getDeviceId(), payload);
}
// 7. 处理扩展字段
@@ -229,7 +325,9 @@ public class HttpDownRequestConverter extends AbstratIoTService
return request;
}
/** 判断是否为网关子设备 */
/**
* 判断是否为网关子设备
*/
private boolean isGatewaySubDevice(IoTProduct product) {
return DeviceNode.GATEWAY_SUB_DEVICE.getValue().equalsIgnoreCase(product.getDeviceNode());
}
@@ -294,7 +392,7 @@ public class HttpDownRequestConverter extends AbstratIoTService
// 保存设备信息到上下文(供后续拦截器使用)
if (request.getIoTDeviceDTO() != null) {
context.setAttribute("deviceName", request.getIoTDeviceDTO().getDeviceName());
context.setAttribute("deviceStatus", request.getIoTDeviceDTO().getState()); // 使用getState()
context.setAttribute("deviceStatus", request.getIoTDeviceDTO().getState()); // 使用getState()
}
}
}
@@ -74,11 +74,21 @@ public class MQTTDownRequestConverter extends AbstratIoTService
private MQTTDownRequest convertGatewaySubDevice(
UnifiedDownlinkCommand command, IoTProduct subProduct, DownlinkContext<?> context) {
log.info(
"[MQTT转换器] 检测到网关子设备, productKey={}, deviceId={}",
"[MQTT转换器] 检测到网关子设备, productKey={}, deviceId={}, cmd={}",
command.getProductKey(),
command.getDeviceId());
command.getDeviceId(),
command.getCmd());
// 1. 加载子设备信息
// 1. 判断是否需要网关代理
boolean needGatewayProxy = isNeedGatewayProxy(command.getCmd());
if (!needGatewayProxy) {
// 对于不需要网关代理的命令(如DEV_ADD等设备管理命令),直接使用子设备信息
log.info("[MQTT转换器] 命令{}不需要网关代理,直接使用子设备信息", command.getCmd());
return convertSubDeviceDirectly(command, subProduct, context);
}
// 2. 加载子设备信息(需要网关代理时必须存在)
IoTDeviceDTO subDevice =
getIoTDeviceDTO(
IoTDeviceQuery.builder()
@@ -87,12 +97,23 @@ public class MQTTDownRequestConverter extends AbstratIoTService
.iotId(command.getIotId())
.build());
if (subDevice == null && command.getCmd() != DownCmd.DEV_ADD) {
if (subDevice == null) {
throw new IllegalArgumentException(
"子设备不存在: productKey=" + command.getProductKey() + ", deviceId=" + command.getDeviceId());
}
// 2. 使用子设备的ProductKey执行编解码
// 3. 验证网关绑定信息
if (StrUtil.isBlank(subDevice.getGwProductKey())
|| StrUtil.isBlank(subDevice.getExtDeviceId())) {
throw new IllegalArgumentException(
"网关子设备缺少网关绑定信息: gwProductKey="
+ subDevice.getGwProductKey()
+ ", extDeviceId="
+ subDevice.getExtDeviceId()
+ ", 请先完成子设备与网关的绑定");
}
// 4. 使用子设备的ProductKey执行编解码
String payload = null;
if (DownCmd.DEV_FUNCTION.equals(command.getCmd())
&& CollectionUtil.isNotEmpty(command.getFunction())) {
@@ -107,21 +128,13 @@ public class MQTTDownRequestConverter extends AbstratIoTService
}
}
// 3. 查询网关设备信息
if (StrUtil.isBlank(subDevice.getGwProductKey())
|| StrUtil.isBlank(subDevice.getExtDeviceId())) {
throw new IllegalArgumentException(
"网关子设备缺少网关信息: gwProductKey="
+ subDevice.getGwProductKey()
+ ", extDeviceId="
+ subDevice.getExtDeviceId());
}
// 5. 查询网关产品信息
IoTProduct gatewayProduct = getProduct(subDevice.getGwProductKey());
if (gatewayProduct == null) {
throw new IllegalArgumentException("网关产品不存在: " + subDevice.getGwProductKey());
}
// 6. 查询网关设备信息
IoTDeviceDTO gatewayDevice =
getIoTDeviceDTO(
IoTDeviceQuery.builder()
@@ -137,7 +150,7 @@ public class MQTTDownRequestConverter extends AbstratIoTService
+ subDevice.getExtDeviceId());
}
// 4. 构建请求对象(使用网关设备的配置)
// 7. 构建请求对象(通过网关代理)
MQTTDownRequest request = new MQTTDownRequest();
BeanUtil.copyProperties(command, request, "extensions", "metadata");
@@ -156,17 +169,17 @@ public class MQTTDownRequestConverter extends AbstratIoTService
request.setSubProductKey(command.getProductKey());
request.setIsGatewayProxy(true);
// 5. 设置网关的配置信息
// 8. 设置网关的配置信息
DownCommonData downCommonData = new DownCommonData();
downCommonData.setConfiguration(parseProductConfigurationSafely(gatewayProduct));
request.setDownCommonData(downCommonData);
// 6. 处理扩展字段
// 9. 处理扩展字段
if (command.getExtensions() != null && !command.getExtensions().isEmpty()) {
request.setData(JSONUtil.parseObj(command.getExtensions()));
}
// 7. 设置消息ID
// 10. 设置消息ID
if (StrUtil.isBlank(request.getMsgId())) {
request.setMsgId(generateMsgId());
}
@@ -179,6 +192,88 @@ public class MQTTDownRequestConverter extends AbstratIoTService
return request;
}
/**
* 判断命令是否需要网关代理
* @param cmd 下行命令
* @return true-需要网关代理, false-直接使用子设备信息
*/
private boolean isNeedGatewayProxy(DownCmd cmd) {
if (cmd == null) {
return false;
}
// 设备管理类命令不需要网关代理,直接操作子设备
return switch (cmd) {
case DEV_ADD, DEV_ADDS, // 设备新增
DEV_DEL, DEVICE_DELETE, // 设备删除
DEV_UPDATE, DEVICE_UPDATE // 设备更新
-> false;
// 其他命令(功能调用、状态查询等)需要通过网关代理
default -> true;
};
}
/**
* 直接使用子设备信息转换(不需要网关代理的场景)
* @param command 下行命令
* @param subProduct 子设备产品信息
* @param context 下行上下文
* @return MQTT下行请求
*/
private MQTTDownRequest convertSubDeviceDirectly(
UnifiedDownlinkCommand command, IoTProduct subProduct, DownlinkContext<?> context) {
// 1. 创建请求对象
MQTTDownRequest request = new MQTTDownRequest();
BeanUtil.copyProperties(command, request, "extensions", "metadata");
// 2. 设置子设备产品信息
request.setIoTProduct(subProduct);
// 3. 尝试加载子设备信息(DEV_ADD时可能不存在)
IoTDeviceDTO subDevice = null;
if (command.getCmd() != DownCmd.DEV_ADD && command.getCmd() != DownCmd.DEV_ADDS) {
subDevice = getIoTDeviceDTO(
IoTDeviceQuery.builder()
.productKey(command.getProductKey())
.deviceId(command.getDeviceId())
.iotId(command.getIotId())
.build());
if (subDevice == null) {
throw new IllegalArgumentException(
"子设备不存在: productKey=" + command.getProductKey() + ", deviceId=" + command.getDeviceId());
}
}
request.setIoTDeviceDTO(subDevice);
// 4. 设置子设备的配置信息
DownCommonData downCommonData = new DownCommonData();
downCommonData.setConfiguration(parseProductConfigurationSafely(subProduct));
request.setDownCommonData(downCommonData);
// 5. 处理扩展字段
if (command.getExtensions() != null && !command.getExtensions().isEmpty()) {
request.setData(JSONUtil.parseObj(command.getExtensions()));
}
// 6. 设置消息ID
if (StrUtil.isBlank(request.getMsgId())) {
request.setMsgId(generateMsgId());
}
// 7. 标记为子设备(但不通过网关代理)
request.setIsGatewayProxy(false);
log.info(
"[MQTT转换器] 子设备直接转换完成(无需网关代理): productKey={}, deviceId={}, cmd={}",
command.getProductKey(),
command.getDeviceId(),
command.getCmd());
return request;
}
/** 转换普通设备请求 */
private MQTTDownRequest convertNormalDevice(
UnifiedDownlinkCommand command, IoTProduct ioTProduct, DownlinkContext<?> context) {