package com.imyeyu.spring.util; import com.imyeyu.java.TimiJava; import com.imyeyu.java.bean.timi.TimiException; import com.imyeyu.spring.config.AbstractRedisConfig; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ScanOptions; import org.springframework.data.redis.serializer.RedisSerializer; import java.time.Duration; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; /** * RedisTemplate 功能封装,简化 Redis 操作 *

serializer 为该 RedisTemplate 的键的序列化操作,序列化解析器由 {@link AbstractRedisConfig} 提供 * * @param 键类型 * @param 值类型 * @author 夜雨 * @version 2021-11-21 09:58 */ @Data @NoArgsConstructor @AllArgsConstructor public class Redis { private RedisTemplate redis; private RedisSerializer serializer; /** * 加锁 * * @param key 键 * @param value 值 * @param timeoutMS 超时时间毫秒 * @return true 为加锁成功 */ public boolean lock(K key, V value, long timeoutMS) { Boolean lock = redis.opsForValue().setIfAbsent(key, value, timeoutMS, TimeUnit.MILLISECONDS); return lock != null && lock; } /** * 释放锁 * * @param key 键 */ public void releaseLock(K key) { destroy(key); } /** * 设置存活时间 * * @param key 键 * @param ms 毫秒 TTL */ public void setExpire(K key, long ms) { redis.expire(key, Duration.ofMillis(ms)); } /** * 获取该数据 TTL * * @param key 键 * @return 毫秒 TTL */ public long getExpire(K key) { return Objects.requireNonNullElse(redis.getExpire(key, TimeUnit.MILLISECONDS), -1L); } /** * 设置数据并保持 TTL * * @param key 键 * @param value 值 */ public void setAndKeepTTL(K key, V value) { long expire = redis.getExpire(key, TimeUnit.MILLISECONDS); if (expire <= 0) { // 判死 destroy(key); } else { redis.opsForValue().set(key, value, Duration.ofMillis(expire)); } } /** * 设置数据 * * @param key 键 * @param value 值 * @param ms 毫秒 TTL */ public void set(K key, V value, long ms) { redis.opsForValue().set(key, value, Duration.ofMillis(ms)); } /** * 获取值 * * @param key 键 * @return 值 */ public V get(K key) { return redis.opsForValue().get(key); } /** * 获取值,强转为 String * * @param key 键 * @return 值 */ public String getString(K key) { return get(key).toString(); } /** * 获取值,强转为 Boolean * * @param key 键 * @return 值 */ public Boolean is(K key) { return Boolean.parseBoolean(getString(key)); } /** * 获取值,强转为 Boolean 并取反 * * @param key 键 * @return 值 */ public Boolean not(K key) { return !is(key); } /** * 是否存在 * * @param key 键 * @return true 为存在 */ public boolean has(K key) { return get(key) != null; } /** * 对列表添加值 * * @param key 键 * @param value 值 */ public void add(K key, V value) { redis.opsForList().leftPush(key, value); } /** * 对列表批量添加值 * * @param key 键 * @param values 值 */ @SafeVarargs public final void addAll(K key, V... values) { redis.opsForList().leftPushAll(key, values); } /** * 获取为列表 * * @param key 键 * @return 列表 */ public List getList(K key) { return redis.opsForList().range(key, 0, -1); } /** * 获取所有数据列表 * * @return 所有数据列表 */ public Map> getAllList() { Map> r = new HashMap<>(); List ks = keys("*"); for (K k : ks) { r.put(k, getList(k)); } return r; } /** * 值为列表时查找是否存在某值 * * @param key 键 * @param value 值 * @return true 为存在 */ public boolean contains(K key, V value) { return getList(key).contains(value); } /** * 获取所有值 * * @return 所有值 * @throws TimiException 异常 */ public List values() { List r = new ArrayList<>(); List ks = keys("*"); for (K k : ks) { r.add(get(k)); } return r; } /** * 获取所有数据(包括键) * * @return 所有数据(包括键) */ public Map map() { Map r = new HashMap<>(); List ks = keys("*"); for (K k : ks) { r.put(k, get(k)); } return r; } /** * 获取符合条件的 key * * @param pattern 表达式 * @return keys */ public List keys(String pattern) { List keys = new ArrayList<>(); scan(pattern, item -> { if (item != null) { keys.add(serializer.deserialize(item)); } }); return keys; } /** * 销毁对象 * * @param key 键 * @return true 为成功 */ public boolean destroy(K key) { if (TimiJava.isNotEmpty(key) && has(key)) { return redis.delete(key); } return false; } /** 删库 */ public void flushAll() { Objects.requireNonNull(redis.getConnectionFactory()).getConnection().serverCommands().flushAll(); } /** * scan 实现 * * @param pattern 表达式 * @param consumer 对迭代到的 key 进行操作 */ private void scan(String pattern, Consumer consumer) { redis.execute((RedisConnection connection) -> { try (Cursor cursor = connection.keyCommands().scan(ScanOptions.scanOptions().count(Long.MAX_VALUE).match(pattern).build())) { cursor.forEachRemaining(consumer); return null; } }); } }