From 0541c0791acea41b584f71fc59e22d4d21ba0883 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 15 四月 2026 11:10:46 +0800
Subject: [PATCH] ``` refactor(energy): 优化实时能耗数据服务实现
---
src/main/java/com/ruoyi/http/service/impl/RealTimeEnergyConsumptionServiceImpl.java | 411 ++++++++++++++++++++++++++++++++++++++++++----------------
1 files changed, 297 insertions(+), 114 deletions(-)
diff --git a/src/main/java/com/ruoyi/http/service/impl/RealTimeEnergyConsumptionServiceImpl.java b/src/main/java/com/ruoyi/http/service/impl/RealTimeEnergyConsumptionServiceImpl.java
index be25fb3..c529eb0 100644
--- a/src/main/java/com/ruoyi/http/service/impl/RealTimeEnergyConsumptionServiceImpl.java
+++ b/src/main/java/com/ruoyi/http/service/impl/RealTimeEnergyConsumptionServiceImpl.java
@@ -3,6 +3,7 @@
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.http.service.RealTimeEnergyConsumptionService;
import lombok.extern.slf4j.Slf4j;
@@ -10,12 +11,13 @@
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
-import java.time.Instant;
-import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
@@ -26,9 +28,7 @@
@Slf4j
public class RealTimeEnergyConsumptionServiceImpl implements RealTimeEnergyConsumptionService {
- private static final long REMOTE_CACHE_TTL_SECONDS = 10L; // 缂撳瓨TTL锛�10绉�
-
- private static final long REMOTE_CACHE_TTL_SECONDS_30 = 30L; // 缂撳瓨TTL锛�30绉�
+ private static final long REMOTE_CACHE_TTL_SECONDS_30 = 30L;
private static final String URL = "https://new.e-elitech.cn/api/data-api";
@@ -42,13 +42,25 @@
private static final String KEY_SECRET = "xTUGToozKpYgUPqTsZzB";
- private static final String USER_NAME = "鐢ㄦ埛30773662";
+ private static final String USER_NAME = "\u7528\u623730773662";
private static final String PASS_WORD = "y17775163675";
private static final String REAL_TIME_CACHE_PREFIX = "JCLY:REAL_TIME:";
private static final String HISTORY_CACHE_PREFIX = "JCLY:HISTORY:";
+
+ private static final String TOKEN_CACHE_KEY = "JCLY_TOKEN:";
+
+ private static final String STATUS_KEY = "status";
+
+ private static final String STATUS_MESSAGE_KEY = "statusMessage";
+
+ private static final String STATUS_ONLINE = "鍦ㄧ嚎";
+
+ private static final String STATUS_OFFLINE = "offline";
+
+ private static final String STATUS_ERROR = "error";
@Autowired
private RedisTemplate<String, String> redisTemplate;
@@ -68,121 +80,98 @@
public List<Map<String, String>> getHistoryData(String guid, long startTime, long endTime) {
List<Map<String, String>> resultList = new ArrayList<>();
- String historyData = requestHistoryData(getToken(), guid, startTime, endTime);
- Map<String, Object> resultMap = JSON.parseObject(historyData, Map.class);
- if (!Integer.valueOf(0).equals(resultMap.get("code"))) {
- return resultList;
- }
+ String token = getToken();
+ try {
+ String historyData = requestHistoryData(token, guid, startTime, endTime);
+ JSONObject resultObj = JSON.parseObject(historyData);
+ if (resultObj == null) {
+ resultList.add(buildStatusItem(guid, STATUS_ERROR, "history response is empty"));
+ return resultList;
+ }
- JSONArray historyList = JSON.parseArray(String.valueOf(resultMap.get("data")));
- if (historyList == null || historyList.isEmpty()) {
- return resultList;
- }
+ Integer code = resultObj.getInteger("code");
+ if (!Integer.valueOf(0).equals(code)) {
+ resultList.add(buildStatusItem(guid, resolveStatusByCodeOrMessage(code, resultObj.getString("msg")), resultObj.getString("msg")));
+ return resultList;
+ }
- for (int i = 0; i < historyList.size(); i++) {
- JSONObject historyObj = historyList.getJSONObject(i);
- Map<String, String> historyItem = new HashMap<>();
- historyItem.put("guid", firstNonBlank(
- historyObj.getString("deviceGuid"),
- historyObj.getString("guid"),
- guid
- ));
- historyItem.put("subUId", stringValue(historyObj.get("subUid")));
- historyItem.put("monitorTimeStamp", stringValue(historyObj.get("monitorTimeStamp")));
- historyItem.put("monitorTimeStr", historyObj.getString("monitorTimeStr"));
- historyItem.put("position", historyObj.getString("position"));
- historyItem.put("address", historyObj.getString("address"));
+ JSONArray historyList = resultObj.getJSONArray("data");
+ if (historyList == null || historyList.isEmpty()) {
+ resultList.add(buildStatusItem(guid, STATUS_OFFLINE, "no history data"));
+ return resultList;
+ }
- JSONArray paramList = historyObj.getJSONArray("data");
- if (paramList != null && !paramList.isEmpty()) {
- for (int j = 0; j < paramList.size(); j++) {
- JSONObject paramObj = paramList.getJSONObject(j);
- String paramName = paramObj.getString("paramName");
- String paramCode = paramObj.getString("paramCode");
- String value = paramObj.getString("value");
- String unitCode = paramObj.getString("unitCode");
- String fullValue = value == null ? null : value + (unitCode == null ? "" : unitCode);
- switch (paramName) {
- case "鎺㈠ご1":
+ for (int i = 0; i < historyList.size(); i++) {
+ JSONObject historyObj = historyList.getJSONObject(i);
+ Map<String, String> historyItem = new HashMap<>();
+ historyItem.put("guid", firstNonBlank(
+ historyObj.getString("deviceGuid"),
+ historyObj.getString("guid"),
+ guid
+ ));
+ historyItem.put("subUId", stringValue(historyObj.get("subUid")));
+ historyItem.put("monitorTimeStamp", stringValue(historyObj.get("monitorTimeStamp")));
+ historyItem.put("monitorTimeStr", historyObj.getString("monitorTimeStr"));
+ historyItem.put("position", historyObj.getString("position"));
+ historyItem.put("address", historyObj.getString("address"));
+ historyItem.put(STATUS_KEY, resolveStatusByAlarmState(historyObj.get("alarmState"), STATUS_ONLINE));
+
+ JSONArray paramList = historyObj.getJSONArray("data");
+ if (paramList != null && !paramList.isEmpty()) {
+ for (int j = 0; j < paramList.size(); j++) {
+ JSONObject paramObj = paramList.getJSONObject(j);
+ String paramCode = paramObj.getString("paramCode");
+ String value = paramObj.getString("value");
+ String unitCode = paramObj.getString("unitCode");
+ String fullValue = concatValueWithUnit(value, unitCode);
+ if ("0100".equals(paramCode)) {
historyItem.put("light", fullValue);
- break;
- case "鎺㈠ご2":
+ } else if ("0110".equals(paramCode)) {
historyItem.put("temperature", fullValue);
- break;
- case "鎺㈠ご3":
+ } else if ("0120".equals(paramCode)) {
historyItem.put("humidity", fullValue);
- break;
- case "鎺㈠ご4":
+ } else if ("0130".equals(paramCode)) {
historyItem.put("co2", fullValue);
- break;
- default:
- if (paramCode != null) {
- historyItem.put(paramCode, fullValue);
- }
- break;
+ } else if ("0042".equals(paramCode)) {
+ historyItem.put("battery", fullValue);
+ } else if (paramCode != null) {
+ historyItem.put(paramCode, fullValue);
+ }
}
}
+ resultList.add(historyItem);
}
- resultList.add(historyItem);
+ return resultList;
+ } catch (Exception ex) {
+ log.error("history data parse/request failed, guid={}", guid, ex);
+ resultList.add(buildStatusItem(guid, STATUS_ERROR, ex.getMessage()));
+ return resultList;
}
- return resultList;
}
public List<Map<String, String>> getRealData(List<String> guidList) {
- log.info("寮�濮嬭幏鍙栧疄鏃舵暟鎹�");
+ log.info("start get real data");
List<Map<String, String>> listMaps = new ArrayList<>();
- String realTimeData = getRealTimeData(getToken(), guidList);
- Map<String, Object> map = JSON.parseObject(realTimeData, Map.class);
- if (!Integer.valueOf(0).equals(map.get("code"))) {
+ if (guidList == null || guidList.isEmpty()) {
return listMaps;
}
- JSONArray deviceList = JSON.parseArray(String.valueOf(map.get("data")));
- if (deviceList == null || deviceList.isEmpty()) {
- return listMaps;
+ String token = getToken();
+ try {
+ String realTimeData = getRealTimeData(token, guidList);
+ JSONObject batchResp = JSON.parseObject(realTimeData);
+ Integer code = batchResp == null ? null : batchResp.getInteger("code");
+ if (Integer.valueOf(0).equals(code)) {
+ parseRealDataResponse(batchResp, guidList, listMaps);
+ return listMaps;
+ }
+ log.warn("batch getRealData failed, fallback one by one. code={}, msg={}", code, batchResp == null ? null : batchResp.getString("msg"));
+ } catch (Exception ex) {
+ log.error("batch getRealData exception, fallback one by one", ex);
}
- String[] targetCodes = {"0100", "0110", "0120", "0130"};
- for (int deviceIndex = 0; deviceIndex < deviceList.size(); deviceIndex++) {
- JSONObject deviceObj = deviceList.getJSONObject(deviceIndex);
- JSONArray paramList = deviceObj.getJSONArray("data");
- Map<String, String> deviceData = new HashMap<>();
- String deviceGuid = firstNonBlank(
- deviceObj.getString("deviceGuid"),
- deviceObj.getString("guid"),
- deviceObj.getString("devGuid"),
- deviceObj.getString("sn")
- );
- if (deviceGuid != null) {
- deviceData.put("guid", deviceGuid);
- }
- for (String code : targetCodes) {
- JSONObject paramObj = getProbeParam(paramList, code);
- if (paramObj.isEmpty()) {
- continue;
- }
- String paramName = paramObj.getString("paramName");
- String value = paramObj.getString("value");
- String unitCode = paramObj.getString("unitCode");
- log.info("{}: {} {}", paramName, value, unitCode);
- switch (paramName) {
- case "鎺㈠ご1":
- deviceData.put("light", value + unitCode);
- break;
- case "鎺㈠ご2":
- deviceData.put("temperature", value + unitCode);
- break;
- case "鎺㈠ご3":
- deviceData.put("humidity", value + unitCode);
- break;
- case "鎺㈠ご4":
- deviceData.put("co2", value + unitCode);
- break;
- default:
- break;
- }
- }
- listMaps.add(deviceData);
+ for (String guid : guidList) {
+ listMaps.add(fetchSingleDeviceRealData(token, guid));
}
return listMaps;
}
@@ -192,7 +181,7 @@
}
public String getToken() {
- String cachedToken = sanitizeToken(redisTemplate.opsForValue().get("JCLY_TOKEN:"));
+ String cachedToken = sanitizeToken(redisTemplate.opsForValue().get(TOKEN_CACHE_KEY));
if (cachedToken != null) {
return cachedToken;
}
@@ -201,17 +190,18 @@
param.put("keySecret", KEY_SECRET);
param.put("userName", USER_NAME);
param.put("password", PASS_WORD);
- log.info("璇锋眰鍙傛暟锛歿}", JSON.toJSONString(param));
+ log.info("request token payload: {}", JSON.toJSONString(param));
String result = HttpUtils.sendPostJson(URL + TOKEN_URL, JSON.toJSONString(param));
- log.info("杩斿洖缁撴灉锛歿}", result);
+ log.info("request token response: {}", result);
Map<String, Object> map = JSON.parseObject(result, Map.class);
if (Integer.valueOf(0).equals(map.get("code"))) {
Object token = map.get("data");
log.info("token:{}", token);
- redisTemplate.opsForValue().set("JCLY_TOKEN:", token.toString(), 60 * 60 * 24);
+ redisTemplate.opsForValue().set(TOKEN_CACHE_KEY, token.toString(), 60 * 60 * 12);
return token.toString();
}
- return result;
+ log.error("get token failed, response={}", result);
+ return null;
}
private String sanitizeToken(String token) {
@@ -235,20 +225,213 @@
return value == null ? null : String.valueOf(value);
}
+ private String refreshToken() {
+ redisTemplate.delete(TOKEN_CACHE_KEY);
+ return getToken();
+ }
+
+ private boolean isUnauthorizedException(Exception ex) {
+ if (ex == null || ex.getMessage() == null) {
+ return false;
+ }
+ String msg = ex.getMessage().toLowerCase();
+ return msg.contains("401") || msg.contains("unauthorized");
+ }
+
+ private boolean isUnauthorizedResponse(String result) {
+ if (result == null || result.trim().isEmpty()) {
+ return false;
+ }
+ try {
+ JSONObject obj = JSON.parseObject(result);
+ if (obj == null) {
+ return false;
+ }
+ Integer code = obj.getInteger("code");
+ if (code != null && (code == 401 || code == 403)) {
+ return true;
+ }
+ String msg = obj.getString("msg");
+ return msg != null && msg.toLowerCase().contains("unauthorized");
+ } catch (Exception ignore) {
+ return result.contains("401");
+ }
+ }
+
+ private String requestWithTokenRetry(String url, String payload, String token, String scene) {
+ String usedToken = sanitizeToken(token);
+ if (usedToken == null) {
+ usedToken = refreshToken();
+ }
+ try {
+ String result = HttpUtils.sendPostJson(url, payload, usedToken);
+ if (!isUnauthorizedResponse(result) && StringUtils.isNotEmpty(result)) {
+ return result;
+ }
+ log.warn("{} got unauthorized response, refresh token and retry once", scene);
+ } catch (Exception ex) {
+ if (!isUnauthorizedException(ex)) {
+ throw ex;
+ }
+ log.warn("{} got 401 exception, refresh token and retry once", scene);
+ }
+
+ String newToken = refreshToken();
+ if (newToken == null) {
+ throw new RuntimeException("refresh token failed");
+ }
+ return HttpUtils.sendPostJson(url, payload, newToken);
+ }
+
+ private String concatValueWithUnit(String value, String unitCode) {
+ if (value == null) {
+ return null;
+ }
+ return value + (unitCode == null ? "" : unitCode);
+ }
+
+ private Map<String, String> buildStatusItem(String guid, String status, String statusMessage) {
+ Map<String, String> result = new HashMap<>();
+ result.put("guid", guid);
+ result.put(STATUS_KEY, status);
+ if (statusMessage != null && !statusMessage.trim().isEmpty()) {
+ result.put(STATUS_MESSAGE_KEY, statusMessage);
+ }
+ return result;
+ }
+
+ private String resolveStatusByCodeOrMessage(Integer code, String message) {
+ if (code != null && (code == 5 || code == 1003 || code == 1004)) {
+ return STATUS_OFFLINE;
+ }
+ if (message == null) {
+ return STATUS_ERROR;
+ }
+ String lowered = message.toLowerCase();
+ if (lowered.contains("offline") || message.contains("绂荤嚎")) {
+ return STATUS_OFFLINE;
+ }
+ return STATUS_ERROR;
+ }
+
+ private void parseRealDataResponse(JSONObject responseObj, List<String> requestedGuids, List<Map<String, String>> output) {
+ JSONArray deviceList = responseObj.getJSONArray("data");
+ Set<String> returnedGuids = new HashSet<>();
+ if (deviceList != null) {
+ for (int deviceIndex = 0; deviceIndex < deviceList.size(); deviceIndex++) {
+ JSONObject deviceObj = deviceList.getJSONObject(deviceIndex);
+ Map<String, String> deviceData = parseSingleDevice(deviceObj, null);
+ String guid = deviceData.get("guid");
+ if (guid != null) {
+ returnedGuids.add(guid);
+ }
+ output.add(deviceData);
+ }
+ }
+
+ for (String requestGuid : requestedGuids) {
+ if (!returnedGuids.contains(requestGuid)) {
+ output.add(buildStatusItem(requestGuid, STATUS_OFFLINE, "device not returned by remote API"));
+ }
+ }
+ }
+
+ private Map<String, String> fetchSingleDeviceRealData(String token, String guid) {
+ try {
+ String singleResult = getRealTimeData(token, Collections.singletonList(guid));
+ JSONObject singleObj = JSON.parseObject(singleResult);
+ if (singleObj == null) {
+ return buildStatusItem(guid, STATUS_ERROR, "single device response is empty");
+ }
+ Integer code = singleObj.getInteger("code");
+ if (!Integer.valueOf(0).equals(code)) {
+ return buildStatusItem(guid, resolveStatusByCodeOrMessage(code, singleObj.getString("msg")), singleObj.getString("msg"));
+ }
+
+ JSONArray dataList = singleObj.getJSONArray("data");
+ if (dataList == null || dataList.isEmpty()) {
+ return buildStatusItem(guid, STATUS_OFFLINE, "single device response has no data");
+ }
+ return parseSingleDevice(dataList.getJSONObject(0), guid);
+ } catch (Exception ex) {
+ log.error("single getRealData failed, guid={}", guid, ex);
+ return buildStatusItem(guid, STATUS_ERROR, ex.getMessage());
+ }
+ }
+
+ private Map<String, String> parseSingleDevice(JSONObject deviceObj, String fallbackGuid) {
+ Map<String, String> deviceData = new HashMap<>();
+ String deviceGuid = firstNonBlank(
+ deviceObj.getString("deviceGuid"),
+ deviceObj.getString("guid"),
+ deviceObj.getString("devGuid"),
+ deviceObj.getString("sn"),
+ fallbackGuid
+ );
+ if (deviceGuid != null) {
+ deviceData.put("guid", deviceGuid);
+ }
+
+ JSONArray paramList = deviceObj.getJSONArray("data");
+ if (paramList == null || paramList.isEmpty()) {
+ deviceData.put(STATUS_KEY, STATUS_OFFLINE);
+ deviceData.put(STATUS_MESSAGE_KEY, "device data is empty");
+ return deviceData;
+ }
+
+ deviceData.put(STATUS_KEY, resolveStatusByAlarmState(deviceObj.get("alarmState"), STATUS_ONLINE));
+ for (int i = 0; i < paramList.size(); i++) {
+ JSONObject paramObj = paramList.getJSONObject(i);
+ String code = paramObj.getString("paramCode");
+ String value = paramObj.getString("value");
+ String unitCode = paramObj.getString("unitCode");
+ String fullValue = concatValueWithUnit(value, unitCode);
+ if ("0100".equals(code)) {
+ deviceData.put("light", fullValue);
+ } else if ("0110".equals(code)) {
+ deviceData.put("temperature", fullValue);
+ } else if ("0120".equals(code)) {
+ deviceData.put("humidity", fullValue);
+ } else if ("0130".equals(code)) {
+ deviceData.put("co2", fullValue);
+ } else if ("0042".equals(code)) {
+ deviceData.put("battery", fullValue);
+ }
+ }
+ return deviceData;
+ }
+
+ private String resolveStatusByAlarmState(Object alarmState, String defaultStatus) {
+ if (alarmState == null) {
+ return defaultStatus;
+ }
+ if (alarmState instanceof Boolean) {
+ return (Boolean) alarmState ? STATUS_OFFLINE : STATUS_ONLINE;
+ }
+ String normalized = String.valueOf(alarmState).trim().toLowerCase();
+ if ("true".equals(normalized) || "1".equals(normalized)) {
+ return STATUS_OFFLINE;
+ }
+ if ("false".equals(normalized) || "0".equals(normalized)) {
+ return STATUS_ONLINE;
+ }
+ return defaultStatus;
+ }
+
public String getRealTimeData(String token, List<String> guidList) {
Map<String, Object> param = new HashMap<>();
param.put("keyId", KET_ID);
param.put("keySecret", KEY_SECRET);
param.put("deviceGuids", guidList);
- log.info("璇锋眰鍙傛暟锛歿}", JSON.toJSONString(param));
+ log.info("request realtime payload: {}", JSON.toJSONString(param));
String cacheKey = REAL_TIME_CACHE_PREFIX + JSON.toJSONString(param);
String cachedResult = sanitizeToken(redisTemplate.opsForValue().get(cacheKey));
if (cachedResult != null) {
- log.info("鍛戒腑瀹炴椂鏁版嵁缂撳瓨锛歿}", cacheKey);
+ log.info("hit realtime cache: {}", cacheKey);
return cachedResult;
}
- String result = HttpUtils.sendPostJson(URL + REAL_TIME_URL, JSON.toJSONString(param), token);
- log.info("杩斿洖缁撴灉锛歿}", result);
+ String result = requestWithTokenRetry(URL + REAL_TIME_URL, JSON.toJSONString(param), token, "getRealTimeData");
+ log.info("request realtime response: {}", result);
cacheRemoteResponse(cacheKey, result);
return result;
}
@@ -260,15 +443,15 @@
param.put("deviceGuid", guid);
param.put("startTime", startTime);
param.put("endTime", endTime);
- log.info("鍘嗗彶鏁版嵁璇锋眰鍙傛暟锛歿}", JSON.toJSONString(param));
+ log.info("request history payload: {}", JSON.toJSONString(param));
String cacheKey = HISTORY_CACHE_PREFIX + JSON.toJSONString(param);
String cachedResult = sanitizeToken(redisTemplate.opsForValue().get(cacheKey));
if (cachedResult != null) {
- log.info("鍛戒腑鍘嗗彶鏁版嵁缂撳瓨锛歿}", cacheKey);
+ log.info("hit history cache: {}", cacheKey);
return cachedResult;
}
- String result = HttpUtils.sendPostJson(REAL_HISTORY_URL, JSON.toJSONString(param), token);
- log.info("鍘嗗彶鏁版嵁杩斿洖缁撴灉锛歿}", result);
+ String result = requestWithTokenRetry(REAL_HISTORY_URL, JSON.toJSONString(param), token, "getHistoryData");
+ log.info("request history response: {}", result);
cacheRemoteResponse(cacheKey, result);
return result;
}
--
Gitblit v1.9.3