吉安感知网项目-后端
xiebin
2026-01-06 d207a86cdf1ab52ef8cb7cd83bad8fceab8038cf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package org.sxkj.common.cache;
 
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.sxkj.common.enums.RefreshStatusEnum;
import org.sxkj.common.func.Streams;
 
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
 
/**
 * 比较前后状态是否一致
 */
public class StatusCacheUtils {
 
    /**
     * 上一次获取的设备状态值缓存
     * Key: 用户ID, Value: 设备状态列表
     */
    private static final ConcurrentHashMap<String, List<StatusBo>> STATUS_CACHE = new ConcurrentHashMap<>();
 
    /**
     * 检查间隔时间内设备状态是否变更
     *
     * @param userId       用户ID
     * @param intervalTime 间隔时间(秒)
     * @param supplier     设备SN列表提供函数
     * @return true-状态已变更需要处理, false-状态未变更
     */
    public static boolean intervalTimeStatusChange(Long userId, RefreshStatusEnum refreshStatusEnum, int intervalTime, Supplier<List<String>> supplier) {
        if (Objects.isNull(userId)) {
            return false;
        }
        String unionKey = refreshStatusEnum.name() + userId;
        // 获取缓存中的设备状态
        List<StatusBo> cachedStatus = STATUS_CACHE.get(unionKey);
 
        // 检查是否需要刷新缓存
        if (shouldRefreshCache(cachedStatus, intervalTime)) {
            cachedStatus = refreshStatusCache(userId, supplier, refreshStatusEnum);
        }
 
        // 无设备状态数据时直接返回false
        if (CollectionUtils.isEmpty(cachedStatus)) {
            return false;
        }
 
        // 获取当前设备状态
        List<String> sns = Streams.toList(cachedStatus, StatusBo::getKey);
        List<StatusBo> currentStatus = getStatuses(sns, refreshStatusEnum);
        // 比较状态并更新缓存
        boolean statusChanged = !compareStatus(cachedStatus, currentStatus);
        STATUS_CACHE.put(unionKey, currentStatus);
        return statusChanged;
    }
 
    /**
     * 判断是否需要刷新缓存
     */
    private static boolean shouldRefreshCache(List<StatusBo> cachedStatus, int intervalTime) {
        if (CollectionUtils.isEmpty(cachedStatus)) {
            return true;
        }
 
        // 计算时间差(绝对值)
        long timeDiff = Math.abs(System.currentTimeMillis() - cachedStatus.get(0).getTime());
        return timeDiff >= intervalTime * 2 * 1000L;
    }
 
    /**
     * 刷新设备状态缓存
     *
     * @param userId
     * @param supplier
     * @param refreshStatusEnum
     * @return
     */
    private static List<StatusBo> refreshStatusCache(Long userId, Supplier<List<String>> supplier
        , RefreshStatusEnum refreshStatusEnum) {
        // sns 要看 refreshStatusEnum 是设备的还是任务的,如果是设备的就是设备的sn 如果是任务就是当前用户的arecode  例如 36
        List<String> sns = supplier.get();
        if (CollectionUtils.isEmpty(sns)) {
            return Collections.emptyList();
        }
 
        List<StatusBo> newStatus = getStatuses(sns, refreshStatusEnum);
        STATUS_CACHE.put(refreshStatusEnum.name() + userId, newStatus);
        return newStatus;
    }
 
    /**
     * 比较两个设备状态列表是否一致
     */
    private static boolean compareStatus(List<StatusBo> before, List<StatusBo> current) {
        if (before == current) return true;
        if (before == null || current == null) return false;
        if (before.size() != current.size()) return false;
 
        // 创建设备SN到状态码的映射
        Map<String, String> statusMap = Streams.toMap(before,
            StatusBo::getKey,
            StatusBo::getValue);
 
        // 比较每个设备的状态
        return current.stream().allMatch(curr -> {
            String prevCode = statusMap.get(curr.getKey());
            return Objects.equals(prevCode, curr.getValue());
        });
    }
 
    /**
     * 获取设备状态列表
     */
    private static List<StatusBo> getStatuses(List<String> sns, RefreshStatusEnum refreshStatusEnum) {
        long currentTime = System.currentTimeMillis();
        return Streams.toList(sns, sn -> {
            StatusBo status = new StatusBo();
            status.setKey(sn);
            String modelCode = CurrentCacheUtils.getValue(refreshStatusEnum + sn);
            status.setValue(StringUtils.isEmpty(modelCode) ? "-1" : modelCode);
            status.setTime(currentTime);
            return status;
        });
    }
 
    /**
     * 清空状态缓存
     */
    public static void clearStatusCache() {
        STATUS_CACHE.clear();
    }
 
}