fix: 修复java.lang.RuntimeException: JT808 消息编码失败: 消息参数格式错误,params 必须是 Map 类型
All checks were successful
aiot-platform CI/CD / build-and-deploy (push) Successful in 7m41s

at com.viewshanghai.module.iot.gateway.codec.jt808.IotJt808DeviceMessageCodec.encode(IotJt808DeviceMessageCodec.java:77) ~[!/:na]
This commit is contained in:
lzh
2025-12-26 17:58:36 +08:00
parent a5c2b7aabf
commit 8d52e9e413

View File

@@ -598,98 +598,163 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
/**
* 提取终端手机号
*
*
* 优先级:
* 1. 从 params._deviceName 中获取下发场景IotTcpDownstreamHandler 自动注入)
* 2. 从 params._metadata.terminalPhone 中获取(上行消息回复场景)
* 3. 从 params.phone 中获取(手动指定,向下兼容,不推荐)
* 4. 从 data.phone 中获取(应答消息场景,使用 replyOf 构建的消息)
*/
private String extractPhoneNumber(IotDeviceMessage message) {
if (!(message.getParams() instanceof Map)) {
log.error("[extractPhoneNumber][params 不是 Map 类型,消息: {}]", message);
throw new IllegalArgumentException("消息参数格式错误params 必须是 Map 类型");
// 尝试从 params 提取
if (message.getParams() instanceof Map) {
Map<?, ?> params = (Map<?, ?>) message.getParams();
String phone = extractPhoneFromMap(params);
if (phone != null) {
return phone;
}
}
Map<?, ?> params = (Map<?, ?>) message.getParams();
// 尝试从 data 提取(应答消息使用 replyOf 时,参数在 data 字段)
if (message.getData() instanceof Map) {
Map<?, ?> data = (Map<?, ?>) message.getData();
String phone = extractPhoneFromMap(data);
if (phone != null) {
return phone;
}
}
// 如果都获取不到,抛出异常
log.error("[extractPhoneNumber][无法提取终端手机号params: {}, data: {}]",
message.getParams(), message.getData());
throw new IllegalArgumentException(
"消息中缺少终端手机号。请确保设备的 deviceName 为终端手机号(纯数字),例如: \"13800138000\"");
}
/**
* 从 Map 中提取终端手机号
*/
private String extractPhoneFromMap(Map<?, ?> map) {
if (map == null) {
return null;
}
// 1. 优先从 _deviceName 获取(下发场景,由 IotTcpDownstreamHandler 注入)
Object deviceName = params.get("_deviceName");
Object deviceName = map.get("_deviceName");
if (deviceName != null && StrUtil.isNotBlank(deviceName.toString())) {
String deviceNameStr = deviceName.toString().trim();
// 验证是否为数字(终端手机号应该是纯数字)
if (deviceNameStr.matches("\\d+")) {
return deviceNameStr;
} else {
log.warn("[extractPhoneNumber][_deviceName 不是纯数字: {}]", deviceNameStr);
log.warn("[extractPhoneFromMap][_deviceName 不是纯数字: {}]", deviceNameStr);
}
}
// 2. 从 metadata 中获取(上行消息回复场景)
if (params.get("_metadata") instanceof Map) {
Map<?, ?> metadata = (Map<?, ?>) params.get("_metadata");
if (map.get("_metadata") instanceof Map) {
Map<?, ?> metadata = (Map<?, ?>) map.get("_metadata");
Object terminalPhone = metadata.get("terminalPhone");
if (terminalPhone != null && StrUtil.isNotBlank(terminalPhone.toString())) {
return terminalPhone.toString();
}
}
// 3. 从 phone 字段获取(向下兼容,不推荐)
Object phone = params.get("phone");
Object phone = map.get("phone");
if (phone != null && StrUtil.isNotBlank(phone.toString())) {
String phoneStr = phone.toString().trim();
if (phoneStr.matches("\\d+")) {
return phoneStr;
}
}
// 4. 如果都获取不到,抛出异常
log.error("[extractPhoneNumber][无法提取终端手机号params: {}]", params);
throw new IllegalArgumentException(
"消息中缺少终端手机号。请确保设备的 deviceName 为终端手机号(纯数字),例如: \"13800138000\"");
return null;
}
/**
* 提取流水号
*
*
* 对于下发消息,如果没有指定流水号,则生成一个随机流水号
*/
private int extractFlowId(IotDeviceMessage message) {
// 尝试从 params 提取
if (message.getParams() instanceof Map) {
Map<?, ?> params = (Map<?, ?>) message.getParams();
// 尝试获取显式指定的流水号
Object flowId = params.get("flowId");
if (flowId instanceof Number) {
return ((Number) flowId).intValue();
}
// 尝试从 metadata 中获取(上行消息的流水号)
if (params.get("_metadata") instanceof Map) {
Map<?, ?> metadata = (Map<?, ?>) params.get("_metadata");
Object metaFlowId = metadata.get("flowId");
if (metaFlowId instanceof Number) {
return ((Number) metaFlowId).intValue();
}
Integer flowId = extractFlowIdFromMap(params);
if (flowId != null) {
return flowId;
}
}
// 尝试从 data 提取(应答消息使用 replyOf 时,参数在 data 字段)
if (message.getData() instanceof Map) {
Map<?, ?> data = (Map<?, ?>) message.getData();
Integer flowId = extractFlowIdFromMap(data);
if (flowId != null) {
return flowId;
}
}
// 生成随机流水号1-65535
return (int) (System.currentTimeMillis() % 65535) + 1;
}
/**
* 从 Map 中提取流水号
*/
private Integer extractFlowIdFromMap(Map<?, ?> map) {
if (map == null) {
return null;
}
// 尝试获取显式指定的流水号
Object flowId = map.get("flowId");
if (flowId instanceof Number) {
return ((Number) flowId).intValue();
}
// 尝试从 metadata 中获取(上行消息的流水号)
if (map.get("_metadata") instanceof Map) {
Map<?, ?> metadata = (Map<?, ?>) map.get("_metadata");
Object metaFlowId = metadata.get("flowId");
if (metaFlowId instanceof Number) {
return ((Number) metaFlowId).intValue();
}
}
return null;
}
/**
* 获取参数为Map
*
* 优先从 params 获取,如果 params 为空则从 data 获取(应答消息场景)
*/
@SuppressWarnings("unchecked")
private Map<String, Object> getParamsAsMap(IotDeviceMessage message) {
// 优先从 params 获取
if (message.getParams() instanceof Map) {
return (Map<String, Object>) message.getParams();
}
// 尝试JSON转换
// 从 data 获取(应答消息使用 replyOf 时,参数在 data 字段)
if (message.getData() instanceof Map) {
return (Map<String, Object>) message.getData();
}
// 尝试JSON转换 params
if (message.getParams() != null) {
String json = JsonUtils.toJsonString(message.getParams());
return JsonUtils.parseObject(json, Map.class);
}
// 尝试JSON转换 data
if (message.getData() != null) {
String json = JsonUtils.toJsonString(message.getData());
return JsonUtils.parseObject(json, Map.class);
}
return new HashMap<>();
}