|
|
@@ -9,13 +9,16 @@ import com.gyee.dataadapter.cache.MqttCache;
|
|
|
import com.gyee.dataadapter.dao.MyWebClient;
|
|
|
import com.gyee.dataadapter.entity.*;
|
|
|
import com.gyee.dataadapter.service.IAdapterService;
|
|
|
+import com.gyee.dataadapter.service.TsDataService;
|
|
|
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
|
|
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
|
|
import org.apache.http.impl.client.CloseableHttpClient;
|
|
|
import org.apache.http.impl.client.HttpClients;
|
|
|
import org.apache.http.ssl.SSLContextBuilder;
|
|
|
-import org.springframework.http.*;
|
|
|
+import org.springframework.data.redis.core.HashOperations;
|
|
|
+import org.springframework.data.redis.core.RedisTemplate;
|
|
|
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
|
|
+import org.springframework.scheduling.annotation.Scheduled;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.web.client.RestTemplate;
|
|
|
import reactor.core.publisher.Mono;
|
|
|
@@ -36,6 +39,15 @@ public class AdapterServiceImpl implements IAdapterService {
|
|
|
@Resource
|
|
|
private MyWebClient myWebClient;
|
|
|
|
|
|
+ @Resource
|
|
|
+ private RedisTemplate redisTemplate;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private IAdapterService adapterService;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private TsDataService tsDataService;
|
|
|
+
|
|
|
|
|
|
/**
|
|
|
* 请求历史数据
|
|
|
@@ -71,22 +83,22 @@ public class AdapterServiceImpl implements IAdapterService {
|
|
|
sb.append("/scadarest/api/SA/HistoryQuerySdb?start=").append(uStart).append("&end=").append(uEnd)
|
|
|
.append("&sampleType=").append(sampleType).append("&paths=").append(paths);
|
|
|
sb.append("&sampleRate=");
|
|
|
- if (sampleRate != null){
|
|
|
+ if (sampleRate != null) {
|
|
|
sb.append(sampleRate);
|
|
|
- }else {
|
|
|
- long jg = (end.getTime()-start.getTime())/1000;
|
|
|
+ } else {
|
|
|
+ long jg = (end.getTime() - start.getTime()) / 1000;
|
|
|
sb.append(jg);
|
|
|
}
|
|
|
sb.append("&pageIndex=");
|
|
|
- if (StrUtil.isNotBlank(pageIndex)){
|
|
|
+ if (StrUtil.isNotBlank(pageIndex)) {
|
|
|
sb.append(pageIndex);
|
|
|
- }else {
|
|
|
+ } else {
|
|
|
sb.append(1);
|
|
|
}
|
|
|
sb.append("&pageSize=");
|
|
|
- if (StrUtil.isNotBlank(pageSize)){
|
|
|
+ if (StrUtil.isNotBlank(pageSize)) {
|
|
|
sb.append(pageSize);
|
|
|
- }else {
|
|
|
+ } else {
|
|
|
sb.append(90000);
|
|
|
}
|
|
|
sb.append("&isDesc=");
|
|
|
@@ -133,7 +145,7 @@ public class AdapterServiceImpl implements IAdapterService {
|
|
|
end = DateUtil.offsetHour(end, -8);
|
|
|
String uStart = DateUtil.formatDateTime(start);
|
|
|
String uEnd = DateUtil.formatDateTime(end);
|
|
|
- long jg = (end.getTime()-start.getTime())/1000;
|
|
|
+ long jg = (end.getTime() - start.getTime()) / 1000;
|
|
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
sb.append("/scadarest/api/SA/HistoryQuerySdb?start=").append(uStart).append("&end=").append(uEnd)
|
|
|
@@ -228,18 +240,93 @@ public class AdapterServiceImpl implements IAdapterService {
|
|
|
* @param tagNames 根据逗号隔开的测点
|
|
|
* @return 测点的实时数据
|
|
|
*/
|
|
|
- @Override
|
|
|
+// @Override
|
|
|
+// public Map<String, PointData> getLatestData2(List<String> tagNames) {
|
|
|
+// Map<String, PointData> map = new HashMap<>();
|
|
|
+// if (CollUtil.isEmpty(tagNames)) return map;
|
|
|
+// for (String path : tagNames) {
|
|
|
+// PointData pd = MqttCache.subData2.get(path);
|
|
|
+// if(pd!=null) map.put(path, pd);
|
|
|
+// }
|
|
|
+// return map;
|
|
|
+// }
|
|
|
public Map<String, PointData> getLatestData2(List<String> tagNames) {
|
|
|
Map<String, PointData> map = new HashMap<>();
|
|
|
- if (CollUtil.isEmpty(tagNames)) return map;
|
|
|
+ if (CollUtil.isEmpty(tagNames)) {
|
|
|
+ return map;
|
|
|
+ }
|
|
|
+
|
|
|
for (String path : tagNames) {
|
|
|
- PointData pd = MqttCache.subData2.get(path);
|
|
|
- if(pd!=null) map.put(path, pd);
|
|
|
+ String redisKey = "mqtt:point:" + path; // 构造完整 Key
|
|
|
+
|
|
|
+ // 1. 优先从 Redis 获取实时数据(使用 ValueOperations)
|
|
|
+ PointData pd = (PointData) redisTemplate.opsForValue().get(redisKey);
|
|
|
+ if (pd != null) {
|
|
|
+ map.put(path, pd);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. Redis 无数据,尝试从历史接口获取最新时刻的数据
|
|
|
+ PointData resultPd = null;
|
|
|
+ Date latestTime = new Date();
|
|
|
+ Map<String, PointData> historyResult = tsDataService.getHistorySection(latestTime, path);
|
|
|
+ if (historyResult != null && historyResult.containsKey(path)) {
|
|
|
+ resultPd = historyResult.get(path);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 仍无数据,查询最近一个月的原始历史数据,取最新一条
|
|
|
+ if (resultPd == null) {
|
|
|
+ Date endTime = new Date();
|
|
|
+ Date startTime = DateUtil.offsetMonth(endTime, -1);
|
|
|
+ List<PointData> rawHistoryList = tsDataService.getHistoryRaw(path, startTime, endTime);
|
|
|
+ if (CollUtil.isNotEmpty(rawHistoryList)) {
|
|
|
+ resultPd = rawHistoryList.get(rawHistoryList.size() - 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 如果获取到了有效数据,则回填 Redis 并加入返回 Map
|
|
|
+ if (resultPd != null) {
|
|
|
+ redisTemplate.opsForValue().set(redisKey, resultPd); // 回填 Redis
|
|
|
+ map.put(path, resultPd);
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
return map;
|
|
|
}
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
+ * 每 30 秒执行一次,将 MqttCache.subData2 全量写入 Redis
|
|
|
+ */
|
|
|
+ @Scheduled(fixedRate = 30000) // 单位:毫秒,30000ms = 30s
|
|
|
+ public void scheduledWriteToRedis() {
|
|
|
+ writeRedis();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将 MqttCache.subData2 中的所有数据写入 Redis
|
|
|
+ */
|
|
|
+ public void writeRedis() {
|
|
|
+ Map<String, PointData> pdMap = MqttCache.subData2;
|
|
|
+ if (pdMap == null || pdMap.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 遍历 Map,每个测点一个独立的 Redis Key
|
|
|
+ for (Map.Entry<String, PointData> entry : pdMap.entrySet()) {
|
|
|
+ String pname = entry.getKey();
|
|
|
+ PointData pi = entry.getValue();
|
|
|
+ String redisKey = "mqtt:point:" + pname;
|
|
|
+ try {
|
|
|
+ redisTemplate.opsForValue().set(redisKey, pi);
|
|
|
+ } catch (Exception e) {
|
|
|
+ // 记录日志,避免单条失败影响其他数据
|
|
|
+ System.err.println("写入 Redis 失败,Key: " + redisKey + ",错误:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
public static RestTemplate createRestTemplateWithSSLDisabled() {
|
|
|
try {
|
|
|
// 创建一个不验证主机名的 SSLContext
|