package com.zksy.manhole.utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; import java.util.Date; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** * 设备离线检测定时任务 * 通过 REST API 更新设备在线状态 */ @Component public class DeviceOfflineCheckTask { private static final Logger logger = LoggerFactory.getLogger(DeviceOfflineCheckTask.class); /** 设备最后接收数据时间 */ public static ConcurrentHashMap deviceLastReceiveTimeMap = new ConcurrentHashMap<>(); /** 已知离线设备集合,用于避免重复API调用 */ private final Set offlineDeviceSet = ConcurrentHashMap.newKeySet(); @Autowired private RestTemplate restTemplate; /** 离线判定超时,单位:分钟,默认30分钟 */ @Value("${device.offline.timeout-minutes:30}") private int offlineTimeoutMinutes; /** 检查间隔,单位:毫秒,默认5分钟 */ @Scheduled(fixedRateString = "${device.offline.check-interval-ms:300000}") public void checkDeviceOffline() { Date now = new Date(); long timeoutMs = (long) offlineTimeoutMinutes * 60 * 1000; for (Map.Entry entry : deviceLastReceiveTimeMap.entrySet()) { long diff = now.getTime() - entry.getValue().getTime(); if (diff > timeoutMs) { // 只在设备不在离线集合中时才调用API if (offlineDeviceSet.add(entry.getKey())) { updateDeviceOnlineStatus(entry.getKey(), 0); logger.info("设备 {} 已离线(超过{}分钟未收到数据)", entry.getKey(), offlineTimeoutMinutes); } } } } /** * 标记设备在线(收到数据时调用) * 只在设备当前处于离线状态时才调用API */ public void markDeviceOnline(String deviceCode) { if (offlineDeviceSet.remove(deviceCode)) { updateDeviceOnlineStatus(deviceCode, 1); logger.info("设备 {} 恢复在线", deviceCode); } } private void updateDeviceOnlineStatus(String deviceCode, int onlineStatus) { try { Map params = Map.of("deviceCode", deviceCode, "onlineStatus", onlineStatus); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); HttpEntity> request = new HttpEntity<>(params, headers); restTemplate.postForObject("http://zk-api-service/equipmentStatus/updateOnlineStatus", request, Map.class); } catch (Exception e) { logger.error("更新设备在线状态失败: deviceCode={}, onlineStatus={}", deviceCode, onlineStatus, e); } } }