diff --git a/pom.xml b/pom.xml
index 91b26d6..8f498a1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -111,6 +111,12 @@
provided
+
+
+ com.github.ben-manes.caffeine
+ caffeine
+
+
org.springframework.integration
diff --git a/src/main/java/com/ruoyi/device/domain/impl/ThingsBoardDomainImpl.java b/src/main/java/com/ruoyi/device/domain/impl/ThingsBoardDomainImpl.java
index 50349d3..d464842 100644
--- a/src/main/java/com/ruoyi/device/domain/impl/ThingsBoardDomainImpl.java
+++ b/src/main/java/com/ruoyi/device/domain/impl/ThingsBoardDomainImpl.java
@@ -1,6 +1,9 @@
package com.ruoyi.device.domain.impl;
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
+import com.github.benmanes.caffeine.cache.Expiry;
import com.ruoyi.device.domain.api.IThingsBoardDomain;
import com.ruoyi.device.domain.model.thingsboard.*;
import com.ruoyi.device.domain.model.thingsboard.constants.DeviceAttributes;
@@ -27,7 +30,9 @@ import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
+import java.util.Random;
import java.util.UUID;
+import java.util.concurrent.TimeUnit;
/**
* ThingsBoard设备服务实现类
@@ -41,6 +46,10 @@ public class ThingsBoardDomainImpl implements IThingsBoardDomain {
private final RestClient client;
private final int pageSize;
+ private final Random random = new Random();
+
+ private final Cache attributesCache;
+ private final Cache telemetryCache;
/**
* 构造函数 - Spring 会自动装配
@@ -51,6 +60,48 @@ public class ThingsBoardDomainImpl implements IThingsBoardDomain {
@Value("${thingsboard.page-size:10}") int pageSize) {
this.client = clientManager.getClient();
this.pageSize = pageSize;
+
+ this.attributesCache = Caffeine.newBuilder()
+ .expireAfter(new Expiry() {
+ @Override
+ public long expireAfterCreate(String key, AttributeMap value, long currentTime) {
+ long randomSeconds = 60 + random.nextInt(61);
+ return TimeUnit.SECONDS.toNanos(randomSeconds);
+ }
+
+ @Override
+ public long expireAfterUpdate(String key, AttributeMap value, long currentTime, long currentDuration) {
+ long randomSeconds = 60 + random.nextInt(61);
+ return TimeUnit.SECONDS.toNanos(randomSeconds);
+ }
+
+ @Override
+ public long expireAfterRead(String key, AttributeMap value, long currentTime, long currentDuration) {
+ return currentDuration;
+ }
+ })
+ .build();
+
+ this.telemetryCache = Caffeine.newBuilder()
+ .expireAfter(new Expiry() {
+ @Override
+ public long expireAfterCreate(String key, TelemetryMap value, long currentTime) {
+ long randomSeconds = 12 + random.nextInt(7);
+ return TimeUnit.SECONDS.toNanos(randomSeconds);
+ }
+
+ @Override
+ public long expireAfterUpdate(String key, TelemetryMap value, long currentTime, long currentDuration) {
+ long randomSeconds = 12 + random.nextInt(7);
+ return TimeUnit.SECONDS.toNanos(randomSeconds);
+ }
+
+ @Override
+ public long expireAfterRead(String key, TelemetryMap value, long currentTime, long currentDuration) {
+ return currentDuration;
+ }
+ })
+ .build();
}
@Override
@@ -88,68 +139,66 @@ public class ThingsBoardDomainImpl implements IThingsBoardDomain {
@Override
public AttributeMap getDeviceAttributes(String deviceId) {
- AttributeMap attributeMap = new AttributeMap();
+ return attributesCache.get(deviceId, id -> {
+ AttributeMap attributeMap = new AttributeMap();
- try {
- DeviceId id = new DeviceId(UUID.fromString(deviceId));
+ try {
+ DeviceId deviceIdObj = new DeviceId(UUID.fromString(id));
- // 获取所有属性键
- List attributeKeys = client.getAttributeKeys(id);
- if (attributeKeys == null || attributeKeys.isEmpty()) {
- log.debug("设备 {} 没有属性", deviceId);
- return attributeMap;
+ List attributeKeys = client.getAttributeKeys(deviceIdObj);
+ if (attributeKeys == null || attributeKeys.isEmpty()) {
+ log.debug("设备 {} 没有属性", id);
+ return attributeMap;
+ }
+
+ List attributeKvEntries = client.getAttributeKvEntries(deviceIdObj, attributeKeys);
+ if (attributeKvEntries == null || attributeKvEntries.isEmpty()) {
+ log.debug("设备 {} 的属性值为空", id);
+ return attributeMap;
+ }
+
+ for (AttributeKvEntry entry : attributeKvEntries) {
+ parseAndPutAttribute(attributeMap, entry);
+ }
+
+ } catch (Exception e) {
+ log.error("获取设备属性失败: deviceId={}, error={}", id, e.getMessage(), e);
}
- // 获取属性值
- List attributeKvEntries = client.getAttributeKvEntries(id, attributeKeys);
- if (attributeKvEntries == null || attributeKvEntries.isEmpty()) {
- log.debug("设备 {} 的属性值为空", deviceId);
- return attributeMap;
- }
-
- // 解析并填充到AttributeMap
- for (AttributeKvEntry entry : attributeKvEntries) {
- parseAndPutAttribute(attributeMap, entry);
- }
-
- } catch (Exception e) {
- log.error("获取设备属性失败: deviceId={}, error={}", deviceId, e.getMessage(), e);
- }
-
- return attributeMap;
+ return attributeMap;
+ });
}
@Override
public TelemetryMap getDeviceTelemetry(String deviceId) {
- TelemetryMap telemetryMap = new TelemetryMap();
+ return telemetryCache.get(deviceId, id -> {
+ TelemetryMap telemetryMap = new TelemetryMap();
- try {
- DeviceId id = new DeviceId(UUID.fromString(deviceId));
+ try {
+ DeviceId deviceIdObj = new DeviceId(UUID.fromString(id));
- // 获取所有遥测键
- List timeseriesKeys = client.getTimeseriesKeys(id);
- if (timeseriesKeys == null || timeseriesKeys.isEmpty()) {
- log.debug("设备 {} 没有遥测数据", deviceId);
- return telemetryMap;
+ List timeseriesKeys = client.getTimeseriesKeys(deviceIdObj);
+ if (timeseriesKeys == null || timeseriesKeys.isEmpty()) {
+ log.debug("设备 {} 没有遥测数据", id);
+ return telemetryMap;
+ }
+
+ List latestTimeseries = client.getLatestTimeseries(deviceIdObj, timeseriesKeys);
+ if (latestTimeseries == null || latestTimeseries.isEmpty()) {
+ log.debug("设备 {} 的遥测数据为空", id);
+ return telemetryMap;
+ }
+
+ for (TsKvEntry entry : latestTimeseries) {
+ parseAndPutTelemetry(telemetryMap, entry);
+ }
+
+ } catch (Exception e) {
+ log.error("获取设备遥测数据失败: deviceId={}, error={}", id, e.getMessage(), e);
}
- // 获取最新的遥测数据
- List latestTimeseries = client.getLatestTimeseries(id, timeseriesKeys);
- if (latestTimeseries == null || latestTimeseries.isEmpty()) {
- log.debug("设备 {} 的遥测数据为空", deviceId);
- return telemetryMap;
- }
-
- // 解析并填充到TelemetryMap
- for (TsKvEntry entry : latestTimeseries) {
- parseAndPutTelemetry(telemetryMap, entry);
- }
-
- } catch (Exception e) {
- log.error("获取设备遥测数据失败: deviceId={}, error={}", deviceId, e.getMessage(), e);
- }
-
- return telemetryMap;
+ return telemetryMap;
+ });
}