redis 设置

parent 2a8e9ba8
......@@ -41,14 +41,21 @@
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>${dynamic-datasource.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.33</version>
</dependency>
<!-- 代码生成器 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 模板引擎 -->
<dependency>
<groupId>org.apache.velocity</groupId>
......
package com.aps.common.util.redis;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Import;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.connection.ReturnType;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* Redis分布式锁
*
* @author Administrator
*/
@Slf4j
@Component
@Import(RedisUtils.class)
public class RedisLockUtil {
public RedisLockUtil(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
private RedisTemplate<String, Object> redisTemplate;
private static final byte[] SCRIPT_RELEASE_LOCK = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end".getBytes();
/**
* 尝试获取分布式锁
*
* @param key 键
* @param requestId 请求ID
* @param expire 锁的有效时间(秒)
*/
public Boolean tryLock(String key, String requestId, long expire) {
return redisTemplate.execute((RedisCallback<Boolean>) redisConnection -> redisConnection.set(key.getBytes(), requestId.getBytes(), Expiration.from(expire, TimeUnit.SECONDS), RedisStringCommands.SetOption.SET_IF_ABSENT));
}
/**
* 释放分布式锁
*
* @param key 键
* @param requestId 请求ID
*/
public Boolean releaseLock(String key, String requestId) {
return redisTemplate.execute((RedisCallback<Boolean>) redisConnection -> redisConnection.eval(SCRIPT_RELEASE_LOCK, ReturnType.BOOLEAN, 1, key.getBytes(), requestId.getBytes()));
}
}
\ No newline at end of file
package com.aps.common.util.redis;
import com.alibaba.fastjson2.JSONObject;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.TimeoutUtils;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationUtils;
import org.springframework.util.Assert;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* 或者使用${@link RedisUtils#setPrefix(String)} 设置统一的key前缀
* 1. Key的命名应该具有可读性,方便开发者理解和维护。可以使用类似于命名空间的方式,将相关的key放在同一个前缀下,例如"user:id"和"order:id"。
* <p>
* 2. Key的命名应该尽量简短,以减少内存占用和提高查询效率。
* <p>
* 3. Key的命名应该避免使用特殊字符和空格,可以使用下划线或者破折号代替。
* <p>
* 4. Key的命名应该避免使用过于具体的词汇,例如"order:2021-01-01:customer:123",应该改为"order:123",并将日期信息存储在其他字段中。
*
* @author guojing
*/
@Slf4j
public class RedisUtils {
@Autowired
@SuppressWarnings("all")
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private RedisLockUtil redisLockUtil;
/**
* 所有key的前缀
*/
@Getter
public static String prefix = "aps:";
/**
* 设置redis前缀进行操作
*
* @param prefix
*/
public static void setPrefix(String prefix) {
RedisUtils.prefix = prefix;
}
/**
* 判断是否有这个缓存key
*
* @param key 缓存key
* @author: guojing
* @return: boolean
*/
public boolean exists(final String key) {
return redisTemplate.hasKey(prefix + key);
}
public Set<String> keys(final String pattern) {
return redisTemplate.keys(prefix + pattern);
}
/**
* 指定缓存失效时间
*
* @param key 键
* @param time 时间(秒)
* @return Boolean
*/
public void expire(String key, int time, TimeUnit timeUnit) {
redisTemplate.expire(prefix + key, time, timeUnit);
}
public Boolean expire(String key, Long time) {
try {
if (time > 0) {
redisTemplate.expire(prefix + key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return false;
}
}
/**
* 添加到带有 过期时间的 缓存
*
* @param key redis主键
* @param value 值
* @param time 过期时间
* @param timeUnit 过期时间单位
*/
public void setExpire(final String key, final Object value, final long time, final TimeUnit timeUnit) {
redisTemplate.opsForValue().set(prefix + key, value, time, timeUnit);
}
public void setExpire(final String key, final Object value, final long time, final TimeUnit timeUnit, RedisSerializer<Object> valueSerializer) {
byte[] rawKey = rawKey(prefix + key);
byte[] rawValue = rawValue(value, valueSerializer);
redisTemplate.execute(new RedisCallback<Object>() {
@Override
public Object doInRedis(RedisConnection connection) throws DataAccessException {
potentiallyUsePsetEx(connection);
return null;
}
public void potentiallyUsePsetEx(RedisConnection connection) {
if (!TimeUnit.MILLISECONDS.equals(timeUnit) || !failsafeInvokePsetEx(connection)) {
connection.setEx(rawKey, TimeoutUtils.toSeconds(time, timeUnit), rawValue);
}
}
private boolean failsafeInvokePsetEx(RedisConnection connection) {
boolean failed = false;
try {
connection.pSetEx(rawKey, time, rawValue);
} catch (UnsupportedOperationException e) {
failed = true;
}
return !failed;
}
}, true);
}
/**
* 根据key获取过期时间
*
* @param key 键 不能为 null
* @return 时间(秒) 返回 0代表为永久有效
*/
public Long getExpire(String key) {
return redisTemplate.getExpire(prefix + key, TimeUnit.SECONDS);
}
/**
* 判断 key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public Boolean hasKey(String key) {
try {
return redisTemplate.hasKey(prefix + key);
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return false;
}
}
/**
* 删除缓存
*
* @param key 可以传一个值 或多个
*/
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(prefix + key[0]);
} else {
redisTemplate.delete(Arrays.asList(key).stream().map(e -> prefix + e).collect(Collectors.toList()));
}
}
}
public void del(Collection<String> keys) {
redisTemplate.delete(keys.stream().map(e -> prefix + e).collect(Collectors.toList()));
}
/**
* 普通缓存获取
*
* @param key 键
* @return 值
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(prefix + key);
}
/**
* 根据key获取对象
*
* @param key the key
* @param valueSerializer 序列化
* @return the string
*/
public Object get(final String key, RedisSerializer<Object> valueSerializer) {
byte[] rawKey = rawKey(prefix + key);
return redisTemplate.execute(connection -> deserializeValue(connection.get(rawKey), valueSerializer), true);
}
/**
* 普通缓存放入
*
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public Boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(prefix + key, value);
return true;
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return false;
}
}
/**
* 普通缓存放入并设置时间
*
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
* @return true成功 false 失败
*/
public Boolean set(String key, Object value, Long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(prefix + key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return false;
}
}
/**
* 普通缓存放入并设置时间
*
* @param key 键
* @param value 值
* @return true成功 false 失败
*/
public Boolean set(String key, Object value, Duration timeout) {
try {
Assert.notNull(timeout, "Timeout must not be null!");
if (TimeoutUtils.hasMillis(timeout)) {
redisTemplate.opsForValue().set(prefix + key, value, timeout.toMillis(), TimeUnit.MILLISECONDS);
} else {
redisTemplate.opsForValue().set(prefix + key, value, timeout.getSeconds(), TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return false;
}
}
/**
* 递增
*
* @param key 键
* @param delta 要增加几(大于0)
* @return Long
*/
public Long incr(String key, Long delta) {
return redisTemplate.opsForValue().increment(prefix + key, delta);
}
/**
* 递减
*
* @param key 键
* @param delta 要减少几(小于0)
* @return Long
*/
public Long decr(String key, Long delta) {
return redisTemplate.opsForValue().increment(prefix + key, -delta);
}
/**
* HashGet
*
* @param key 键 不能为 null
* @param item 项 不能为 null
* @return 值
*/
public Object hget(String key, String item) {
return redisTemplate.opsForHash().get(prefix + key, item);
}
/**
* 获取 hashKey对应的所有键值
*
* @param key 键
* @return 对应的多个键值
*/
public Map<Object, Object> hmget(String key) {
return redisTemplate.opsForHash().entries(prefix + key);
}
/**
* HashSet
*
* @param key 键
* @param map 对应多个键值
* @return true 成功 false 失败
*/
public Boolean hmset(String key, Map<String, Object> map) {
try {
redisTemplate.opsForHash().putAll(prefix + key, map);
return true;
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return false;
}
}
/**
* HashSet 并设置时间
*
* @param key 键
* @param map 对应多个键值
* @param time 时间(秒)
* @return true成功 false失败
*/
public Boolean hmset(String key, Map<String, Object> map, Long time) {
try {
redisTemplate.opsForHash().putAll(prefix + key, map);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @return true 成功 false失败
*/
public Boolean hset(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(prefix + key, item, value);
return true;
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true 成功 false失败
*/
public Boolean hset(String key, String item, Object value, Long time) {
try {
redisTemplate.opsForHash().put(prefix + key, item, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return false;
}
}
/**
* 删除hash表中的值
*
* @param key 键 不能为 null
* @param item 项 可以使多个不能为 null
*/
public void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(prefix + key, item);
}
/**
* 判断hash表中是否有该项的值
*
* @param key 键 不能为 null
* @param item 项 不能为 null
* @return true 存在 false不存在
*/
public Boolean hHasKey(String key, String item) {
return redisTemplate.opsForHash().hasKey(prefix + key, item);
}
/**
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
*
* @param key 键
* @param item 项
* @param by 要增加几(大于0)
* @return Double
*/
public Double hincr(String key, String item, Double by) {
return redisTemplate.opsForHash().increment(prefix + key, item, by);
}
/**
* hash递减
*
* @param key 键
* @param item 项
* @param by 要减少记(小于0)
* @return Double
*/
public Double hdecr(String key, String item, Double by) {
return redisTemplate.opsForHash().increment(prefix + key, item, -by);
}
/**
* 根据 key获取 Set中的所有值
*
* @param key 键
* @return Set
*/
public Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(prefix + key);
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return null;
}
}
/**
* 根据value从一个set中查询,是否存在
*
* @param key 键
* @param value 值
* @return true 存在 false不存在
*/
public Boolean sHasKey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(prefix + key, value);
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return false;
}
}
/**
* 将数据放入set缓存
*
* @param key 键
* @param values 值 可以是多个
* @return 成功个数
*/
public Long sSet(String key, Object... values) {
try {
return redisTemplate.opsForSet().add(prefix + key, values);
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return 0L;
}
}
/**
* 将set数据放入缓存
*
* @param key 键
* @param time 时间(秒)
* @param values 值 可以是多个
* @return 成功个数
*/
public Long sSetAndTime(String key, Long time, Object... values) {
try {
Long count = redisTemplate.opsForSet().add(prefix + key, values);
if (time > 0) {
expire(key, time);
}
return count;
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return 0L;
}
}
/**
* 获取set缓存的长度
*
* @param key 键
* @return Long
*/
public Long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(prefix + key);
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return 0L;
}
}
/**
* 移除值为value的
*
* @param key 键
* @param values 值 可以是多个
* @return 移除的个数
*/
public Long setRemove(String key, Object... values) {
try {
return redisTemplate.opsForSet().remove(prefix + key, values);
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return 0L;
}
}
/**
* 获取list缓存的内容
*
* @param key 键
* @param start 开始
* @param end 结束 0 到 -1代表所有值
* @return List
*/
public List<Object> lGet(String key, int start, int end) {
try {
return redisTemplate.opsForList().range(prefix + key, start, end);
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return null;
}
}
/**
* 获取list缓存的长度
*
* @param key 键
* @return Long
*/
public Long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(prefix + key);
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return 0L;
}
}
/**
* 通过索引 获取list中的值
*
* @param key 键
* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;
* index<0时,-1,表尾,-2倒数第二个元素,依次类推
* @return Object
*/
public Object lGetIndex(String key, Long index) {
try {
return redisTemplate.opsForList().index(prefix + key, index);
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return null;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @return Boolean
*/
public Boolean lSet(String key, Object value) {
try {
redisTemplate.opsForSet().add(prefix + key, value);
return true;
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return Boolean
*/
public Boolean lSet(String key, Object value, Long time) {
try {
redisTemplate.opsForSet().add(prefix + key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return false;
}
}
/**
* 往list头部插入值
*
* @param key 键
* @param value 值
* @return Boolean
*/
public Boolean lSetList(String key, Object value) {
try {
redisTemplate.opsForList().leftPush(prefix + key, value);
return true;
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return false;
}
}
/**
* 往list尾部插入值
*
* @param key 键
* @param value 值
* @return Boolean
*/
public Boolean lSetListRight(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(prefix + key, value);
return true;
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return false;
}
}
public List<Object> getSetList(String key) {
try {
return redisTemplate.opsForList().range(prefix + key, 0, -1);
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return new ArrayList<>();
}
}
public List<Object> getSetList(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(prefix + key, start, end);
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return new ArrayList<>();
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @return Boolean
*/
public Boolean lSetList(String key, List<Object> value) {
try {
redisTemplate.opsForList().rightPushAll(prefix + key, value);
return true;
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return Boolean
*/
public Boolean lSet(String key, List<Object> value, Long time) {
try {
redisTemplate.opsForList().rightPushAll(prefix + key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return false;
}
}
/**
* 根据索引修改list中的某条数据
*
* @param key 键
* @param index 索引
* @param value 值
* @return Boolean
*/
public Boolean lUpdateIndex(String key, Long index, Object value) {
try {
redisTemplate.opsForList().set(prefix + key, index, value);
return true;
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return false;
}
}
/**
* 移除N个值为value
*
* @param key 键
* @param count 移除多少个
* @param value 值
* @return 移除的个数
*/
public Long lRemove(String key, Long count, Object value) {
try {
return redisTemplate.opsForList().remove(prefix + key, count, value);
} catch (Exception e) {
log.error("Exception: {}", e.getMessage());
return 0L;
}
}
/**
* redis List数据结构 : 返回列表 key 中指定区间内的元素,区间以偏移量 start 和 end 指定。
*
* @param key the key
* @param start the start
* @param end the end
* @param valueSerializer 序列化
* @return the list
*/
public List<Object> getList(String key, int start, int end, RedisSerializer<Object> valueSerializer) {
byte[] rawKey = rawKey(prefix + key);
return redisTemplate.execute(connection -> deserializeValues(connection.lRange(rawKey, start, end), valueSerializer), true);
}
private byte[] rawKey(Object key) {
Assert.notNull(key, "non null key required");
if (key instanceof byte[]) {
return (byte[]) key;
}
RedisSerializer<Object> redisSerializer = (RedisSerializer<Object>) redisTemplate.getKeySerializer();
return redisSerializer.serialize(key);
}
private byte[] rawValue(Object value, RedisSerializer valueSerializer) {
if (value instanceof byte[]) {
return (byte[]) value;
}
return valueSerializer.serialize(value);
}
private List deserializeValues(List<byte[]> rawValues, RedisSerializer<Object> valueSerializer) {
if (valueSerializer == null) {
return rawValues;
}
return SerializationUtils.deserialize(rawValues, valueSerializer);
}
private Object deserializeValue(byte[] value, RedisSerializer<Object> valueSerializer) {
if (valueSerializer == null) {
return value;
}
return valueSerializer.deserialize(value);
}
public void publish(String channal, Object obj) {
redisTemplate.convertAndSend(channal, JSONObject.toJSONString(obj));
}
public void publish(String channal, String obj) {
redisTemplate.convertAndSend(channal, obj);
}
/**
* 分布式锁
*
* @param key 分布式锁key
* @param expireTime 持有锁的最长时间 (redis过期时间) 秒为单位
* @return 返回获取锁状态 成功失败
*/
public boolean tryLock(String key, int expireTime) {
final JSONObject lock = new JSONObject();
lock.put("id", key);
// startTime
lock.put("st", System.currentTimeMillis());
// keepSeconds
lock.put("ks", expireTime);
return redisLockUtil.tryLock(prefix + key, "", expireTime);
}
public void unLock(String key) {
redisLockUtil.releaseLock(prefix + key, "");
}
}
package com.aps.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* Redis基础配置类
*
* @author pangu
*/
@Configuration
@Lazy(value = false)
@EnableCaching
public class RedisConfiguration {
@Bean
@ConditionalOnMissingBean
public RedisSerializer<String> redisKeySerializer() {
return new Jackson2JsonRedisSerializer(String.class);
}
@Bean
@ConditionalOnMissingBean
public RedisSerializer<Object> redisValueSerializer() {
return new Jackson2JsonRedisSerializer(Object.class);
}
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
RedisTemplate template = new RedisTemplate();
//LettuceConnectionFactory
template.setConnectionFactory(factory);
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.activateDefaultTyping(om.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
......@@ -9,7 +9,12 @@ spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher # Spring Boot 2.6+ 需要这个配置
redis:
host: 192.168.0.181
port: 6380
timeout: 10000
database: 10
password: redis@228!
# Swagger 配置
doc:
swagger-ui:
......
package com.aps.demo;
import com.aps.common.util.redis.RedisUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.*;
import java.util.concurrent.TimeUnit;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
public class RedisUtilsTest {
@Autowired
private RedisUtils redisUtils;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@BeforeEach
void setUp() {
// 清理可能存在的测试数据
Set<String> keys = redisTemplate.keys("jvs:test:*");
if (keys != null && !keys.isEmpty()) {
redisTemplate.delete(keys);
}
}
@Test
public void testSetAndGet() {
String key = "test:setAndGet";
String value = "testValue";
// 测试设置值
Boolean setResult = redisUtils.set(key, value);
assertTrue(setResult, "设置值应该成功");
// 测试获取值
Object getResult = redisUtils.get(key);
assertEquals(value, getResult, "获取的值应该与设置的值相同");
System.out.println("获取的值:" + getResult);
}
@Test
public void testSetWithExpire() {
String key = "test:setWithExpire";
String value = "testValue";
Long expireTime = 5L;
// 测试设置带过期时间的值
Boolean setResult = redisUtils.set(key, value, expireTime);
assertTrue(setResult, "设置带过期时间的值应该成功");
// 验证值存在
Object getResult = redisUtils.get(key);
assertEquals(value, getResult, "获取的值应该与设置的值相同");
// 验证过期时间
Long ttl = redisUtils.getExpire(key);
assertTrue(ttl > 0 && ttl <= expireTime, "过期时间应该在预期范围内");
}
@Test
public void testExistsAndHasKey() {
String key = "test:exists";
String value = "testValue";
// 初始状态下key不存在
assertFalse(redisUtils.exists(key), "初始状态下key不应该存在");
assertFalse(redisUtils.hasKey(key), "初始状态下key不应该存在");
// 设置值后key应该存在
redisUtils.set(key, value);
assertTrue(redisUtils.exists(key), "设置值后key应该存在");
assertTrue(redisUtils.hasKey(key), "设置值后key应该存在");
}
@Test
public void testDel() {
String key = "test:del";
String value = "testValue";
// 设置值
redisUtils.set(key, value);
assertTrue(redisUtils.exists(key), "设置值后key应该存在");
// 删除值
redisUtils.del(key);
assertFalse(redisUtils.exists(key), "删除后key不应该存在");
// 测试批量删除
String key1 = "test:del1";
String key2 = "test:del2";
redisUtils.set(key1, value);
redisUtils.set(key2, value);
assertTrue(redisUtils.exists(key1), "设置值后key1应该存在");
assertTrue(redisUtils.exists(key2), "设置值后key2应该存在");
redisUtils.del(key1, key2);
assertFalse(redisUtils.exists(key1), "批量删除后key1不应该存在");
assertFalse(redisUtils.exists(key2), "批量删除后key2不应该存在");
}
@Test
public void testExpire() {
String key = "test:expire";
String value = "testValue";
int expireTime = 10;
redisUtils.set(key, value);
redisUtils.expire(key, expireTime, TimeUnit.SECONDS);
Long ttl = redisUtils.getExpire(key);
assertTrue(ttl > 0 && ttl <= expireTime, "过期时间应该在预期范围内");
}
@Test
public void testKeys() {
String key1 = "test:keys1";
String key2 = "test:keys2";
String value = "testValue";
redisUtils.set(key1, value);
redisUtils.set(key2, value);
Set<String> keys = redisUtils.keys("test:keys*");
assertNotNull(keys, "返回的keys不应该为null");
assertTrue(keys.contains("jvs:test:keys1"), "应该包含key1");
assertTrue(keys.contains("jvs:test:keys2"), "应该包含key2");
}
@Test
public void testIncrAndDecr() {
String key = "test:incrdecr";
Long initialValue = 10L;
Long delta = 5L;
redisUtils.set(key, initialValue);
// 测试递增
Long incrResult = redisUtils.incr(key, delta);
assertEquals(initialValue + delta, incrResult, "递增结果应该正确");
// 测试递减
Long decrResult = redisUtils.decr(key, delta);
assertEquals(initialValue, decrResult, "递减结果应该正确");
}
@Test
public void testHashSetAndGet() {
String key = "test:hash";
String item1 = "item1";
String item2 = "item2";
String value1 = "value1";
String value2 = "value2";
// 测试单个hash设置和获取
Boolean hsetResult = redisUtils.hset(key, item1, value1);
assertTrue(hsetResult, "Hash设置应该成功");
Object hgetResult = redisUtils.hget(key, item1);
assertEquals(value1, hgetResult, "Hash获取的值应该正确");
// 测试多个hash设置和获取
Map<String, Object> map = new HashMap<>();
map.put(item1, value1);
map.put(item2, value2);
Boolean hmsetResult = redisUtils.hmset(key, map);
assertTrue(hmsetResult, "批量Hash设置应该成功");
Map<Object, Object> hmgetResult = redisUtils.hmget(key);
assertNotNull(hmgetResult, "批量Hash获取结果不应该为null");
assertEquals(value1, hmgetResult.get(item1), "Hash获取的值应该正确");
assertEquals(value2, hmgetResult.get(item2), "Hash获取的值应该正确");
// 测试hash是否存在
Boolean hHasKeyResult = redisUtils.hHasKey(key, item1);
assertTrue(hHasKeyResult, "Hash key应该存在");
}
@Test
public void testHashDelAndIncr() {
String key = "test:hashdel";
String item = "item";
String value = "10";
redisUtils.hset(key, item, value);
// 测试hash删除
redisUtils.hdel(key, item);
Boolean hHasKeyResult = redisUtils.hHasKey(key, item);
assertFalse(hHasKeyResult, "删除后Hash key不应该存在");
// 测试hash递增
String incrItem = "incrItem";
Double incrValue = 5.0;
Double hincrResult = redisUtils.hincr(key, incrItem, incrValue);
assertEquals(incrValue, hincrResult, "Hash递增结果应该正确");
// 测试hash递减
Double decrValue = 3.0;
Double hdecrResult = redisUtils.hdecr(key, incrItem, decrValue);
assertEquals(incrValue - decrValue, hdecrResult, "Hash递减结果应该正确");
}
@Test
public void testSetOperations() {
String key = "test:set";
String value1 = "value1";
String value2 = "value2";
// 测试添加set元素
Long sSetResult = redisUtils.sSet(key, value1, value2);
assertEquals(2, sSetResult, "应该成功添加2个元素");
// 测试set大小
Long sGetSizeResult = redisUtils.sGetSetSize(key);
assertEquals(2, sGetSizeResult, "Set大小应该为2");
// 测试元素是否存在于set中
Boolean sHasKeyResult = redisUtils.sHasKey(key, value1);
assertTrue(sHasKeyResult, "value1应该存在于set中");
// 测试获取set所有元素
Set<Object> sGetResult = redisUtils.sGet(key);
assertNotNull(sGetResult, "Set结果不应该为null");
assertTrue(sGetResult.contains(value1), "Set应该包含value1");
assertTrue(sGetResult.contains(value2), "Set应该包含value2");
// 测试从set中移除元素
Long setRemoveResult = redisUtils.setRemove(key, value1);
assertEquals(1, setRemoveResult, "应该成功移除1个元素");
sGetSizeResult = redisUtils.sGetSetSize(key);
assertEquals(1, sGetSizeResult, "移除元素后Set大小应该为1");
}
@Test
public void testListOperations() {
String key = "test:list";
String value1 = "value1";
String value2 = "value2";
String value3 = "value3";
// 测试往list头部插入值
Boolean lSetListResult = redisUtils.lSetList(key, value1);
assertTrue(lSetListResult, "往list头部插入值应该成功");
// 测试往list尾部插入值
Boolean lSetListRightResult = redisUtils.lSetListRight(key, value2);
assertTrue(lSetListRightResult, "往list尾部插入值应该成功");
// 测试获取list长度
Long lGetListSizeResult = redisUtils.lGetListSize(key);
assertEquals(2, lGetListSizeResult, "List长度应该为2");
// 测试通过索引获取list中的值
Object lGetIndexResult = redisUtils.lGetIndex(key, 0L);
assertEquals(value1, lGetIndexResult, "索引0的值应该是value1");
lGetIndexResult = redisUtils.lGetIndex(key, -1L);
assertEquals(value2, lGetIndexResult, "索引-1的值应该是value2");
// 测试获取list缓存内容
List<Object> lGetResult = redisUtils.lGet(key, 0, -1);
assertNotNull(lGetResult, "List结果不应该为null");
assertEquals(2, lGetResult.size(), "List大小应该为2");
assertEquals(value1, lGetResult.get(0), "第一个元素应该是value1");
assertEquals(value2, lGetResult.get(1), "第二个元素应该是value2");
// 测试批量设置list
List<Object> values = Arrays.asList(value1, value2, value3);
Boolean lSetListBatchResult = redisUtils.lSetList(key, values);
assertTrue(lSetListBatchResult, "批量设置list应该成功");
lGetListSizeResult = redisUtils.lGetListSize(key);
assertEquals(3, lGetListSizeResult, "批量设置后List长度应该为3");
// 测试根据索引修改list中的某条数据
String newValue = "newValue";
Boolean lUpdateIndexResult = redisUtils.lUpdateIndex(key, 0L, newValue);
assertTrue(lUpdateIndexResult, "根据索引修改list数据应该成功");
lGetIndexResult = redisUtils.lGetIndex(key, 0L);
assertEquals(newValue, lGetIndexResult, "索引0的值应该被更新");
// 测试移除N个值为value的元素
Long lRemoveResult = redisUtils.lRemove(key, 1L, value2);
assertEquals(1, lRemoveResult, "应该成功移除1个元素");
}
@Test
public void testPrefix() {
String originalPrefix = RedisUtils.getPrefix();
String newPrefix = "test_prefix:";
// 修改前缀
RedisUtils.setPrefix(newPrefix);
assertEquals(newPrefix, RedisUtils.getPrefix(), "前缀应该被正确设置");
// 测试使用新前缀的操作
String key = "test:prefix";
String value = "testValue";
RedisUtils redisUtilsWithoutAutowired = new RedisUtils();
// 恢复原始前缀
RedisUtils.setPrefix(originalPrefix);
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment