refactor: 【IoT 物联网】修复设备属性条件匹配器设计问题并重构属性值提取逻辑

This commit is contained in:
puhui999
2025-09-01 16:26:51 +08:00
parent 796d69b241
commit fe0c1bbf34
7 changed files with 406 additions and 118 deletions

View File

@@ -69,6 +69,83 @@ public class IotDeviceMessageUtils {
return null;
}
/**
* 从设备消息中提取指定标识符的属性值
* - 支持多种消息格式和属性值提取策略
* - 兼容现有的消息结构
* - 提供统一的属性值提取接口
* <p>
* 支持的提取策略(按优先级顺序):
* 1. 直接值:如果 params 不是 Map直接返回该值适用于简单消息
* 2. 标识符字段:从 params[identifier] 获取
* 3. properties 结构:从 params.properties[identifier] 获取(标准属性上报)
* 4. data 结构:从 params.data[identifier] 获取
* 5. value 字段:从 params.value 获取(单值消息)
* 6. 单值 Map如果 Map 只包含 identifier 和一个值,返回该值
*
* @param message 设备消息
* @param identifier 属性标识符
* @return 属性值,如果未找到则返回 null
*/
@SuppressWarnings("unchecked")
public static Object extractPropertyValue(IotDeviceMessage message, String identifier) {
Object params = message.getParams();
if (params == null) {
return null;
}
// 策略1如果 params 不是 Map直接返回该值适用于简单的单属性消息
if (!(params instanceof Map)) {
return params;
}
Map<String, Object> paramsMap = (Map<String, Object>) params;
// 策略2直接通过标识符获取属性值
Object directValue = paramsMap.get(identifier);
if (directValue != null) {
return directValue;
}
// 策略3从 properties 字段中获取(适用于标准属性上报消息)
Object properties = paramsMap.get("properties");
if (properties instanceof Map) {
Map<String, Object> propertiesMap = (Map<String, Object>) properties;
Object propertyValue = propertiesMap.get(identifier);
if (propertyValue != null) {
return propertyValue;
}
}
// 策略4从 data 字段中获取(适用于某些消息格式)
Object data = paramsMap.get("data");
if (data instanceof Map) {
Map<String, Object> dataMap = (Map<String, Object>) data;
Object dataValue = dataMap.get(identifier);
if (dataValue != null) {
return dataValue;
}
}
// 策略5从 value 字段中获取(适用于单值消息)
Object value = paramsMap.get("value");
if (value != null) {
return value;
}
// 策略6如果 Map 只有两个字段且包含 identifier返回另一个字段的值
if (paramsMap.size() == 2 && paramsMap.containsKey("identifier")) {
for (Map.Entry<String, Object> entry : paramsMap.entrySet()) {
if (!"identifier".equals(entry.getKey())) {
return entry.getValue();
}
}
}
// 未找到对应的属性值
return null;
}
// ========== Topic 相关 ==========
public static String buildMessageBusGatewayDeviceMessageTopic(String serverId) {

View File

@@ -0,0 +1,141 @@
package cn.iocoder.yudao.module.iot.core.util;
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
/**
* {@link IotDeviceMessageUtils} 的单元测试
*
* @author HUIHUI
*/
public class IotDeviceMessageUtilsTest {
@Test
public void testExtractPropertyValue_directValue() {
// 测试直接值(非 Map
IotDeviceMessage message = new IotDeviceMessage();
message.setParams(25.5);
Object result = IotDeviceMessageUtils.extractPropertyValue(message, "temperature");
assertEquals(25.5, result);
}
@Test
public void testExtractPropertyValue_directIdentifier() {
// 测试直接通过标识符获取
IotDeviceMessage message = new IotDeviceMessage();
Map<String, Object> params = new HashMap<>();
params.put("temperature", 25.5);
message.setParams(params);
Object result = IotDeviceMessageUtils.extractPropertyValue(message, "temperature");
assertEquals(25.5, result);
}
@Test
public void testExtractPropertyValue_propertiesStructure() {
// 测试 properties 结构
IotDeviceMessage message = new IotDeviceMessage();
Map<String, Object> properties = new HashMap<>();
properties.put("temperature", 25.5);
properties.put("humidity", 60);
Map<String, Object> params = new HashMap<>();
params.put("properties", properties);
message.setParams(params);
Object result = IotDeviceMessageUtils.extractPropertyValue(message, "temperature");
assertEquals(25.5, result);
}
@Test
public void testExtractPropertyValue_dataStructure() {
// 测试 data 结构
IotDeviceMessage message = new IotDeviceMessage();
Map<String, Object> data = new HashMap<>();
data.put("temperature", 25.5);
Map<String, Object> params = new HashMap<>();
params.put("data", data);
message.setParams(params);
Object result = IotDeviceMessageUtils.extractPropertyValue(message, "temperature");
assertEquals(25.5, result);
}
@Test
public void testExtractPropertyValue_valueField() {
// 测试 value 字段
IotDeviceMessage message = new IotDeviceMessage();
Map<String, Object> params = new HashMap<>();
params.put("identifier", "temperature");
params.put("value", 25.5);
message.setParams(params);
Object result = IotDeviceMessageUtils.extractPropertyValue(message, "temperature");
assertEquals(25.5, result);
}
@Test
public void testExtractPropertyValue_singleValueMap() {
// 测试单值 Map包含 identifier 和一个值)
IotDeviceMessage message = new IotDeviceMessage();
Map<String, Object> params = new HashMap<>();
params.put("identifier", "temperature");
params.put("actualValue", 25.5);
message.setParams(params);
Object result = IotDeviceMessageUtils.extractPropertyValue(message, "temperature");
assertEquals(25.5, result);
}
@Test
public void testExtractPropertyValue_notFound() {
// 测试未找到属性值
IotDeviceMessage message = new IotDeviceMessage();
Map<String, Object> params = new HashMap<>();
params.put("humidity", 60);
message.setParams(params);
Object result = IotDeviceMessageUtils.extractPropertyValue(message, "temperature");
assertNull(result);
}
@Test
public void testExtractPropertyValue_nullParams() {
// 测试 params 为 null
IotDeviceMessage message = new IotDeviceMessage();
message.setParams(null);
Object result = IotDeviceMessageUtils.extractPropertyValue(message, "temperature");
assertNull(result);
}
@Test
public void testExtractPropertyValue_priorityOrder() {
// 测试优先级顺序:直接标识符 > properties > data > value
IotDeviceMessage message = new IotDeviceMessage();
Map<String, Object> properties = new HashMap<>();
properties.put("temperature", 20.0);
Map<String, Object> data = new HashMap<>();
data.put("temperature", 30.0);
Map<String, Object> params = new HashMap<>();
params.put("temperature", 25.5); // 最高优先级
params.put("properties", properties);
params.put("data", data);
params.put("value", 40.0);
message.setParams(params);
Object result = IotDeviceMessageUtils.extractPropertyValue(message, "temperature");
assertEquals(25.5, result); // 应该返回直接标识符的值
}
}