Java项目:Java脚手架项目的通用组件的封装(五)

文章目录

  • 前言
  • [一、redis 的封装](#一、redis 的封装)
    • [1.1 为什么封装 redis?](#1.1 为什么封装 redis?)
    • [1.2 在 common 工程下创建 common-redis 子工程](#1.2 在 common 工程下创建 common-redis 子工程)
    • [1.3 添加依赖](#1.3 添加依赖)
    • [1.4 创建包目录及 service 包和 config 包](#1.4 创建包目录及 service 包和 config 包)
    • [1.5 在 service 包下创建 RedisService 类](#1.5 在 service 包下创建 RedisService 类)
    • [1.6 在 service 包下创建 RedissonLockService 类](#1.6 在 service 包下创建 RedissonLockService 类)
    • [1.7 对 redis 的默认的序列化器进行更改](#1.7 对 redis 的默认的序列化器进行更改)
      • [1.7.1 在 config 目录下创建 RedisConfig](#1.7.1 在 config 目录下创建 RedisConfig)
    • [1.8 在 resources 下创建自动配置](#1.8 在 resources 下创建自动配置)
  • [二、配置 nacos](#二、配置 nacos)
  • 三、验证
    • [3.1 引入依赖](#3.1 引入依赖)
  • END

鸡汤:
● 允许自己'电量不足',脆弱里藏着比完美更动人的生命力。
● 你不必做太阳,做一盏记得关掉的台灯就好。------ 累了就暗下来,真正的温柔是先对自己说:'今天,到此为止。

前言

进度:前面我们将基础通用包 common-core 、模板服务、网关服务、以及统一模版搞完了。

现在的项目都要引入一个两个的中间件,而我们作为一个''成熟''的脚手架项目也是要封装那么一两个中间件的!

一、redis 的封装

1.1 为什么封装 redis?

在高性能的应用场景下,Redis 展现出了卓越的性能。它能够轻松应对大量并发请求,为系统提供高效、稳定的缓存支持。这种出色的并发处理能力,使得 Redis 在应对高流量、高负载的复杂业务场景时游刃有余,极大地提升了整个系统的响应速度和处理能力,成为保障系统高性能运行的关键因素之一。
正是因为 Redis 具有这些显著的优势,它才会这么常用,在很多项目中才会使用它作为缓存实现方案,这也是我们在脚手架中封装 Redis 的原因。

1.2 在 common 工程下创建 common-redis 子工程

我们将 redis 单独创建一个工程出来,就是为了达到 ''可插拔''的效果,开发者如果需要就可以引入 common-redis 的依赖,而开发者如果无需要,只要不添加依赖就可以。

1.3 添加依赖

pom.xml:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.my</groupId>
        <artifactId>common</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <groupId>com.my</groupId>
    <artifactId>common-redis</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-json</artifactId>
        </dependency>

        <!-- redisson -->
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>com.my</groupId>
            <artifactId>common-core</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

</project>

1.4 创建包目录及 service 包和 config 包

1.5 在 service 包下创建 RedisService 类


封装 redis 提供的方法,思考方向 通用 -> String类型 -> List类型 -> Set类型 -> Zset类型 -> Hash类型
RedisService:

java 复制代码
package com.my.commonredis.service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.my.commoncore.utils.JsonUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Component
public class RedisService {

    @Autowired
    private RedisTemplate redisTemplate;

    //*********************** 基本操作 **************************
    public Boolean expire(final String key, final long timeout) {
        return redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
    }


    //redis设置数据有效时间(可指定时间单位)
    public Boolean expire(final String key, final long timeout, final TimeUnit timeUnit) {
        return redisTemplate.expire(key, timeout, timeUnit);
    }

    /**
     * 获取有效时间
     *
     * @param key Redis键
     * @return 有效时间
     */
    public long getExpire(final String key) {
        return redisTemplate.getExpire(key);
    }

    /**
     * 判断 key是否存在
     *
     * @param key 键
     * @return true=存在;false=不存在
     */
    public Boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 根据提供的键模式查找 Redis 中匹配的键
     *
     * @param pattern 要查找的键的模式
     * @return 键列表
     */
    public Collection<String> keys(final String pattern) {
        return redisTemplate.keys(pattern);
    }


    /**
     * 重命名key
     *
     * @param oldKey 原来key
     * @param newKey 新key
     */
    public void renameKey(String oldKey, String newKey) {
        redisTemplate.rename(oldKey, newKey);
    }

    /**
     * 删除单个数据
     *
     * @param key 缓存的键值
     * @return 是否成功  true=删除成功;false=删除失败
     */
    public boolean deleteObject(final String key) {
        return redisTemplate.delete(key);
    }

    /**
     * 删除多个数据
     *
     * @param collection 多个数据对应的缓存的键值
     * @return 是否删除了对象 true=删除成功;false=删除失败
     */
    public boolean deleteObject(final Collection collection) {
        return redisTemplate.delete(collection) > 0;
    }


    //************************* String类型操作 ****************************/

    //修饰符  返回值类型 函数名  参数列表  函数体
    //    缓存String数据     key value  test aaa
    //(将数据转为Json字符串存入)
    /**
     * 缓存String数据 (将数据转为Json字符串存入)
     *
     * @param key 缓存的键值
     * @param value 缓存的值
     * @param <T> 对象类型
     */
    public <T> void setCacheObject(String key, T value) {
        redisTemplate.opsForValue().set(key,value);
    }

    //    缓存String数据,并设置有效时间
//    (将数据转为Json字符串存入)
    /**
     * 缓存String数据,并设置有效时间 (将数据转为Json字符串存入)
     * @param key 缓存的键值
     * @param value 缓存的值
     * @param timeout 时间
     * @param timeUnit 时间单位
     * @param <T> 对象类型
     */
    public <T> void setCacheObject(String key, T value, long timeout, TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(key,value,timeout,timeUnit);
    }

    //    缓存String数据,如果该键不存在则存储,若已存在则不存储。
    /**
     * 缓存String数据,如果该键不存在则存储,若已存在则不存储。
     *
     * @param key      缓存的键值
     * @param value    缓存的值
     * @param <T> 对象类型
     * @return 是否缓存了对象   如果key已经存在,则返回false,否则返回true
     */
    public <T> Boolean setCacheObjectIfAbsent(String key, T value) {
        return redisTemplate.opsForValue().setIfAbsent(key,value);
    }

    /**
     * 缓存String数据,如果该键不存在则存储,并设置数据有效时间,若已存在则不存储。
     *
     * @param key      缓存的键值
     * @param value    缓存的值
     * @param timeout  时间
     * @param timeUnit 时间单位
     * @param <T> 对象类型
     * @return 是否缓存了对象   如果key已经存在,则返回false,否则返回true
     */
    public <T> Boolean setCacheObjectIfAbsent(String key, T value, long timeout, TimeUnit timeUnit) {
        return redisTemplate.opsForValue().setIfAbsent(key,value,timeout,timeUnit);
    }

    //    获得缓存的数据(将缓存的数据反序列化为指定类型返回)
    //key : test  value
    /**
     * 获得缓存的数据(将缓存的数据反序列化为指定类型返回)
     * @param key 缓存键值
     * @param clazz 对应数据的类
     * @return 缓存键值对应的数据
     * @param <T> 对应数据的类型
     */
    public <T> T getCacheObject(String key, Class<T> clazz) {
        Object o = redisTemplate.opsForValue().get(key);
        if(o==null){
            return null;
        }
        // o 不一定就是 String类型,不能强转
        String json = JsonUtil.toJson(o);
        return JsonUtil.fromJson(json,clazz);
    }

    /**
     * 获得缓存的数据 (将缓存的数据反序列化为指定类型返回,支持复杂的泛型)
     * @param key 缓存键值
     * @param valueTypeRef 类型模板
     * @return 缓存键值对应的数据
     * @param <T> 对象类型
     */
    public <T> T getCacheObject(String key, TypeReference<T> valueTypeRef) {
        Object o = redisTemplate.opsForValue().get(key);
        if(o==null){
            return null;
        }
        // o 不一定就是 String类型,不能强转
        String json = JsonUtil.toJson(o);
        return JsonUtil.fromJson(json,valueTypeRef);
    }

    //************************* List类型操作 ****************************/
    //修饰符  返回值类型 函数名  参数列表  函数体
    //缓存List数据(插入整个list数据,并保持原顺序)
    /**
     * 缓存List数据
     * @param key 缓存的键值
     * @param dataList 待缓存的List数据
     * @return 添加元素后 Redis 列表的长度
     * @param <T> 对象类型
     */
    public <T> Long setCacheList (String key, List<T> dataList) {
        //        redisTemplate.opsForList().leftPushAll()
        //rightPushAll 的返回值指的是:添加之后,Redis中当前操作的这个list结构的长度
        Long count = redisTemplate.opsForList().rightPushAll(key,dataList);
        return count == null ? 0L : count;
    }

    /**
     * 从List结构左侧插入数据(头插、入队)
     * @param key key
     * @param value 缓存的对象
     * @param <T> 值类型
     */
    public <T> void leftPushForList(String key,T value) {
        redisTemplate.opsForList().leftPush(key,value);
    }

    /**
     * 从List结构右侧插入数据(尾插、插入单个数据)
     * @param key key
     * @param value 缓存的对象
     * @param <T> 值类型
     */
    public <T> void rightPushForList(String key,T value) {
        redisTemplate.opsForList().rightPush(key,value);
    }

    /**
     * 删除左侧第一个数据 (头删)
     * @param key   key
     */
    public <T> void leftPopForList(String key) {
        redisTemplate.opsForList().leftPop(key);
    }

    /**
     * 删除右侧第一个数据 (尾删)
     * @param key   key
     */
    public <T> void rightPopForList(String key) {
        redisTemplate.opsForList().rightPop(key);
    }

    /**
     * 移除List第一个匹配的元素
     *
     * @param key key
     * @param value 值
     * @param <T> 值类型
     */
    public <T> void removeForList(String key,T value) {
        redisTemplate.opsForList().remove(key,-1,value);
        //删除的方向: > 0 从左往右   <0 从右往左
        //key : redis key
        ///count :删除的方向 & 删除个数(count绝对值的大小  1 -1 =》 1   2 -2 =》2)   count > 0 从左往右删除  count < 0 从右往左删除
        //count = 0 代表全部删除
    }

    /**
     * 移除List中匹配的所有列表元素
     *
     * @param key key
     * @param value 值
     * @param <T> 值类型
     */
    public <T> void removeAllForList(String key, T value) {
        redisTemplate.opsForList().remove(key,0,value);
    }

    /**
     * 移除指定列表中的所有元素
     *
     * @param key key
     */
    public <T> void removeForAllList(String key) {
        redisTemplate.opsForList().trim(key,0,-1);
    }

    /**
     *  修改指定下标数据
     * @param key        key
     * @param index     下标
     * @param newValue  修改后新值
     * @param <T>       值类型
     */
    public <T> void setElementAtIndex(String key,T newValue,int index) {
        redisTemplate.opsForList().set(key,index,newValue);
    }

    /**
     * 获得缓存的list对象
     * @param key key 缓存的键值
     * @param clazz 对象的类
     * @return 列表
     * @param <T> 对象类型
     */
//    Set data = redisTemplate.opsForZSet().range(key, 0, -1);
    //range :获取指定范围的数据
    //有序性
    public <T> List<T> getCacheList(String key, Class<T> clazz) {
        List list = redisTemplate.opsForList().range(key,-1,0);
        return JsonUtil.fromJsonToList(JsonUtil.toJson(list),clazz);
        //key  : redis的key
        //0 代表第一个元素  1 :第二个元素  2 第三个元素 依次类推    -1 最后一个元素  -2 倒数第二个元素  依次类推
        //start : 起始索引(下标)
        //end : 结束索引(下标)
    }

    /**
     * 获得缓存的list对象 (支持复杂的泛型嵌套)
     * @param key key信息
     * @param typeReference 类型模板
     * @return list对象
     * @param <T> 对象类型
     */
    public <T> List<T> getCacheList(String key, TypeReference<List<T>> typeReference) {
        List list = redisTemplate.opsForList().range(key,0,-1);
        return JsonUtil.fromJson(JsonUtil.toJson(list),typeReference);
    }

    /**
     * 根据范围获取List
     *
     * @param key key
     * @param start 开始位置
     * @param end 结束位置
     * @param clazz 类信息
     * @return List列表
     * @param <T> 类型
     */
    public <T> List<T> getCacheListByRange(final String key, long start, long end, Class<T> clazz) {
        List list = redisTemplate.opsForList().range(key,start,end);
        return JsonUtil.fromJsonToList(JsonUtil.toJson(list),clazz);
    }

    /**
     * 根据范围获取List(支持复杂的泛型嵌套 )
     *
     * @param key key
     * @param start 开始
     * @param end 结果
     * @param typeReference 类型模板
     * @return list列表
     * @param <T> 类型信息
     */
    public <T> List<T> getCacheListByRange(final String key, long start, long end, TypeReference<List<T>> typeReference) {
        List list = redisTemplate.opsForList().range(key,start,end);
        return JsonUtil.fromJson(JsonUtil.toJson(list),typeReference);
    }

    /**
     * 获取指定列表长度
     * @param key key信息
     * @return 列表长度
     */
    public Long getCacheListSize(String key) {
        Long count = redisTemplate.opsForList().size(key);
        return count == null ? 0 : count;
    }

    //************************ 操作Set类型 ***************************
    /**
     * set添加元素(批量添加或添加单个元素)
     * @param key key
     * @param member 元素信息
     */
    public void addMember(final String key, Object... member) {
        redisTemplate.opsForSet().add(key, member);
    }

    /**
     * 删除元素
     * @param key key
     * @param member 元素信息
     */
    public void deleteMember(final String key, Object... member) {
        redisTemplate.opsForSet().remove(key, member);
    }


    /**
     * 获取set数据(支持复杂的泛型嵌套)
     * @param key key
     * @param typeReference 类型模板
     * @return set数据
     * @param <T> 类型信息
     */
    public <T> Set<T> getCacheSet(final String key, TypeReference<Set<T>> typeReference) {
        Set data = redisTemplate.opsForSet().members(key);
        return JsonUtil.fromJson(JsonUtil.toJson(data), typeReference);
    }

    //************************ 操作ZSet类型 ***************************
    /**
     * 添加元素
     * @param key key
     * @param value 值
     * @param seqNo 分数
     */
    public void addMemberZSet(String key, Object value, double seqNo) {
        redisTemplate.opsForZSet().add(key, value, seqNo);
    }

    /**
     * 删除元素
     * @param key    key
     * @param value  值
     */
    public void delMemberZSet(String key, Object value) {
        redisTemplate.opsForZSet().remove(key, value);
    }

    /**
     * 根据排序分值删除
     *
     * @param key key
     * @param minScore 最小分
     * @param maxScore 最大分
     */
    public void removeZSetByScore(final String key, double minScore, double maxScore) {
        redisTemplate.opsForZSet().removeRangeByScore(key, minScore, maxScore);
    }


    /**
     * 获取有序集合数据(支持复杂的泛型嵌套)
     *
     * @param key key信息
     * @param typeReference 类型模板
     * @return 有序集合
     * @param <T> 对象类型
     */
    public <T> Set<T> getCacheZSet(final String key, TypeReference<LinkedHashSet<T>> typeReference) {
        Set data = redisTemplate.opsForZSet().range(key, 0, -1);
        return JsonUtil.fromJson(JsonUtil.toJson(data), typeReference);
    }

    /**
     * 降序获取有序集合(支持复杂的泛型嵌套)
     * @param key key信息
     * @param typeReference 类型模板
     * @return 降序的有序集合
     * @param <T> 对象类型信息
     */
    public <T> Set<T> getCacheZSetDesc(final String key, TypeReference<LinkedHashSet<T>> typeReference) {
        Set data = redisTemplate.opsForZSet().reverseRange(key, 0, -1);

        return JsonUtil.fromJson(JsonUtil.toJson(data), typeReference);
    }

    //************************ 操作Hash类型 ***************************
    /**
     * 缓存Map数据
     * @param key key
     * @param dataMap map
     * @param <T> 对象类型
     */
    public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
        if (dataMap != null) {
            redisTemplate.opsForHash().putAll(key, dataMap);
        }
    }

    /**
     * 往Hash中存入单个数据
     * @param key Redis键
     * @param hKey Hash键
     * @param value 值
     * @param <T> 对象类型
     */
    public <T> void setCacheMapValue(final String key, final String hKey, final T value) {
        redisTemplate.opsForHash().put(key, hKey, value);
    }

    /**
     * 删除Hash中的某条数据
     *
     * @param key  Redis键
     * @param hKey Hash键
     * @return 是否成功
     */
    public boolean deleteCacheMapValue(final String key, final String hKey) {
        return redisTemplate.opsForHash().delete(key, hKey) > 0;
    }

    /**
     * 获取缓存的map数据(支持复杂的泛型嵌套)
     * @param key key
     * @param typeReference 类型模板
     * @return hash对应的map
     * @param <T> 对象类型
     */
    public <T> Map<String, T> getCacheMap(final String key, TypeReference<Map<String, T>> typeReference) {
        Map data= redisTemplate.opsForHash().entries(key);
        return JsonUtil.fromJson(JsonUtil.toJson(data), typeReference);
    }

    /**
     * 获取Hash中的单个数据
     * @param key Redis键
     * @param hKey Hash键
     * @return Hash中的对象
     * @param <T> 对象类型
     */
    public <T> T getCacheMapValue(final String key, final String hKey) {
        HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
        return opsForHash.get(key, hKey);
    }

    /**
     * 获取Hash中的多个数据
     *
     * @param key Redis键
     * @param hKeys Hash键集合
     * @param typeReference 对象模板
     * @return 获取的多个数据的集合
     * @param <T> 对象类型
     */
    public <T> List<T> getMultiCacheMapValue(final String key, final Collection<String> hKeys, TypeReference<List<T>> typeReference) {
        List data = redisTemplate.opsForHash().multiGet(key, hKeys);

        return JsonUtil.fromJson(JsonUtil.toJson(data), typeReference);
    }


    //******************************** LUA脚本 ***********************************
    /**
     * 删除指定值对应的 Redis 中的键值(compare and delete)
     *
     * @param key   缓存key
     * @param value value
     * @return 是否完成了比较并删除
     */
    public boolean cad(String key, String value) {
        if (key.contains(StringUtils.SPACE) || value.contains(StringUtils.SPACE)) {
            return false;
        }

        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";

        // 通过lua脚本原子验证令牌和删除令牌
        Long result = (Long) redisTemplate.execute(new DefaultRedisScript<>(script, Long.class),
                Collections.singletonList(key),
                value);
        return !Objects.equals(result, 0L);
    }

}

1.6 在 service 包下创建 RedissonLockService 类


提供 Redisson 分布式锁的服务,因为是基于 redis 实现的所以就将它俩放在一起了。
RedissonLockService :

java 复制代码
package com.my.commonredis.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;

import java.util.concurrent.TimeUnit;

/**
 * 分布式锁
 */
@Slf4j
@RequiredArgsConstructor
public class RedissonLockService {
    /**
     * redis操作客户端
     */
    private final RedissonClient redissonClient;

    /**
     * 获取锁
     *
     * @param lockKey        锁的key,唯一标识,建议模块名+唯一键
     * @param expire         超时时间,单位毫秒,传入-1自动续期
     * @return 获取到的RLock实例,为null则获取失败
     */
    public RLock acquire(String lockKey, long expire) {
        try {
            final RLock lockInstance = redissonClient.getLock(lockKey);

            // 注意:如果tryLock指定了leaseTime>0就不会续期。参考 RedissonLock类的tryAcquireAsync方法的实现
            lockInstance.lock(expire, TimeUnit.MILLISECONDS);
            return lockInstance;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 释放锁。注意:必须和获取锁在一个线程中
     *
     * @param lockInstance 锁的实例,acquire返回的
     * @return 释放成功返回true,否则返回false
     */
    public boolean releaseLock(RLock lockInstance) {
        if (lockInstance.isHeldByCurrentThread()) {
            lockInstance.unlock();
            return true;
        }
        return false;
    }
}

1.7 对 redis 的默认的序列化器进行更改

redis 默认提供的 redisTemplate 的序列化器在序列化的时候会把数据存储为不可读的二进制的数据,随然可能对项目没什么影响,但是如果以后我们就是要看 redis 里的数据呢?

所以我们就要自己创建一个 redisTemplate,交给Spring 容器管理,修改序列化器

1.7.1 在 config 目录下创建 RedisConfig


这里的序列化器使用 GenericJackson2JsonRedisSerializer
RedisConfig:

java 复制代码
package com.my.commonredis.config;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.my.commondomain.constants.CommonConstants;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;


@AutoConfigureBefore(RedisAutoConfiguration.class)
@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate (RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //Redis 中key的序列化设置
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        //Redis 中value的序列化设置
        GenericJackson2JsonRedisSerializer jsonRedisSerializer = createJacksonSerializer();
        redisTemplate.setValueSerializer(jsonRedisSerializer);
        redisTemplate.setHashValueSerializer(jsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    /**
     * 创建序列化器
     * @return redis序列化器
     */
    private GenericJackson2JsonRedisSerializer createJacksonSerializer() {
        ObjectMapper OBJECT_MAPPER = JsonMapper.builder()
                //反序列化时,如果出现对应Java对象类没有定义的属性时,默认会抛出异常
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                //序列化时,将日期转化为时间戳,默认为 true
                .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
                //序列化时,如果序列化的类为 null,设为 true 会报错,false 不会报错,默认为 true
                .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
                .configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false)
                //不适用默认的dateTime进行序列化,使用JSR310的LocalDateTimeSerializer
                .configure(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS, false)
                //设置序列化类上的注解是否生效,默认为 true
                .configure(MapperFeature.USE_ANNOTATIONS, false)
                //重点,这是序列化LocalDateTIme和LocalDate的必要配置,由Jackson-data-JSR310实现
                .addModule(new JavaTimeModule())
                .addModule(new SimpleModule()
                        // 定义 LocalDateTime 序列化和反序列化的格式
                        .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(CommonConstants.STANDARD_FORMAT)))
                        .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(CommonConstants.STANDARD_FORMAT)))
                )
                //所有的日期格式都统一为以下的样式,即yyyy-MM-dd HH:mm:ss
                .defaultDateFormat(new SimpleDateFormat(CommonConstants.STANDARD_FORMAT))
                // 只针对非空的值进行序列化
                .serializationInclusion(JsonInclude.Include.NON_NULL)
                .build();
        return new GenericJackson2JsonRedisSerializer(OBJECT_MAPPER);
    }
}

注:
@AutoConfigureBefore(RedisAutoConfiguration.class) 这个注解是抢在 RedisAutoConfiguration 前注册 Bean ,如果不加这个,后面在给网关服务引入相关服务时,启动会报错,说有两个 Bean

1.8 在 resources 下创建自动配置

自动配置目录 : META.spring.org.springframework.boot.autoconfigure.AutoConfiguration.imports

将他们三个全部交给 Spring 容器管理

二、配置 nacos

因为想要使用 redis 必然需要 redis 的地址配置啥的。我们将 redis 的配置放在 nacos 里这样引入了 redis 依赖的服务,都可以在 nacos 拿到 redis 的配置


三、验证

再次拿 mstemplate 模版服务来进行验证,将 common-redis 的依赖引入模板服务,搞一个 controller 层,拿apifox验证一下

3.1 引入依赖


我自己当时全验证了一遍,现在就简单的验一下
TestRedisController:

java 复制代码
package com.my.mstemplateservice.test;

import com.fasterxml.jackson.core.type.TypeReference;
import com.my.commondomain.domain.vo.R;
import com.my.commonredis.service.RedisService;
import com.my.mstemplateservice.domain.RegionTest;
import com.my.mstemplateservice.domain.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.*;

@RestController
@Slf4j
@RequestMapping("/test/redis")
public class TestRedisController {

    @Autowired
    private RedisService redisService;

    @PostMapping("/add")
    public R<Void> add () {
//        redisService.setCacheObject("key", "value");

//        redisService.setCacheObject("key", "value123",15, TimeUnit.SECONDS);

//        Boolean b = redisService.setCacheObjectIfAbsent("key", "value123");
//        if (!b) {
//            return R.fail(ResultCode.FAILED.getCode(),ResultCode.FAILED.getMsg());
//        }

//        Boolean b = redisService.setCacheObjectIfAbsent("key", "value123",15, TimeUnit.SECONDS);
//        if (!b) {
//            return R.fail(ResultCode.FAILED.getCode(),ResultCode.FAILED.getMsg());
//        }

        RegionTest testRegion = new RegionTest();
        testRegion.setId(1L);
        testRegion.setName("北京");
        testRegion.setFullName("北京市");
        testRegion.setCode("110000");

        List<Map<String, RegionTest>> list = new ArrayList<>();
        Map<String, RegionTest> map = new LinkedHashMap<>();
        map.put("beijing", testRegion);
        list.add(map);

        redisService.setCacheObject("testList",list);
        return R.success();
    }

    @GetMapping("/get")
    public R<Void> get () {
//        String value = redisService.getCacheObject("key", String.class);
//        System.out.println(value);
        //将redis中的数据获取出来  对象的类型不会产生泛型擦除问题
        List<Map<String, RegionTest>> testList = redisService.getCacheObject("testList", new TypeReference<List<Map<String, RegionTest>>>() {
        });
        System.out.println(testList);
        return R.success();
    }

    @PostMapping("/list/add")
    public R<Void> listAdd() {
//        String str = "listKey";
//        List<String> list = new ArrayList<>();
//        list.add("a");
//        list.add("c");
//        list.add("d");
//        list.add("g");
//        list.add("a");
//        list.add("b");
//        list.add("c");
//        list.add("c");
//        list.add("a");
//        redisService.setCacheList(str,list);

        // 在左边第一位插入元素
//        redisService.leftPushForList(str,"d");
        // 在右边第一位插入元素
//        redisService.rightPushForList(str,"p");

//        String userListKey = "userListKey";
//        List<User> list = new ArrayList<>();
//        list.add(new User("zhangsan",21));
//        list.add(new User("list",31));
//        list.add(new User("wangwu",26));
//        redisService.setCacheList(userListKey,list);

        String userListMapKey = "userListMap";
        List<Map<String,User>> list = new ArrayList<>();
//        list.add(Map.of("1",new User("zhangsan",21)));
//        list.add(Map.of("2",new User("list",31)));
//        list.add(Map.of("3",new User("wangwu",26)));
        list.add(Map.of("1",new User("zhangsan",21),"2",new User("list",31)));
        list.add(Map.of("3",new User("wangwu",26)));
        redisService.setCacheList(userListMapKey,list);
        return R.success();
    }

    @DeleteMapping("/list/delete")
    public R<Void> listDel() {
        String str = "listKey";
        // 删除从左到右的第一个 匹配元素
//        redisService.removeForList(str,"c");
        // 删除从右到左的第一个 匹配元素
//        redisService.removeForList(str,"a");
        // 删除左边第一个元素
//        redisService.leftPopForList(str);
        // 删除右边第一个元素
//        redisService.rightPopForList(str);
        // 删除 list 中的所有指定元素
        redisService.removeAllForList(str,"a");
        return R.success();
    }

    @GetMapping("/list/get")
    public R<Void> listGet() {
//        String str = "listKey";
        // get 简单结构的 list
//        List<String> cacheList = redisService.getCacheList(str, String.class);
//        System.out.println(cacheList);
//        List<User> userListKey = redisService.getCacheList("userListKey", User.class);
//        System.out.println(userListKey);

        // get 复杂结构的 list
        List<Map<String, User>> userListMap = redisService.getCacheList("userListMap", new TypeReference<List<Map<String, User>>>() {
        });
        System.out.println(userListMap);
        return R.success();
    }

    @PostMapping("/type/add")
    public R<Void> typeAdd() {
//        String str = "setKey";
//        redisService.addMember(str,"a");
//        redisService.addMember(str,"c");
//        redisService.addMember(str,"d");
//        redisService.addMember(str,"e","c","f");
//        redisService.addMember(str,"a");
//        redisService.addMember(str,"c");

//        String zsetKey = "zset";
//        redisService.addMemberZSet(zsetKey,"zhangsan",13.5);
//        redisService.addMemberZSet(zsetKey,"lisi",3.6);
//        redisService.addMemberZSet(zsetKey,"wangwu",5.7);
//        redisService.addMemberZSet(zsetKey,"kk",1);

//        String hashKey = "user1";
//        User user = new User();
//        user.setName("zhangsan");
//        user.setAge(45);
//        User user = new User();
//        user.setName("wangwu");
//        user.setAge(30);
//        redisService.setCacheMap(hashKey, JsonUtil.convertToMap(user));
//        redisService.setCacheMapValue(hashKey,"name","lisi");
//        redisService.setCacheMap("user2",JsonUtil.convertToMap(user));
//        redisService.setCacheMapValue(hashKey,"address","内蒙古");

//        String str = "setKey";
//        redisService.renameKey(str,"listKey");

        return R.success();
    }

    @DeleteMapping("/type/delete")
    public R<Void> typeDel() {
//        String str = "setKey";
//        redisService.deleteMember(str,"a");
//        redisService.deleteMember(str,"d");
//        redisService.deleteMember(str,"c","f");
//        String zsetKey = "zset";
//        redisService.delMemberZSet(zsetKey,"zhangsan");
//        redisService.removeZSetByScore(zsetKey,1,6.0);

//        String str = "setKey";
//        redisService.expire("setKey",15,TimeUnit.SECONDS);

//        String hashKey = "user1";
//        redisService.deleteCacheMapValue(hashKey,"address");

//        String str = "listKey";
//        redisService.deleteObject(str);
        List<String> delList = new ArrayList<>();
        delList.add("user1");
        delList.add("user2");
        redisService.deleteObject(delList);
        return R.success();
    }

    @GetMapping("/type/get")
    public R<Void> typeGet() {
//        String str = "setKey";
//        Set<String> cacheSet = redisService.getCacheSet(str, new TypeReference<Set<String>>() {
//        });
//        System.out.println(cacheSet);

//        String zsetKey = "zset";
//        Set<String> cacheZSet = redisService.getCacheZSet(zsetKey, new TypeReference<LinkedHashSet<String>>() {
//        });
//        Set<String> cacheZSet = redisService.getCacheZSetDesc(zsetKey, new TypeReference<LinkedHashSet<String>>() {
//        });
//        System.out.println(cacheZSet);

        String hashKey = "user1";
//        Map<String, Object> cacheMap = redisService.getCacheMap(hashKey, new TypeReference<Map<String, Object>>() {
//        });
//        System.out.println(cacheMap);
//        Object name = redisService.getCacheMapValue(hashKey, "age");
//        System.out.println(name);
        List<String> list = new ArrayList<>();
        list.add("name");
        list.add("age");
        List<String> multiCacheMapValue = redisService.getMultiCacheMapValue(hashKey, list, new TypeReference<List<String>>() {
        });
        System.out.println(multiCacheMapValue);
        return R.success();
    }
}

这个 redis 的可视化管理界面是 Another Redis Desktop Manager


END

redis 中间件封装完毕!

相关推荐
哈库纳玛塔塔1 小时前
dbVisitor 利用 queryForPairs 让键值查询一步到位
java·数据库·python
sa100271 小时前
京东评论接口调用、签名生成与异常处理
开发语言·数据库·python
赵谨言1 小时前
基于Python实现地理空间数据批处理技术探讨及实现--以“多规合一“总体规划数据空间叠加分析为例
大数据·开发语言·经验分享·python
亓才孓1 小时前
[Stream]
java
独自破碎E2 小时前
BISHI40数组取精
java·开发语言
❀͜͡傀儡师2 小时前
基于mybatis-plus进行加解密 Spring Boot Starter
spring boot·oracle·mybatis
丑八怪大丑2 小时前
Java面向对象(进阶)
java·开发语言
java1234_小锋2 小时前
Java高频面试题:Java中变量和常量有什么区别?
java·开发语言·面试
enjoy嚣士3 小时前
Java 之 实现C++库函数等价函数遇到的问题
java·开发语言·c++