實現代碼
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.Codec;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;@Slf4j
@Component
public class RedissonDataUtils {private static RedissonClient redissonClient;@Autowiredpublic void setRedissonClient(RedissonClient client) {RedissonDataUtils.redissonClient = client;}private static boolean clientReady() {if (redissonClient == null) {log.error("[RedissonDataUtils] RedissonClient 未注入,無法執行Redis操作");return false;}return true;}public static <T> T getOrDefault(String key, Class<T> type, T defaultValue) {return get(key, type, null).orElse(defaultValue);}public static <T> T getOrDefault(String key, Class<T> type, T defaultValue, Codec codec) {return get(key, type, codec).orElse(defaultValue);}public static <T> T getOrDefaultSupplier(String key, Class<T> type, Supplier<T> defaultSupplier) {return get(key, type, null).orElseGet(defaultSupplier);}public static <T> T getOrDefaultSupplier(String key, Class<T> type, Supplier<T> defaultSupplier, Codec codec) {return get(key, type, codec).orElseGet(defaultSupplier);}public static <T> Optional<T> get(String key, Class<T> type, Codec codec) {if (StrUtil.isBlank(key) || ObjectUtil.isNull(type)) {return Optional.empty();}if (!clientReady()) {return Optional.empty();}try {RBucket<Object> bucket;if (codec != null) {bucket = redissonClient.getBucket(key, codec);} else {bucket = redissonClient.getBucket(key);}Object cacheVal = bucket.get();if (cacheVal == null) {return Optional.empty();}T parsed = tryParse(cacheVal, type);return Optional.ofNullable(parsed);} catch (Exception e) {log.error("[RedissonDataUtils] 獲取并解析緩存異常, key={}, type={}, error:", key, type.getSimpleName(), e);return Optional.empty();}}public static <T> List<T> getList(String key, Class<T> elementType) {return getList(key, elementType, null);}public static <T> List<T> getList(String key, Class<T> elementType, Codec codec) {if (StrUtil.isBlank(key) || ObjectUtil.isNull(elementType)) {return Collections.emptyList();}if (!clientReady()) {return Collections.emptyList();}try {RBucket<Object> bucket;if (codec != null) {bucket = redissonClient.getBucket(key, codec);} else {bucket = redissonClient.getBucket(key);}Object cacheVal = bucket.get();if (cacheVal == null) {return Collections.emptyList();}if (cacheVal instanceof List) {try {@SuppressWarnings("unchecked")List<T> list = (List<T>) cacheVal;return CollUtil.isEmpty(list) ? Collections.emptyList() : list;} catch (ClassCastException ex) {}}if (cacheVal instanceof String) {String json = (String) cacheVal;if (StrUtil.isBlank(json)) {return Collections.emptyList();}List<T> list = JSON.parseObject(json, new TypeReference<List<T>>() {});return CollUtil.isEmpty(list) ? Collections.emptyList() : list;}String json = JSON.toJSONString(cacheVal);List<T> list = JSON.parseObject(json, new TypeReference<List<T>>() {});return CollUtil.isEmpty(list) ? Collections.emptyList() : list;} catch (Exception e) {log.error("[RedissonDataUtils] 獲取并解析列表緩存異常, key={}, elementType={}", key, elementType.getSimpleName(), e);return Collections.emptyList();}}public static <T> T getOrLoad(String key, Class<T> type, Supplier<T> loader, long ttlSeconds, Codec codec) {Optional<T> cached = get(key, type, codec);if (cached.isPresent()) {return cached.get();}if (!clientReady()) {try {return loader == null ? null : loader.get();} catch (Exception e) {log.error("[RedissonDataUtils] 回源加載異常(客戶端未就緒), key={}, type={}", key, type == null ? "null" : type.getSimpleName(), e);return null;}}T loaded;try {loaded = loader == null ? null : loader.get();} catch (Exception e) {log.error("[RedissonDataUtils] 回源加載異常, key={}, type={}", key, type == null ? "null" : type.getSimpleName(), e);return null;}if (loaded == null) {return null;}try {set(key, loaded, ttlSeconds, codec);} catch (Exception e) {log.warn("[RedissonDataUtils] 寫入緩存失敗(忽略), key={}", key, e);}return loaded;}public static void set(String key, Object value, long ttlSeconds, Codec codec) {if (StrUtil.isBlank(key)) {return;}if (!clientReady()) {return;}try {RBucket<Object> bucket;if (codec != null) {bucket = redissonClient.getBucket(key, codec);} else {bucket = redissonClient.getBucket(key);}if (ttlSeconds > 0) {bucket.set(value, ttlSeconds, TimeUnit.SECONDS);} else {bucket.set(value);}} catch (Exception e) {log.error("[RedissonDataUtils] 寫入緩存異常, key={}", key, e);}}private static <T> T tryParse(Object cacheVal, Class<T> type) {if (cacheVal == null) {return null;}if (type.isInstance(cacheVal)) {return type.cast(cacheVal);}if (cacheVal instanceof String) {String json = (String) cacheVal;if (StrUtil.isBlank(json)) {return null;}return JSON.parseObject(json, type);}String json = JSON.toJSONString(cacheVal);return JSON.parseObject(json, type);}
}
使用示例
InfoVo info = RedissonDataUtils.getOrDefault("employee:1001", InfoVo.class, new InfoVo("默認員工", "默認部門")
);
InfoVo Info = RedissonDataUtils.getOrDefault("employee:1001", InfoVo.class, () -> {InfoVo defaultVo = new InfoVo();defaultVo.setName("系統生成員工");defaultVo.setDepartment("技術部");defaultVo.setCreateTime(new Date());return defaultVo;}
);
Integer userScore = RedissonDataUtils.getOrDefault("user:score:1001", Integer.class, 0
);
String userName = RedissonDataUtils.getOrDefault("user:name:1001", String.class, "匿名用戶"
);
Optional<InfoVo> empOpt = RedissonDataUtils.get(rKey, InfoVo.class);
List<InfoVo> list = RedissonDataUtils.getList(rKey, InfoVo.class);
InfoVo vo = RedissonDataUtils.getOrLoad(rKey,InfoVo.class,() -> ucService.loadVo(req.getInfoId()),1800L
);
RedissonDataUtils.set(rKey, infoVo, 1800L);