依赖:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.10.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.3.0</version>
</dependency>
</dependencies>
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.StringUtils;
/**
* @package: com.xxx.token.service.config
* @author: tiget
* @date: 2020/12/23 15:36
* @description: Redis模板配置类,不同数据库或不同集群自定义设置;enabled.redis不配置,默认启动redis
*/
@Configuration
@Slf4j
@ConditionalOnProperty(name = "enabled.redis", havingValue = "true", matchIfMissing = true)
public class RedisConfig {
@Autowired(required = false)
private CommonRedisProperties redisProperties;
@Bean(name = "COMMON_REDIS_FACTORY")
@Primary
@ConditionalOnProperty(name = "enabled.redis", havingValue = "true", matchIfMissing = true)
public JedisConnectionFactory createCommonJedisConnectionFactory() {
JedisConnectionFactory factory = new JedisConnectionFactory();
if (!StringUtils.isEmpty(redisProperties.getHost())) {
factory.getStandaloneConfiguration().setHostName(redisProperties.getHost());
}
if (!StringUtils.isEmpty(redisProperties.getPassword())) {
factory.getStandaloneConfiguration().setPassword(redisProperties.getPassword());
factory.setPassword(redisProperties.getPassword());
log.info("redis配置password:{}",redisProperties.getPassword());
}
factory.getStandaloneConfiguration().setPort(redisProperties.getPort());
factory.getStandaloneConfiguration().setDatabase(redisProperties.getDatabase());
factory.setTimeout(redisProperties.getTimeout());
factory.getPoolConfig().setMaxIdle(redisProperties.getMaxIdle());
factory.getPoolConfig().setMinIdle(redisProperties.getMinIdle());
factory.getPoolConfig().setMaxTotal(redisProperties.getMaxActive());
factory.getPoolConfig().setMaxWaitMillis(redisProperties.getMaxWait());
return factory;
}
@Bean(name = "commonRedisTemplate")
@ConditionalOnProperty(name = "enabled.redis", havingValue = "true", matchIfMissing = true)
public RedisTemplate<String,Object> appCommonRedisTemplate(@Qualifier("COMMON_REDIS_FACTORY") JedisConnectionFactory factory) {
RedisTemplate<String,Object> redisTemplate = new RedisTemplate();
redisTemplate.setConnectionFactory(factory);
/*使用Jackson2JsonRedisSerialize 替换默认序列化*/
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
//GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
/*设置value的序列化规则和 key的序列化规则*/
redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(stringRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setDefaultSerializer(jackson2JsonRedisSerializer);
redisTemplate.setEnableDefaultSerializer(true);
redisTemplate.afterPropertiesSet();
/*afterPropertiesSetredisTemplate.opsForValue().set(appName + ":uuid:redis:test", new Date().toString());*/
return redisTemplate;
}
}
/**
* @package: com.xxx.app.common.config.redis
* @author: tiger
* @date: 2021/2/1 15:54
* @description: redis
*/
public interface CommonRedisService {
/* *
* @Param: timeout 分钟
*/
public void setValue(String key, Object value, int timeout);
public void setEffectiveTime(String key, final long timeout, final TimeUnit unit);
public void setValue(String key, Object value, long timeout, TimeUnit timeUnit);
public Object getValue(String key);
public void putMap(String key, Map<String, Object> map);
public Map getMap(String key);
public Boolean delKey(String key);
/**
* expireTime 单元秒
*/
boolean getRedisLock(String key, int expireTime);
/**
* expireTime 单元秒
*/
boolean getRedisLock(String key, String value, int expireTime);
boolean releaseLock(String key, String value);
public long listSize(String key);
public List range(String key, long start, long end);
public Object listIndex(String listKey, long index);
public <T> List<Object> msetByPipeline(Map<String, Object> entryMap, Class<T> clazz, long expireTime);
public <T> List<T> mgetByPipeline(List<String> keys, Class<T> valueClazz);
public long leftPushAll(String key, List values);
public long leftPushAll(String key, List values, long expireTime);
public long rightPushAll(String key, List values);
public long rightPushAll(String key, List values, long expireTime);
public void hashPut(String key, String field, Object value);
public Map hashEntries(String key);
public boolean hashDelField(String key, String... field);
public List<String> hashKeys(String key);
public void hashPut(String key, Map<String, Object> value, long expireTime);
public void hashPutList(Map<String, Map<String, Object>> mapList, long expireTime);
public Map<String, Map<String, Object>> getHashList(List<String> keys);
public long hashIncrement(String key, String field, long delta);
public boolean hashIncrement(String key, String field, long delta, long maxCount);
public Object hashGet(String key, String field);
public long removeItemByList(String listKey, Object value);
public long getExpireTime(String key, TimeUnit timeUnit);
public boolean setValueIfAbsent(String key, Object value, long timeout, TimeUnit timeUnit);
public boolean zsetAdd(String key, Object value, double score);
public long zsetRemove(String key, Object object);
public Set<Object> zsetRange(String key, long var2, long var4);
public Set<Object> reverseRange(String key, long var2, long var4);
public Set<Object> reverseRangeByScore(String key, long var2, long var4);
Long increment(String key, Long expireMillis, long incrementStep);
public Double score(String key, Object value);
Double incrementScore(String key, Object value, double score);
Long reverseRank(String key, Object value);
Long rank(String key, Object value);
Long count(Object key, double min, double max);
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
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.serializer.RedisSerializer;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* @package: com.xxx.app.common.config.redis
* @author: tiger
* @date: 2021/2/1 15:54
* @description:
*/
@Component
@ConditionalOnProperty(name = "enabled.redis", havingValue = "true", matchIfMissing = true)
@Slf4j
public class CommonRedisServiceImpl implements CommonRedisService {
@Value("${spring.redis.user.keyTimeout:10080}")
private int userkeyTimeout;
@Value("${spring.redis.code.keyTimeout:5}")
private int keyTimeout;
/**
* 注入redis模板
*/
@Autowired
private RedisTemplate<String, Object> commonRedisTemplate;
@Override
public void setValue(String key, Object requestBody, int timeout) {
if (timeout <= 0) {
timeout = keyTimeout;
}
if (log.isDebugEnabled()) {
log.debug("\n" + "->\n接收到来自用户新建缓存请求:\n[\nkey:{}, \ntimeout:{}\n]\n",
key, timeout);
}
this.commonRedisTemplate.opsForValue().set(key, requestBody, timeout, TimeUnit.MINUTES);
}
@Override
public void setEffectiveTime(String key, long timeout, TimeUnit unit) {
commonRedisTemplate.expire(key, timeout, unit);
}
@Override
public void setValue(String key, Object value, long timeout, TimeUnit timeUnit) {
this.commonRedisTemplate.opsForValue().set(key, value, timeout, timeUnit);
}
@Override
public Object getValue(String key) {
if (log.isDebugEnabled()) {
log.debug("\n" + "->\n接收到来自用户获取缓存请求:\n[\nkey:{}",
key);
}
Object con = (Object) this.commonRedisTemplate.opsForValue().get(key);
return con;
}
@Override
public void putMap(String key, Map<String, Object> map) {
if (log.isDebugEnabled()) {
log.debug("\nputMap:[{}, {}]", key);
}
Map tokenContent = (Map) this.commonRedisTemplate.opsForValue().get(key);
if (tokenContent != null) {
tokenContent.putAll(map);
this.commonRedisTemplate.opsForValue().set(key, tokenContent, userkeyTimeout, TimeUnit.MINUTES);
if (log.isDebugEnabled()) {
log.debug("\nputMap->putAll:[{}, {}]", key, map);
}
} else {
// 这里可能存在并发问题,但缓存覆盖只是操作DB而已,也没啥问题
this.commonRedisTemplate.opsForValue().set(key, map, userkeyTimeout, TimeUnit.MINUTES);
}
}
@Override
public Map getMap(String key) {
if (log.isDebugEnabled()) {
log.debug("\ngetMap:[{}]", key);
}
Map map = (Map) this.commonRedisTemplate.opsForValue().get(key);
return map;
}
@Override
public Boolean delKey(String key) {
if (log.isDebugEnabled()) {
log.debug("\n" + "->\n接收到来自用户删除请求:\n[\nkey:{}", key);
}
Boolean del = this.commonRedisTemplate.delete(key);
return del;
}
@Override
public boolean getRedisLock(String key, int expireTime) {
return getRedisLock(key, UUID.randomUUID().toString(), expireTime);
}
@Override
public boolean getRedisLock(String key, String value, int expireTime) {
String scriptText = "if redis.call('setNx',KEYS[1],ARGV[1]) == 1 then return redis.call('expire',KEYS[1],ARGV[2]) else return 0 end";
List<String> keys = new ArrayList<>();
keys.add(key);
List<String> args = new ArrayList<>();
args.add(value);
args.add(String.valueOf(expireTime));
Long result = (Long) commonRedisTemplate.execute(new RedisCallback<Long>() {
@Override
public Long doInRedis(RedisConnection connection) throws DataAccessException {
Object nativeConnection = connection.getNativeConnection();
// 集群模式和单点模式虽然执行脚本的方法一样,但是没有共同的接口,所以只能分开执行
// 集群
if (nativeConnection instanceof JedisCluster) {
return (Long) ((JedisCluster) nativeConnection).eval(scriptText, keys, args);
}
// 单点
else if (nativeConnection instanceof Jedis) {
return (Long) ((Jedis) nativeConnection).eval(scriptText, keys, args);
}
return null;
}
});
return 1L == result;
}
/**
* 释放锁
*
* @param key
* @param value
* @return
*/
@Override
public boolean releaseLock(String key, String value) {
String scriptText = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
List<String> keys = new ArrayList<>();
keys.add(key);
List<String> args = new ArrayList<>();
args.add(value);
Long result = (Long) commonRedisTemplate.execute(new RedisCallback<Long>() {
@Override
public Long doInRedis(RedisConnection connection) throws DataAccessException {
Object nativeConnection = connection.getNativeConnection();
// 集群模式和单点模式虽然执行脚本的方法一样,但是没有共同的接口,所以只能分开执行
// 集群
if (nativeConnection instanceof JedisCluster) {
return (Long) ((JedisCluster) nativeConnection).eval(scriptText, keys, args);
}
// 单点
else if (nativeConnection instanceof Jedis) {
return (Long) ((Jedis) nativeConnection).eval(scriptText, keys, args);
}
return null;
}
});
return 1L == result;
}
@Override
public long listSize(String key) {
return commonRedisTemplate.opsForList().size(key);
}
@Override
public List range(String key, long start, long end) {
return commonRedisTemplate.opsForList().range(key, start, end);
}
@Override
public Object listIndex(String listKey, long index) {
return commonRedisTemplate.opsForList().index(listKey, index);
}
@Override
public <T> List<Object> msetByPipeline(Map<String, Object> entryMap, Class<T> valueClazz, long expireTime) {
//获取序列化方式
final RedisSerializer keySerializer = commonRedisTemplate.getKeySerializer();
final RedisSerializer valueSerializer = commonRedisTemplate.getValueSerializer();
List<Object> result = (List) commonRedisTemplate.executePipelined(new RedisCallback<T>() {
@Override
public T doInRedis(RedisConnection connection) throws DataAccessException {
for (Map.Entry<String, Object> entry : entryMap.entrySet()) {
byte[] key = keySerializer.serialize(entry.getKey());
connection.set(key, valueSerializer.serialize((T) entry.getValue()));
if (expireTime > 0) connection.pExpire(key, expireTime);
}
return null;
}
});
return result;
}
@Override
public <T> List<T> mgetByPipeline(List<String> keys, Class<T> valueClazz) {
final RedisSerializer keySerializer = commonRedisTemplate.getKeySerializer();
List<T> list = (List) commonRedisTemplate.executePipelined(new RedisCallback<T>() {
@Override
public T doInRedis(RedisConnection connection) throws DataAccessException {
for (String goods : keys) {
connection.get(keySerializer.serialize(goods));
}
return null;
}
});
return list;
}
@Override
public long leftPushAll(String key, List values) {
return commonRedisTemplate.opsForList().leftPushAll(key, values.toArray());
}
@Override
public long leftPushAll(String key, List values, long expireTime) {
long result = leftPushAll(key, values);
setEffectiveTime(key, expireTime, TimeUnit.MILLISECONDS);
return result;
}
@Override
public long rightPushAll(String key, List values) {
return commonRedisTemplate.opsForList().rightPushAll(key, values.toArray());
}
@Override
public long rightPushAll(String key, List values, long expireTime) {
long result = rightPushAll(key, values);
setEffectiveTime(key, expireTime, TimeUnit.MILLISECONDS);
return result;
}
@Override
public void hashPut(String key, String field, Object value) {
commonRedisTemplate.opsForHash().put(key, field, value);
}
@Override
public Map hashEntries(String key) {
return commonRedisTemplate.opsForHash().entries(key);
}
@Override
public boolean hashDelField(String key, String... field) {
return commonRedisTemplate.opsForHash().delete(key, field) > 0;
}
@Override
public List<String> hashKeys(String key) {
return new ArrayList(commonRedisTemplate.opsForHash().keys(key));
}
@Override
public void hashPut(String key, Map<String, Object> value, long expireTime) {
final RedisSerializer keySerializer = commonRedisTemplate.getHashKeySerializer();
final RedisSerializer valueSerializer = commonRedisTemplate.getHashValueSerializer();
commonRedisTemplate.executePipelined(new RedisCallback<Object>() {
@Override
public Object doInRedis(RedisConnection connection) throws DataAccessException {
for (Map.Entry<String, Object> entry : value.entrySet()) {
byte keys[] = keySerializer.serialize(key);
byte fields[] = keySerializer.serialize(entry.getKey());
byte values[] = valueSerializer.serialize(entry.getValue());
connection.hashCommands().hSet(keys, fields, values);
if (expireTime > 0) connection.pExpire(keys, expireTime);
}
return null;
}
});
}
@Override
public void hashPutList(Map<String, Map<String, Object>> mapList, long expireTime) {
for (Map.Entry<String, Map<String, Object>> entry : mapList.entrySet()) {
hashPut(entry.getKey(), entry.getValue(), expireTime);
}
}
@Override
public Map<String, Map<String, Object>> getHashList(List<String> keys) {
Map<String, Map<String, Object>> result = new HashMap<>(keys.size());
for (String key : keys) {
result.put(key, hashEntries(key));
}
return result;
}
@Override
public long hashIncrement(String key, String field, long delta) {
return commonRedisTemplate.opsForHash().increment(key, field, delta);
}
@Override
public boolean hashIncrement(String key, String field, long delta, long maxCount) {
String scriptText = "if tonumber(redis.call('hget',KEYS[1],ARGV[1])) + tonumber(ARGV[2]) < tonumber(ARGV[3]) then return redis.call('hincrby',KEYS[1],ARGV[1],ARGV[2]) else return 0 end";
List<String> keys = new ArrayList<>();
keys.add(key);
List<String> args = new ArrayList<>();
args.add(field);
args.add(String.valueOf(delta));
args.add(String.valueOf(maxCount));
Long result = (Long) commonRedisTemplate.execute(new RedisCallback<Long>() {
@Override
public Long doInRedis(RedisConnection connection) throws DataAccessException {
Object nativeConnection = connection.getNativeConnection();
// 集群模式和单点模式虽然执行脚本的方法一样,但是没有共同的接口,所以只能分开执行
// 集群
if (nativeConnection instanceof JedisCluster) {
return (Long) ((JedisCluster) nativeConnection).eval(scriptText, keys, args);
}
// 单点
else if (nativeConnection instanceof Jedis) {
return (Long) ((Jedis) nativeConnection).eval(scriptText, keys, args);
}
return null;
}
});
return result != 0;
}
@Override
public Object hashGet(String key, String field) {
return commonRedisTemplate.opsForHash().get(key, field);
}
@Override
public long removeItemByList(String listKey, Object value) {
return commonRedisTemplate.opsForList().remove(listKey, 0, value);
}
@Override
public long getExpireTime(String key, TimeUnit timeUnit) {
return commonRedisTemplate.getExpire(key, timeUnit);
}
@Override
public boolean setValueIfAbsent(String key, Object value, long timeout, TimeUnit timeUnit) {
return commonRedisTemplate.opsForValue().setIfAbsent(key, value, timeout, timeUnit);
}
@Override
public boolean zsetAdd(String key, Object value, double score) {
return commonRedisTemplate.opsForZSet().add(key, value, score);
}
@Override
public long zsetRemove(String key, Object object) {
return commonRedisTemplate.opsForZSet().remove(key, object);
}
@Override
public Set<Object> zsetRange(String key, long var2, long var4) {
return commonRedisTemplate.opsForZSet().range(key, var2, var4);
}
@Override
public Set<Object> reverseRange(String key, long var2, long var4) {
return commonRedisTemplate.opsForZSet().reverseRange(key, var2, var4);
}
@Override
public Set<Object> reverseRangeByScore(String key, long var2, long var4) {
return commonRedisTemplate.opsForZSet().reverseRangeByScore(key, var2, var4);
}
@Override
public Long increment(String key, Long expireMillis, long incrementStep) {
Long l = commonRedisTemplate.opsForValue().increment(key, incrementStep);
if (expireMillis != null) {
commonRedisTemplate.expire(key, expireMillis, TimeUnit.SECONDS);
}
return l;
}
@Override
public Double score(String key, Object value) {
return commonRedisTemplate.opsForZSet().score(key, value);
}
@Override
public Double incrementScore(String key, Object value, double score) {
return commonRedisTemplate.opsForZSet().incrementScore(key, value, score);
}
@Override
public Long reverseRank(String key, Object value) {
return commonRedisTemplate.opsForZSet().reverseRank(key, value);
}
@Override
public Long rank(String key, Object value) {
return commonRedisTemplate.opsForZSet().rank(key, value);
}
@Override
public Long count(Object key, double min, double max) {
return commonRedisTemplate.opsForZSet().count(String.valueOf(key) , min,max);
}
}
import lombok.Data;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@ConfigurationProperties(prefix = "spring.redis")
@ConditionalOnProperty(name = "enabled.redis", havingValue = "true", matchIfMissing = true)
@Data
public class CommonRedisProperties {
private int port=6379;
private String host;
private List<String> nodes;
private String password;
private int timeout;
private int database;
private AuthJedis authJedis;
public int minIdle = 8;
public int maxIdle=200;
public long maxWait=1000;
public int maxActive=300;
@Data
public static class AuthJedis{
public int database = 10;
public String host ="r-wz9e94.redis.rds.aliyuncs.com";
public String password = "ufvo8b1QCr";
public int port=6379;
}
}