DeviceOfflineCheckTask.java 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. package com.zksy.manhole.utils;
  2. import org.slf4j.Logger;
  3. import org.slf4j.LoggerFactory;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.beans.factory.annotation.Value;
  6. import org.springframework.http.HttpEntity;
  7. import org.springframework.http.HttpHeaders;
  8. import org.springframework.http.MediaType;
  9. import org.springframework.scheduling.annotation.Scheduled;
  10. import org.springframework.stereotype.Component;
  11. import org.springframework.web.client.RestTemplate;
  12. import java.util.Date;
  13. import java.util.Map;
  14. import java.util.Set;
  15. import java.util.concurrent.ConcurrentHashMap;
  16. /**
  17. * 设备离线检测定时任务
  18. * 通过 REST API 更新设备在线状态
  19. */
  20. @Component
  21. public class DeviceOfflineCheckTask {
  22. private static final Logger logger = LoggerFactory.getLogger(DeviceOfflineCheckTask.class);
  23. /** 设备最后接收数据时间 */
  24. public static ConcurrentHashMap<String, Date> deviceLastReceiveTimeMap = new ConcurrentHashMap<>();
  25. /** 已知离线设备集合,用于避免重复API调用 */
  26. private final Set<String> offlineDeviceSet = ConcurrentHashMap.newKeySet();
  27. @Autowired
  28. private RestTemplate restTemplate;
  29. /** 离线判定超时,单位:分钟,默认30分钟 */
  30. @Value("${device.offline.timeout-minutes:30}")
  31. private int offlineTimeoutMinutes;
  32. /** 检查间隔,单位:毫秒,默认5分钟 */
  33. @Scheduled(fixedRateString = "${device.offline.check-interval-ms:300000}")
  34. public void checkDeviceOffline() {
  35. Date now = new Date();
  36. long timeoutMs = (long) offlineTimeoutMinutes * 60 * 1000;
  37. for (Map.Entry<String, Date> entry : deviceLastReceiveTimeMap.entrySet()) {
  38. long diff = now.getTime() - entry.getValue().getTime();
  39. if (diff > timeoutMs) {
  40. // 只在设备不在离线集合中时才调用API
  41. if (offlineDeviceSet.add(entry.getKey())) {
  42. updateDeviceOnlineStatus(entry.getKey(), 0);
  43. logger.info("设备 {} 已离线(超过{}分钟未收到数据)", entry.getKey(), offlineTimeoutMinutes);
  44. }
  45. }
  46. }
  47. }
  48. /**
  49. * 标记设备在线(收到数据时调用)
  50. * 只在设备当前处于离线状态时才调用API
  51. */
  52. public void markDeviceOnline(String deviceCode) {
  53. if (offlineDeviceSet.remove(deviceCode)) {
  54. updateDeviceOnlineStatus(deviceCode, 1);
  55. logger.info("设备 {} 恢复在线", deviceCode);
  56. }
  57. }
  58. private void updateDeviceOnlineStatus(String deviceCode, int onlineStatus) {
  59. try {
  60. Map<String, Object> params = Map.of("deviceCode", deviceCode, "onlineStatus", onlineStatus);
  61. HttpHeaders headers = new HttpHeaders();
  62. headers.setContentType(MediaType.APPLICATION_JSON);
  63. HttpEntity<Map<String, Object>> request = new HttpEntity<>(params, headers);
  64. restTemplate.postForObject("http://zk-api-service/equipmentStatus/updateOnlineStatus", request, Map.class);
  65. } catch (Exception e) {
  66. logger.error("更新设备在线状态失败: deviceCode={}, onlineStatus={}", deviceCode, onlineStatus, e);
  67. }
  68. }
  69. }