add
yj
2024-12-05 b9900893177c78fc559223521fe839aa21000017
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
package com.dobbinsoft.fw.support.component;
 
import com.alibaba.fastjson.JSONObject;
import com.dobbinsoft.fw.support.model.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
 
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
 
/**
 * Created by rize on 2019/3/22.
 */
@Component
public class CacheComponent {
 
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
 
    @Autowired(required = false)
    private BeforeGetCacheKey beforeGetCacheKey;
 
    /**
     * 用于描述一系列的 将要执行的 Redis (写)操作
     */
    private ThreadLocal<CacheContext> contextThreadLocal = new ThreadLocal<>();
 
    /**
     * 放入不过期不序列化缓存
     *
     * @param key
     * @param value
     */
    public void putRaw(String key, String value) {
        stringRedisTemplate.opsForValue().set(getKey(key), value);
    }
 
    /**
     * 放入不过期不序列化缓存
     *
     * @param key
     * @param value
     * @param expireSec
     */
    public void putRaw(String key, String value, Integer expireSec) {
        stringRedisTemplate.opsForValue().set(getKey(key), value, expireSec, TimeUnit.SECONDS);
    }
 
    /**
     * 直接获取不反序列化缓存
     *
     * @param key
     * @return
     */
    public String getRaw(String key) {
        return stringRedisTemplate.opsForValue().get(getKey(key));
    }
 
 
    /**
     * 放入对象/集合,进行序列化
     *
     * @param key
     * @param obj
     */
    public void putObj(String key, Object obj) {
        stringRedisTemplate.opsForValue().set(getKey(key), JSONObject.toJSONString(obj));
    }
 
    /**
     * 放入对象/集合,进行序列化,带过期时间
     *
     * @param key
     * @param obj
     * @param expireSec
     */
    public void putObj(String key, Object obj, Integer expireSec) {
        stringRedisTemplate.opsForValue().set(getKey(key), JSONObject.toJSONString(obj), expireSec, TimeUnit.SECONDS);
    }
 
    /**
     * 获取对象进行序列化
     *
     * @param key
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T getObj(String key, Class<T> clazz) {
        String json = stringRedisTemplate.opsForValue().get(getKey(key));
        if (StringUtils.isEmpty(json)) {
            return null;
        }
        return JSONObject.parseObject(json, clazz);
    }
 
    /**
     * 获取对象列表
     *
     * @param key
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> List<T> getObjList(String key, Class<T> clazz) {
        String json = stringRedisTemplate.opsForValue().get(getKey(key));
        if (StringUtils.isEmpty(json)) {
            return null;
        }
        return JSONObject.parseArray(json, clazz);
    }
 
    /**
     * 将值放入Hash里
     *
     * @param key
     * @param hashKey
     * @param value
     */
    public void putHashRaw(String key, String hashKey, String value) {
        stringRedisTemplate.opsForHash().put(getKey(key), hashKey, value);
    }
 
    /**
     * 设置Hash对象,进行序列化
     *
     * @param key
     * @param hashKey
     * @param obj
     */
    public void putHashObj(String key, String hashKey, Object obj) {
        stringRedisTemplate.opsForHash().put(getKey(key), hashKey, JSONObject.toJSONString(obj));
    }
 
    /**
     * 设置Hash对象,进行序列化
     *
     * @param key
     * @param hashKey
     * @param obj
     * @param expireSec
     */
    public void putHashObj(String key, String hashKey, Object obj, Integer expireSec) {
        String k = getKey(key);
        boolean hasKey = stringRedisTemplate.hasKey(k);
        stringRedisTemplate.opsForHash().put(k, hashKey, JSONObject.toJSONString(obj));
        if (!hasKey) {
            stringRedisTemplate.expire(k, expireSec, TimeUnit.SECONDS);
        }
    }
 
    /**
     * 增加Hash表中键的字面数值
     *
     * @param key
     * @param hashKey
     * @param delta
     * @return
     */
    public long incrementHashKey(String key, String hashKey, long delta) {
        return stringRedisTemplate.opsForHash().increment(getKey(key), hashKey, delta);
    }
 
    /**
     * 减少Hash表中字面的数值
     *
     * @param key
     * @param hashKey
     * @param delta
     * @return
     */
    public long decrementHashKey(String key, String hashKey, long delta) {
        return stringRedisTemplate.opsForHash().increment(getKey(key), hashKey, -delta);
    }
 
    /**
     * 获取Hash值,不进行序列化
     *
     * @param key
     * @param hashKey
     * @return
     */
    public String getHashRaw(String key, String hashKey) {
        String o = (String) stringRedisTemplate.opsForHash().get(getKey(key), hashKey);
        if (StringUtils.isEmpty(o)) {
            return null;
        }
        return o;
    }
 
    /**
     * 获取Hash值,带反序列化
     *
     * @param key
     * @param hashKey
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T getHashObj(String key, String hashKey, Class<T> clazz) {
        String o = (String) stringRedisTemplate.opsForHash().get(getKey(key), hashKey);
        if (StringUtils.isEmpty(o)) {
            return null;
        }
        return JSONObject.parseObject(o, clazz);
    }
 
    /**
     * 获取Hash值,以数组的形式反序列化
     *
     * @param key
     * @param hashKey
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> List<T> getHashList(String key, String hashKey, Class<T> clazz) {
        String o = (String) stringRedisTemplate.opsForHash().get(getKey(key), hashKey);
        if (StringUtils.isEmpty(o)) {
            return null;
        }
        return JSONObject.parseArray(o, clazz);
    }
 
    /**
     * 批量获取Hash表里面的值
     *
     * @param key 桶的名字
     * @param hashKeys String类型键集合 Collection<String>
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> List<T> getHashMultiAsList(String key, Collection hashKeys, Class<T> clazz) {
        List<String> list = stringRedisTemplate.opsForHash().multiGet(getKey(key), hashKeys);
        return list.stream().map(item -> JSONObject.parseObject(item, clazz)).collect(Collectors.toList());
    }
 
    /**
     * 批量获取Hash值 列表
     *
     * @param key
     * @param hashKeys
     * @return
     */
    public List<String> getHashMultiAsRawList(String key, Collection hashKeys) {
        List<String> list = stringRedisTemplate.opsForHash().multiGet(getKey(key), hashKeys);
        return list;
    }
 
    /**
     * 删除Hash值
     *
     * @param key
     * @param hashKey
     */
    public void delHashKey(String key, String hashKey) {
        stringRedisTemplate.opsForHash().delete(getKey(key), hashKey);
    }
 
    public void putHashAll(String key, Map<String, String> map, Integer expireSec) {
        String k = getKey(key);
        stringRedisTemplate.opsForHash().putAll(k, map);
        stringRedisTemplate.expire(k, expireSec, TimeUnit.SECONDS);
    }
 
    public Map<String,String> getHashAll(String key) {
        String k = getKey(key);
        if (!stringRedisTemplate.hasKey(k)) {
            return null;
        }
        return (Map)stringRedisTemplate.opsForHash().entries(k);
    }
 
 
    /**
     * 向有序集合中添加元素
     *
     * @param setName
     * @param source
     * @param value
     */
    public void putZSet(String setName, double source, String value) {
        stringRedisTemplate.opsForZSet().add(getKey(setName), value, source);
    }
 
    public void putZSetMulti(String setName, Set<ZSetOperations.TypedTuple<String>> values) {
        stringRedisTemplate.opsForZSet().add(getKey(setName), values);
    }
 
    /**
     * 从有序集合中移除数据
     *
     * @param setName
     * @param value
     */
    public void delZSet(String setName, String value) {
        stringRedisTemplate.opsForZSet().remove(getKey(setName), value);
    }
 
    /**
     * 从有序集合中分页获取数据
     *
     * @param setName
     * @param pageNo
     * @param pageSize
     * @param isAsc
     * @return
     */
    public Page<String> getZSetPage(String setName, int pageNo, int pageSize, boolean isAsc) {
        String key = getKey(setName);
        Long size = stringRedisTemplate.opsForZSet().size(key);
        List<String> list = new ArrayList<>();
        if (size > 0) {
            if (isAsc) {
                list.addAll(stringRedisTemplate.opsForZSet().range(key, (pageNo - 1) * pageSize, pageNo * pageSize - 1));
            } else {
                list.addAll(stringRedisTemplate.opsForZSet().reverseRange(key, (pageNo - 1) * pageSize, pageNo * pageSize - 1));
            }
        }
        return new Page<>(list, pageNo, pageSize, size);
    }
 
    /**
     * 从有序集合中获取数据
     *
     * @param setName
     * @param isAsc
     * @return
     */
    public Set<String> getZSetList(String setName, boolean isAsc) {
        String key = getKey(setName);
        Long size = stringRedisTemplate.opsForZSet().size(key);
        if (isAsc) {
            return stringRedisTemplate.opsForZSet().range(key, 0, size);
        } else {
            return stringRedisTemplate.opsForZSet().reverseRange(key, 0, size);
        }
    }
 
    /**
     * 设置Lru,最后进来的排最前面
     * @param setName
     * @param value
     * @param max
     * @param exceed 可允许超出范围,清理缓存区。
     */
    public void putZSetLru(String setName, String value, int max, int exceed) {
        String key = getKey(setName);
        Long size = stringRedisTemplate.opsForZSet().size(key);
        if (size > max + exceed - 1) {
            //超过了。淘汰了
            stringRedisTemplate.opsForZSet().removeRange(key, size - exceed, size);
        }
        stringRedisTemplate.opsForZSet().add(key, value, -System.currentTimeMillis());
    }
 
    /**
     * 增加ZSet分数
     * @param setName
     * @param value
     * @param delta
     */
    public Double incZSetSource(String setName, String value, double delta) {
        return stringRedisTemplate.opsForZSet().incrementScore(getKey(setName), value, delta);
    }
 
    /**
     * 获取前N个
     * @param setName
     * @param n
     * @return
     */
    public Set<String> getZSetLruTopN(String setName, int n) {
        return stringRedisTemplate.opsForZSet().range(getKey(setName), 0 , n);
    }
 
 
    /**
     * TODO 保证原子性问题
     * 向一个set中添加数据
     * @param key
     * @param member
     * @param expireSec
     */
    public void putSetRaw(String key, String member, Integer expireSec) {
        stringRedisTemplate.opsForSet().add(getKey(key), member);
        stringRedisTemplate.expire(getKey(key), expireSec, TimeUnit.SECONDS);
    }
 
    /**
     * TODO 保证原子性问题
     * @param key
     * @param set
     * @param expireSec
     */
    public void putSetRawAll(String key, String[] set, Integer expireSec) {
        stringRedisTemplate.opsForSet().add(getKey(key), set);
        stringRedisTemplate.expire(getKey(key), expireSec, TimeUnit.SECONDS);
    }
 
    public void removeSetRaw(String key, String member) {
        stringRedisTemplate.opsForSet().remove(getKey(key), member);
    }
 
    public boolean isSetMember(String key, String member) {
        return stringRedisTemplate.opsForSet().isMember(getKey(key), member);
    }
 
 
    /**
     * 删除键 / 桶 / hash 表等
     *
     * @param key
     */
    public void del(String key) {
        stringRedisTemplate.delete(getKey(key));
    }
 
    /**
     * 判断是否包含键
     *
     * @param key
     * @return
     */
    public boolean hasKey(String key) {
        return stringRedisTemplate.hasKey(getKey(key));
    }
 
 
    /**
     * 获取指定前缀的Key
     *
     * @param prefix
     * @return
     */
    public Set<String> getPrefixKeySet(String prefix) {
        return stringRedisTemplate.keys(getKey(prefix) + "*");
    }
 
    public void delPrefixKey(String prefix) {
        Set<String> prefixKeySet = getPrefixKeySet(prefix);
        for (String key : prefixKeySet) {
            stringRedisTemplate.delete(key);
        }
    }
 
    /**
     * 获取redis中键的过期时间
     * 返回秒
     * @param key
     * @return
     */
    public Long getKeyExpire(String key){
        return stringRedisTemplate.getExpire(getKey(key));
    }
 
    /**
     * 获取键 前置处理
     * @param key
     * @return
     */
    public String getKey(String key) {
        if (beforeGetCacheKey != null) {
            return beforeGetCacheKey.getKey(key);
        }
        return key;
    }
 
    public Collection<String> getKeys(Collection<String> keys) {
        if (beforeGetCacheKey != null) {
            return keys.stream().map(item -> {
                return beforeGetCacheKey.getKey(item);
            }).collect(Collectors.toList());
        }
        return keys;
    }
 
    /**
     * 获取缓存上下文
     * @return
     */
    public CacheContext getCacheContext() {
        CacheContext cacheContext = this.contextThreadLocal.get();
        if (cacheContext == null) {
            cacheContext = new CacheContext();
            this.contextThreadLocal.set(cacheContext);
        }
        return cacheContext;
    }
 
}