Compare commits
12 Commits
5489125cfa
...
016a1e18b7
| Author | SHA1 | Date | |
|---|---|---|---|
| 016a1e18b7 | |||
| 7a81d9e478 | |||
| ea55347651 | |||
| 7561ddf9e9 | |||
| bb8f76d531 | |||
| 69b0767fd7 | |||
| 1737566245 | |||
| 8d52e9e413 | |||
| a5c2b7aabf | |||
| 6d159a02fe | |||
| 97fef34098 | |||
| a2a9ef0c30 |
@@ -47,8 +47,22 @@ public class IoTDeviceApiImpl implements IotDeviceCommonApi {
|
||||
@PostMapping(RpcConstants.RPC_API_PREFIX + "/iot/device/get") // 特殊:方便调用,暂时使用 POST,实际更推荐 GET
|
||||
@PermitAll
|
||||
public CommonResult<IotDeviceRespDTO> getDevice(@RequestBody IotDeviceGetReqDTO getReqDTO) {
|
||||
IotDeviceDO device = getReqDTO.getId() != null ? deviceService.getDeviceFromCache(getReqDTO.getId())
|
||||
: deviceService.getDeviceFromCache(getReqDTO.getProductKey(), getReqDTO.getDeviceName());
|
||||
IotDeviceDO device;
|
||||
|
||||
// 查询优先级:id > (productKey + deviceName) > deviceName
|
||||
if (getReqDTO.getId() != null) {
|
||||
// 通过设备 ID 查询
|
||||
device = deviceService.getDeviceFromCache(getReqDTO.getId());
|
||||
} else if (getReqDTO.getProductKey() != null && getReqDTO.getDeviceName() != null) {
|
||||
// 通过 productKey + deviceName 查询
|
||||
device = deviceService.getDeviceFromCache(getReqDTO.getProductKey(), getReqDTO.getDeviceName());
|
||||
} else if (getReqDTO.getDeviceName() != null) {
|
||||
// 仅通过 deviceName 查询(用于 JT808 等协议,终端手机号应该是全局唯一的)
|
||||
device = deviceService.getDeviceFromCacheByDeviceName(getReqDTO.getDeviceName());
|
||||
} else {
|
||||
device = null;
|
||||
}
|
||||
|
||||
return success(BeanUtils.toBean(device, IotDeviceRespDTO.class, deviceDTO -> {
|
||||
IotProductDO product = productService.getProductFromCache(deviceDTO.getProductId());
|
||||
if (product != null) {
|
||||
|
||||
@@ -131,6 +131,19 @@ public interface IotDeviceService {
|
||||
*/
|
||||
IotDeviceDO getDeviceFromCache(String productKey, String deviceName);
|
||||
|
||||
/**
|
||||
* 【缓存】根据设备名称获得设备信息(仅通过设备名称查询)
|
||||
* <p>
|
||||
* 注意:该方法会忽略租户信息,所以调用时,需要确认会不会有跨租户访问的风险!!!
|
||||
* <p>
|
||||
* 此方法主要用于 JT808 等协议,设备在注册时只知道终端手机号(deviceName),
|
||||
* 不知道 productKey。对于 JT808 协议,终端手机号应该是全局唯一的。
|
||||
*
|
||||
* @param deviceName 设备名称(如 JT808 的终端手机号)
|
||||
* @return 设备信息,未找到返回 null
|
||||
*/
|
||||
IotDeviceDO getDeviceFromCacheByDeviceName(String deviceName);
|
||||
|
||||
/**
|
||||
* 获得设备分页
|
||||
*
|
||||
|
||||
@@ -259,6 +259,13 @@ public class IotDeviceServiceImpl implements IotDeviceService {
|
||||
return deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = RedisKeyConstants.DEVICE, key = "'deviceName_' + #deviceName", unless = "#result == null")
|
||||
@TenantIgnore // 忽略租户信息,用于 JT808 等协议,终端手机号应该是全局唯一的
|
||||
public IotDeviceDO getDeviceFromCacheByDeviceName(String deviceName) {
|
||||
return deviceMapper.selectByDeviceName(deviceName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<IotDeviceDO> getDevicePage(IotDevicePageReqVO pageReqVO) {
|
||||
return deviceMapper.selectPage(pageReqVO);
|
||||
|
||||
@@ -95,16 +95,51 @@ public class IotTcpJsonDeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
@SuppressWarnings("DataFlowIssue")
|
||||
public IotDeviceMessage decode(byte[] bytes) {
|
||||
String jsonStr = StrUtil.utf8Str(bytes).trim();
|
||||
TcpJsonMessage tcpJsonMessage = JsonUtils.parseObject(jsonStr, TcpJsonMessage.class);
|
||||
Assert.notNull(tcpJsonMessage, "消息不能为空");
|
||||
Assert.notBlank(tcpJsonMessage.getMethod(), "消息方法不能为空");
|
||||
return IotDeviceMessage.of(
|
||||
tcpJsonMessage.getId(),
|
||||
tcpJsonMessage.getMethod(),
|
||||
tcpJsonMessage.getParams(),
|
||||
tcpJsonMessage.getData(),
|
||||
tcpJsonMessage.getCode(),
|
||||
tcpJsonMessage.getMsg());
|
||||
|
||||
// 快速验证是否为 JSON 格式(必须以 { 或 [ 开头)
|
||||
if (StrUtil.isBlank(jsonStr)) {
|
||||
throw new IllegalArgumentException("JSON 数据为空");
|
||||
}
|
||||
|
||||
String trimmedJson = jsonStr.trim();
|
||||
if (!trimmedJson.startsWith("{") && !trimmedJson.startsWith("[")) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("不是有效的 JSON 格式,数据开头: %s",
|
||||
jsonStr.length() > 20 ? jsonStr.substring(0, 20) : jsonStr));
|
||||
}
|
||||
|
||||
try {
|
||||
TcpJsonMessage tcpJsonMessage = JsonUtils.parseObject(jsonStr, TcpJsonMessage.class);
|
||||
|
||||
// 检查解析结果
|
||||
if (tcpJsonMessage == null) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("JSON 解析返回 null,可能是空对象或格式错误,数据: %s",
|
||||
jsonStr.length() > 100 ? jsonStr.substring(0, 100) + "..." : jsonStr));
|
||||
}
|
||||
|
||||
// 检查必要字段
|
||||
if (StrUtil.isBlank(tcpJsonMessage.getMethod())) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("JSON 消息缺少 method 字段,数据: %s",
|
||||
jsonStr.length() > 100 ? jsonStr.substring(0, 100) + "..." : jsonStr));
|
||||
}
|
||||
|
||||
return IotDeviceMessage.of(
|
||||
tcpJsonMessage.getId(),
|
||||
tcpJsonMessage.getMethod(),
|
||||
tcpJsonMessage.getParams(),
|
||||
tcpJsonMessage.getData(),
|
||||
tcpJsonMessage.getCode(),
|
||||
tcpJsonMessage.getMsg());
|
||||
} catch (IllegalArgumentException e) {
|
||||
// 重新抛出 IllegalArgumentException(已经是我们自己的错误信息)
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("JSON 解析失败,数据开头: %s,错误: %s",
|
||||
jsonStr.length() > 50 ? jsonStr.substring(0, 50) : jsonStr, e.getMessage()), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user