Spring boot RedisTemplate 序列化服务化配置方式
作者:梦凡尘/n1ら
这篇文章主要介绍了Springboot RedisTemplate序列化服务化配置方式,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
Spring boot RedisTemplate 序列化 服务化配置
一,引入依赖
<!--redis 引入jedis 排除lettuce 解决断线重连问题--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
二、序列化配置
1.因RedisTemplate默认使用的是jdk原生的序列化,但这会导致一些问题,比如数据以Unicode编码格式存储。因此,建议优先使用JSON2的序列化构造器进行序列化。
@Bean public RedisSerializer<Object> redisSerializer() { //创建JSON序列化器 Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.configure(MapperFeature.USE_ANNOTATIONS, false); objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); //解决localDateTime的序列化问题 objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); objectMapper.registerModule(new JavaTimeModule()); objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); //必须设置,否则无法将JSON转化为对象,会转化成Map类型 objectMapper.disableDefaultTyping(); objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); //objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL); serializer.setObjectMapper(objectMapper); return serializer; }
2.然后,我们需要配置RedisCacheManager作为Redis的缓存管理器,并使用上面定义的序列化方法
@Bean public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) { RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory); //设置Redis缓存有效期为1天 RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig() .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer())).entryTtl(Duration.ofDays(1)); return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration); }
3.针对RedisTemplate<String,Object>
,我们可以重新声明一个Bean,并对其进行序列化处理,以实现对Redis的有效操作。为此,我们可以采用Jackson2JsonRedisSerializer来完成序列化,它支持对象的序列化和反序列化,能够轻松实现Redis的存储。
@Bean @ConditionalOnMissingBean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisSerializer<Object> serializer = redisSerializer(); RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(serializer); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(serializer); redisTemplate.afterPropertiesSet(); return redisTemplate; }
三,构建RedisTemplateService
为了能够更好地使用Redis,我们对redisTemplate进行了封装,从而构建出RedisTemplateService,并且实现了泛型化。
public interface RedisTemplateService<T> { /** * 正常的插入 * * @param k k * @param v v * @param time 时间 时间单位秒 */ void set(String k, T v, long time); LinkedHashMap getAndSet(String k, T v, long time); LinkedHashMap getAndSet(String k, T v); /** * 无过期时间的插入 * * @param key * @param value */ void set(String key, T value); /** * 获取值 * * @param key * @return */ T get(String key); /** * 删除值 * * @param key * @return */ Boolean del(String key); /** * 批量删除 * * @param keys * @return */ Long del(List<String> keys); /** * 设置失效时间 * * @param key * @param time * @return */ Boolean expire(String key, long time); /** * 获取过期时间 * * @param key * @return */ Long getExpire(String key); /** * 是否存在key * * @param key * @return */ Boolean hasKey(String key); /** * 以增量的方式将long值存储在变量中 * * @param key * @param delta * @return */ Long incr(String key, long delta); /** * 以减量的方式将long值存储在变量中 * * @param key * @param delta * @return */ Long decr(String key, long delta); /** * 获取变量中的指定map键是否有值,如果存在该map键则获取值,没有则返回null。 * * @param key * @param hashKey * @return */ T hGet(String key, String hashKey); /** * 新增hashMap值 * 设置过期时间 * * @param key * @param hashKey * @param value * @param time * @return */ Boolean hSet(String key, String hashKey, Object value, long time); /** * 新增hashMap值 * * @param key * @param hashKey * @param value */ void hSet(String key, String hashKey, Object value); /** * 获取变量中的键值对 * * @param key * @return */ Map<Object, T> hGetAll(String key); /** * 以map集合的形式添加键值对 * 有过期时间 * * @param key * @param map * @param time * @return */ Boolean hSetAll(String key, Map<String, T> map, long time); /** * 以map集合的形式添加键值对 * * @param key * @param map */ void hSetAll(String key, Map<String, T> map); /** * 删除变量中的键值对,可以传入多个参数,删除多个键值对。 * * @param key * @param hashKey */ Long hDel(String key, T... hashKey); /** * 判断变量中是否有指定的map键。 * * @param key * @param hashKey * @return */ Boolean hHasKey(String key, String hashKey); /** * 延长过期时间 * * @param key * @param hashKey * @param delta * @return */ Long hIncr(String key, String hashKey, Long delta); /** * 减过期时间 * * @param key * @param hashKey * @param delta * @return */ Long hDecr(String key, String hashKey, Long delta); /** * 获取变量中的值。 * * @param key * @return */ Set<T> sMembers(String key); /** * @param key * @param values * @return */ Long sAdd(String key, T... values); /** * 向变量中批量添加值 * 有过期时间 * * @param key * @param time * @param values * @return */ Long sAdd(String key, long time, T... values); /** * 检查给定的元素是否在变量中 * * @param key * @param value * @return */ Boolean sIsMember(String key, T value); /** * 获取变量中值的长度 * * @param key * @return */ Long sSize(String key); /** * 批量移除变量中的元素 * * @param key * @param values * @return */ Long sRemove(String key, T... values); /** * 获取集合区间的值 * * @param key * @param start * @param end * @return */ List<T> lRange(String key, long start, long end); /** * 获取队列个数 * * @param key * @return */ Long lSize(String key); /** * 获取集合中 对应坐标的数据 * * @param key * @param index * @return */ T lIndex(String key, long index); /** * 插入队列首部 单个 * 无过期时间 * * @param key * @param value * @return */ Long lPush(String key, T value); /** * 插入队列首部 (右推单个) * 有过期时间 * * @param key * @param value * @param time * @return */ Long lPush(String key, T value, long time); /** * 从队列首部全部插入(右推全部) * 无过期时间 * * @param key * @param values * @return */ Long lPushAll(String key, T... values); /** * 从队列首部全部插入(右推全部) * 设置过期时间 单位秒 * * @param key * @param time * @param values * @return */ Long lPushAll(String key, Long time, T... values); /** * List 按value值移除,和移除个数 * * @param key * @param count * @param value * @return */ Long lRemove(String key, long count, T value); /** * 分布式锁 默认2分钟 * * @param k * @param l * @param v * @return */ Boolean lock(String k, long l, T v); /** * 分布式锁 默认2分钟 * * @param k * @param v * @return */ Boolean lock(String k, T v); default boolean lock(String k, T v, String errorMsg) { Boolean lock = this.lock(k, v); if (!lock) { throw new BasicException(errorMsg); } return lock; } /** * 分布式锁 设置过期时间的 * * @param k * @param v * @param time * @param unit * @return */ Boolean lock(String k, T v, long time, TimeUnit unit); /** * 死锁(无过期时间的) * * @param k * @param v * @return */ Boolean setIfAbsent(String k, T v); /** * 添加一个元素, zset与set最大的区别就是每个元素都有一个score,因此有个排序的辅助功能; zadd * * @param k * @param v * @param score * @return */ Boolean zadd(String k, T v, double score); /** * 删除元素 zrem * * @param k k * @param v v */ Long zRemove(String k, T v); /** * score的增加or减少 zincrby * * @param key * @param value * @param score */ Double incrScore(String key, T value, double score); /** * 查询value对应的score zscore * * @param key * @param value * @return */ Double score(String key, T value); /** * 判断value在zset中的排名 zrank * * @param key * @param value * @return */ Long rank(String key, T value); /** * 返回集合的长度 * * @param key * @return */ Long size(String key); Set<T> zRange(String key, int start, int end); Set<ZSetOperations.TypedTuple<T>> zRangeWithScore(String key, int start, int end); Set<T> zRevRange(String key, int start, int end); Set<T> zSortRange(String key, int min, int max); /** * 生成编号 * * @param redisKey * @param prefix * @param len * @return */ String createNo(String redisKey, String prefix, int len); }
针对RedisTemplateService进行实现。
public class RedisTemplateServiceImpl<T> implements RedisTemplateService<T> { @Autowired private RedisTemplate<String, T> redisTemplate; @Override public void set(String k, T v, long time) { this.redisTemplate.opsForValue().set(k, v, time, TimeUnit.SECONDS); } @Override public LinkedHashMap getAndSet(String k, T v, long time) { LinkedHashMap t = (LinkedHashMap) this.redisTemplate.opsForValue().getAndSet(k, v); this.expire(k, time); return t; } @Override public LinkedHashMap getAndSet(String k, T v) { return (LinkedHashMap) this.redisTemplate.opsForValue().getAndSet(k, v); } @Override public void set(String key, T value) { this.redisTemplate.opsForValue().set(key, value); } @Override public T get(String key) { return this.redisTemplate.opsForValue().get(key); } @Override public Boolean del(String key) { return this.redisTemplate.delete(key); } @Override public Long del(List<String> keys) { return this.redisTemplate.delete(keys); } @Override public Boolean expire(String key, long time) { return this.redisTemplate.expire(key, time, TimeUnit.SECONDS); } @Override public Long getExpire(String key) { return this.redisTemplate.getExpire(key, TimeUnit.SECONDS); } @Override public Boolean hasKey(String key) { return this.redisTemplate.hasKey(key); } @Override public Long incr(String key, long delta) { return this.redisTemplate.opsForValue().increment(key, delta); } @Override public Long decr(String key, long delta) { return this.redisTemplate.opsForValue().increment(key, -delta); } @Override public T hGet(String key, String hashKey) { return (T) this.redisTemplate.opsForHash().get(key, hashKey); } @Override public Boolean hSet(String key, String hashKey, Object value, long time) { this.redisTemplate.opsForHash().put(key, hashKey, value); return this.expire(key, time); } @Override public void hSet(String key, String hashKey, Object value) { this.redisTemplate.opsForHash().put(key, hashKey, value); } @Override public Map<Object, T> hGetAll(String key) { return (Map<Object, T>) this.redisTemplate.opsForHash().entries(key); } @Override public Boolean hSetAll(String key, Map<String, T> map, long time) { this.redisTemplate.opsForHash().putAll(key, map); return this.expire(key, time); } @Override public void hSetAll(String key, Map<String, T> map) { this.redisTemplate.opsForHash().putAll(key, map); } @Override public Long hDel(String key, T... hashKey) { return this.redisTemplate.opsForHash().delete(key, hashKey); } @Override public Boolean hHasKey(String key, String hashKey) { return this.redisTemplate.opsForHash().hasKey(key, hashKey); } @Override public Long hIncr(String key, String hashKey, Long delta) { return this.redisTemplate.opsForHash().increment(key, hashKey, delta); } @Override public Long hDecr(String key, String hashKey, Long delta) { return this.redisTemplate.opsForHash().increment(key, hashKey, -delta); } @Override public Set<T> sMembers(String key) { return this.redisTemplate.opsForSet().members(key); } @Override public Long sAdd(String key, T... values) { return this.redisTemplate.opsForSet().add(key, values); } @Override public Long sAdd(String key, long time, T... values) { Long count = this.redisTemplate.opsForSet().add(key, values); this.expire(key, time); return count; } @Override public Boolean sIsMember(String key, T value) { return this.redisTemplate.opsForSet().isMember(key, value); } @Override public Long sSize(String key) { return this.redisTemplate.opsForSet().size(key); } @Override public Long sRemove(String key, T... values) { return this.redisTemplate.opsForSet().remove(key, values); } @Override public List<T> lRange(String key, long start, long end) { return this.redisTemplate.opsForList().range(key, start, end); } @Override public Long lSize(String key) { return this.redisTemplate.opsForList().size(key); } @Override public T lIndex(String key, long index) { return this.redisTemplate.opsForList().index(key, index); } @Override public Long lPush(String key, T value) { return this.redisTemplate.opsForList().rightPush(key, value); } @Override public Long lPush(String key, T value, long time) { Long index = this.redisTemplate.opsForList().rightPush(key, value); this.expire(key, time); return index; } @Override public Long lPushAll(String key, T... values) { return this.redisTemplate.opsForList().rightPushAll(key, values); } @Override public Long lPushAll(String key, Long time, T... values) { Long count = this.redisTemplate.opsForList().rightPushAll(key, values); this.expire(key, time); return count; } @Override public Long lRemove(String key, long count, T value) { return this.redisTemplate.opsForList().remove(key, count, value); } @Override public Boolean lock(String k, long l, T v) { return this.redisTemplate.opsForValue().setIfAbsent(k, v, l, TimeUnit.MINUTES); } @Override public Boolean lock(String k, T v) { return this.redisTemplate.opsForValue().setIfAbsent(k, v, 2, TimeUnit.MINUTES); } @Override public Boolean lock(String k, T v, long time, TimeUnit unit) { return this.redisTemplate.opsForValue().setIfAbsent(k, v, time, unit); } @Override public Boolean setIfAbsent(String k, T v) { return this.redisTemplate.opsForValue().setIfAbsent(k, v); } @Override public Boolean zadd(String k, T v, double score) { return this.redisTemplate.opsForZSet().add(k, v, score); } @Override public Long zRemove(String k, T v) { return this.redisTemplate.opsForZSet().remove(k, v); } /** * score的增加or减少 zincrby * * @param key * @param value * @param score */ @Override public Double incrScore(String key, T value, double score) { return this.redisTemplate.opsForZSet().incrementScore(key, value, score); } /** * 查询value对应的score zscore * * @param key * @param value * @return */ @Override public Double score(String key, T value) { return this.redisTemplate.opsForZSet().score(key, value); } /** * 判断value在zset中的排名 zrank * * @param key * @param value * @return */ @Override public Long rank(String key, T value) { return this.redisTemplate.opsForZSet().rank(key, value); } /** * 返回集合的长度 * * @param key * @return */ @Override public Long size(String key) { return this.redisTemplate.opsForZSet().zCard(key); } /** * 查询集合中指定顺序的值, 0 -1 表示获取全部的集合内容 zrange * <p> * 返回有序的集合,score小的在前面 * * @param key * @param start * @param end * @return */ @Override public Set<T> zRange(String key, int start, int end) { return this.redisTemplate.opsForZSet().range(key, start, end); } /** * 查询集合中指定顺序的值和score,0, -1 表示获取全部的集合内容 * * @param key * @param start * @param end * @return */ @Override public Set<ZSetOperations.TypedTuple<T>> zRangeWithScore(String key, int start, int end) { Set<ZSetOperations.TypedTuple<T>> typedTuples = this.redisTemplate.opsForZSet().rangeWithScores(key, start, end); return typedTuples; } /** * 查询集合中指定顺序的值 zrevrange * <p> * 返回有序的集合中,score大的在前面 * * @param key * @param start * @param end * @return */ @Override public Set<T> zRevRange(String key, int start, int end) { return this.redisTemplate.opsForZSet().reverseRange(key, start, end); } /** * 根据score的值,来获取满足条件的集合 zrangebyscore * * @param key * @param min * @param max * @return */ @Override public Set<T> zSortRange(String key, int min, int max) { return this.redisTemplate.opsForZSet().rangeByScore(key, min, max); } @Override public String createNo(String redisKey, String prefix, int len) { //redis 自增 存在自增1 否则返回1 Long incr = incr(redisKey, 1); //补全数字 String leftPad = StringUtils.leftPad(incr.toString(), len ,"0"); return MessageFormat.format("{0}{1}", prefix , leftPad); } }
最终,我们将bean注入到系统中,以完成我们的工作。这是一个重要的步骤,它将使我们的应用程序能够正常运行,并启动我们的业务流程。通过注入bean,我们可以更好地利用资源,使我们的应用程序更加可靠和高效。
@Bean @ConditionalOnMissingBean(RedisTemplateService.class) public RedisTemplateService redisTemplateService() { return new RedisTemplateServiceImpl(); }
四,总结
- Spring boot 已经内置了redis依赖,因此无需指定任何特定版本即可使用。
- 注意,使用redisTemplate时,默认采用的是JDK原生序列化,而为了能够对object对象进行反序列化,我们需要改变其序列化方式。在这种情况下,建议使用Jackson2JsonRedisSerialize
- 使用Jackson2JsonRedisSerializer构造器时,ObjectMapper内部不会对LocalDateTime进行字符串化,而是保持对象化,因此反序列化时会报错。为了解决这个问题,我们需要针对LocalDateTime配置自己的ObjectMapper
- Jackson2JsonRedisSerializer序列化提供的ObjectMapper在没有设置反序列化时,对象会以LinkHashMap的形式存储,因此我们需要单独对其进行配置。
- cloud的项目中gateway网关不知为何利用封装的service获取redis中的数据,获取不到。暂时为发现问题原因所在,建议在gateway中注入RedisTemplate。找到原因后会写博客记录下的。
到此这篇关于Spring boot RedisTemplate 序列化 服务化配置的文章就介绍到这了,更多相关Spring boot RedisTemplate 序列化内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!