9 小时以前 98d925ee9e40ccffed46f9000ae4f066aa99776b
```
refactor(energy): 优化实时能耗数据服务实现

- 移除未使用的导入和常量定义
- 添加状态码和消息常量用于设备状态管理
- 重构历史数据获取方法,增加异常处理和状态反馈
- 改进实时数据获取逻辑,支持单设备回退机制
- 添加设备状态构建和解析功能
- 优化日志输出信息为英文格式
- 统一参数代码匹配方式,提升数据处理准确性
- 增强缓存命中和请求响应的日志记录
```
已修改2个文件
325 ■■■■■ 文件已修改
src/main/java/com/ruoyi/http/service/controller/JclyController.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/http/service/impl/RealTimeEnergyConsumptionServiceImpl.java 323 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/http/service/controller/JclyController.java
@@ -67,6 +67,8 @@
        return AjaxResult.success(maps);
    }
    /**
     * 获取历史数据
     */
src/main/java/com/ruoyi/http/service/impl/RealTimeEnergyConsumptionServiceImpl.java
@@ -10,12 +10,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 +27,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 +41,23 @@
    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 STATUS_KEY = "status";
    private static final String STATUS_MESSAGE_KEY = "statusMessage";
    private static final String STATUS_OK = "ok";
    private static final String STATUS_OFFLINE = "offline";
    private static final String STATUS_ERROR = "error";
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
@@ -68,121 +77,96 @@
    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, STATUS_OK);
                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 (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;
    }
@@ -201,9 +185,9 @@
        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");
@@ -235,20 +219,139 @@
        return value == null ? null : String.valueOf(value);
    }
    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) {
        String[] targetCodes = {"0100", "0110", "0120", "0130"};
        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, STATUS_OK);
        for (String code : targetCodes) {
            JSONObject paramObj = getProbeParam(paramList, code);
            if (paramObj.isEmpty()) {
                continue;
            }
            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);
            }
        }
        return deviceData;
    }
    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);
        log.info("request realtime response: {}", result);
        cacheRemoteResponse(cacheKey, result);
        return result;
    }
@@ -260,15 +363,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);
        log.info("request history response: {}", result);
        cacheRemoteResponse(cacheKey, result);
        return result;
    }
@@ -279,4 +382,4 @@
        }
        redisTemplate.opsForValue().set(cacheKey, result, REMOTE_CACHE_TTL_SECONDS_30, TimeUnit.SECONDS);
    }
}
}