自学内容网 自学内容网

封装Redis模块(最全面的教程!)

1.环境搭建

1.创建模块

CleanShot 2024-11-15 at 20.32.47@2x

2.查看是否交给父模块管理

CleanShot 2024-11-15 at 20.35.25@2x

3.引入依赖
<?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.sunxiansheng</groupId>
        <artifactId>sunrays-common</artifactId>
        <version>1.0</version>
    </parent>

    <version>1.0</version>

    <artifactId>common-redis-starter</artifactId>

    <dependencies>
        <!-- redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <!-- 排除,防止日志冲突 -->
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-logging</artifactId>
                    <groupId>org.springframework.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- 集成 redis 所需 commons-pool2 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>
    </dependencies>

</project>
4.自动配置
1.目录

CleanShot 2024-11-15 at 20.43.20@2x

2.RedisAutoConfiguration.java
package com.sunxiansheng.redis.config;

import org.springframework.context.annotation.Configuration;

/**
 * Description: Redis自动配置类
 *
 * @Author sun
 * @Create 2024/11/15 20:41
 * @Version 1.0
 */
@Configuration
public class RedisAutoConfiguration {
}
3.spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.sunxiansheng.redis.config.RedisAutoConfiguration

2.重写RedisTemplate

1.引入Jackson
        <!-- 重写RedisTemplate所需要的Jackson -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
        </dependency>
2.编写RedisConfig.java

CleanShot 2024-11-15 at 20.47.53@2x

package com.sunxiansheng.redis.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator;
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.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * Redis配置类,会将 Object 类型序列化为 JSON 格式,然后将其作为字符串存储在 Redis 中。
 * 当从 Redis 中读取时,会将 JSON 字符串反序列化回具体的 Object 类型数据,直接强制转换即可,无需手动解析 JSON。
 */
@Configuration
public class RedisConfig {

    /**
     * 自定义RedisTemplate Bean,配置Key和Value的序列化方式。
     * Key采用String序列化,Value采用JSON序列化,支持对象直接转为JSON格式存储在Redis中。
     *
     * @param redisConnectionFactory Redis连接工厂,用于创建RedisTemplate连接
     * @return 配置完成的RedisTemplate实例,用于Redis数据操作
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        // 设置Key的序列化方式为StringRedisSerializer,以便Key以字符串格式存储,便于人类读取
        RedisSerializer<String> stringSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringSerializer);          // 序列化Redis键
        redisTemplate.setHashKeySerializer(stringSerializer);      // 序列化Hash结构的键

        // 设置Value和HashValue的序列化方式为Jackson2JsonRedisSerializer,以便Value以JSON格式存储
        Jackson2JsonRedisSerializer<Object> jacksonSerializer = jackson2JsonRedisSerializer();
        redisTemplate.setValueSerializer(jacksonSerializer);       // 序列化Redis值
        redisTemplate.setHashValueSerializer(jacksonSerializer);   // 序列化Hash结构的值

        // 初始化设置的配置
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    /**
     * 配置Jackson序列化器,以支持复杂Java对象的序列化和反序列化。
     * 使用Jackson2JsonRedisSerializer将对象序列化为JSON字符串,从而提高Redis中的可读性和兼容性。
     *
     * @return 配置好的Jackson2JsonRedisSerializer实例,指定序列化格式为JSON
     */
    private Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer() {
        // 创建Jackson2JsonRedisSerializer,指定泛型为Object,支持序列化任意Java对象
        Jackson2JsonRedisSerializer<Object> jacksonSerializer = new Jackson2JsonRedisSerializer<>(Object.class);

        // 创建ObjectMapper用于配置JSON序列化方式
        ObjectMapper objectMapper = new ObjectMapper();

        // 设置可见性,允许访问所有字段(包括私有和保护字段),确保所有属性都被序列化和反序列化
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);

        // 配置反序列化时忽略未知属性,防止因JSON中多余字段导致反序列化错误
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        // 序列化时忽略空值属性,节省存储空间
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

        // 启用类型信息,确保反序列化时能够恢复原始对象类型
        objectMapper.activateDefaultTyping(
                BasicPolymorphicTypeValidator.builder()
                        .allowIfSubType(Object.class)
                        .build(),
                ObjectMapper.DefaultTyping.NON_FINAL
        );

        // 将配置好的ObjectMapper设置到Jackson2JsonRedisSerializer中,应用上述配置
        jacksonSerializer.setObjectMapper(objectMapper);
        return jacksonSerializer;
    }
}
3.RedisAutoConfiguration.java 导入配置类

CleanShot 2024-11-15 at 20.48.30@2x

3.Redis工具类

1.RBase.java Redis基础工具类
package com.sunxiansheng.redis.utils;

import org.springframework.data.redis.core.RedisTemplate;

import java.util.Collection;
import java.util.concurrent.TimeUnit;

/**
 * Redis基础工具类,提供一些基础的操作
 *
 * @Author sun
 * @Create 2024/11/14 14:25
 * @Version 1.0
 */
public class RBase {

    protected RedisTemplate<String, Object> redisTemplate;

    public RBase(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 默认的key分隔符
     */
    private static final String DEFAULT_KEY_SEPARATOR = ":";

    /**
     * 构建缓存key(使用默认的key分隔符)
     *
     * @param parts 多个字符串拼接成缓存key
     * @return 拼接后的缓存key
     */
    public String buildKeyByDefaultSeparator(String... parts) {
        return String.join(DEFAULT_KEY_SEPARATOR, parts);
    }

    /**
     * 构建缓存key(使用自定义的key分隔符)
     *
     * @param separator 自定义的key分隔符
     * @param parts     多个字符串拼接成缓存key
     * @return 拼接后的缓存key
     */
    public String buildKeyByCustomSeparator(String separator, String... parts) {
        return String.join(separator, parts);
    }

    /**
     * 删除单个key
     *
     * @param key 键
     * @return 如果键不存在,返回false;如果删除成功,返回true
     */
    public Boolean delete(String key) {
        if (key == null || key.isEmpty()) {
            throw new IllegalArgumentException("Key cannot be null or empty");
        }
        return redisTemplate.delete(key);
    }

    /**
     * 批量删除key
     *
     * @param keys 键的集合
     * @return 成功删除的键的数量,键不存在不计数
     */
    public Long deleteBatch(Collection<String> keys) {
        if (keys == null || keys.isEmpty()) {
            return 0L;
        }
        return redisTemplate.delete(keys);
    }

    /**
     * 指定缓存失效时间
     *
     * @param key     键
     * @param timeout 失效时间(小于等于0 表示 永久有效)
     * @param unit    时间单位
     * @return 设置成功返回true,失败返回false
     */
    public Boolean expire(String key, long timeout, TimeUnit unit) {
        if (key == null || key.isEmpty()) {
            throw new IllegalArgumentException("Key cannot be null or empty");
        }
        if (timeout <= 0) {
            // 或直接返回 true,表示设置为永久有效
            return false;
        }
        return redisTemplate.expire(key, timeout, unit);
    }

    /**
     * 指定缓存失效时间(时间单位:秒)
     *
     * @param key     键
     * @param timeout 失效时间(单位:秒,小于等于0 表示 永久有效)
     * @return 设置成功返回true,失败返回false
     */
    public Boolean expire(String key, long timeout) {
        return expire(key, timeout, TimeUnit.SECONDS);
    }

    /**
     * 获取缓存失效时间
     *
     * @param key 键
     * @return 缓存失效时间(秒)。键不存在返回-2,键存在但没有设置过期时间返回-1
     */
    public Long getExpire(String key) {
        if (key == null || key.isEmpty()) {
            throw new IllegalArgumentException("Key cannot be null or empty");
        }
        return redisTemplate.getExpire(key);
    }

    /**
     * 判断key是否存在
     *
     * @param key 键
     * @return 存在返回true,不存在返回false
     */
    public Boolean hasKey(String key) {
        if (key == null || key.isEmpty()) {
            throw new IllegalArgumentException("Key cannot be null or empty");
        }
        return redisTemplate.hasKey(key);
    }

    /**
     * 转换缓存中的对象为指定类型
     *
     * @param value 缓存中的对象
     * @param type  要转换的目标类型
     * @param <T>   返回的泛型类型
     * @return 转换后的对象
     * @throws ClassCastException 如果对象不能转换为指定类型
     */
    protected <T> T convertValue(Object value, Class<T> type) {
        if (value == null) {
            return null;
        }

        // Long类型的特殊处理,因为Redis中的数据会自动反序列化为Integer
        if (type == Long.class && value instanceof Integer) {
            return type.cast(((Integer) value).longValue());
        }

        if (type.isInstance(value)) {
            return type.cast(value);
        } else {
            throw new ClassCastException("Redis中的对象运行类型与请求转换的类型不匹配,请优先检查Redis配置类是否保存了对象原始信息!期待类型:"
                    + type.getName() + ",实际类型:"
                    + value.getClass().getName());
        }
    }
}
2.RString.java
package com.sunxiansheng.redis.utils;

import org.springframework.data.redis.core.RedisTemplate;

import java.util.concurrent.TimeUnit;

/**
 * Description: Redis的String类型操作
 *
 * @Author sun
 * @Create 2024/11/14 14:50
 * @Version 1.1
 */
public class RString extends RBase {

    /**
     * 构造器给父类注入RedisTemplate
     *
     * @param redisTemplate RedisTemplate实例
     */
    public RString(RedisTemplate<String, Object> redisTemplate) {
        super(redisTemplate);
    }

    /**
     * 设置缓存值
     *
     * @param key   键
     * @param value 值
     */
    public void set(String key, Object value) {
        validateKeyAndValue(key, value);
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 设置缓存值并设置过期时间
     *
     * @param key     键
     * @param value   值
     * @param timeout 过期时间
     * @param unit    时间单位
     */
    public void setWithExpire(String key, Object value, final long timeout, final TimeUnit unit) {
        validateKeyAndValue(key, value);
        validateTimeoutAndUnit(timeout, unit);
        redisTemplate.opsForValue().set(key, value, timeout, unit);
    }

    /**
     * 设置缓存值并设置过期时间(单位:秒)
     *
     * @param key     键
     * @param value   值
     * @param timeout 过期时间
     */
    public void setWithExpire(String key, Object value, final long timeout) {
        setWithExpire(key, value, timeout, TimeUnit.SECONDS);
    }

    /**
     * 设置缓存值,如果key不存在,则设置成功,并指定过期时间
     *
     * @param key     键
     * @param value   值
     * @param timeout 过期时间
     * @param unit    时间单位
     * @return 是否设置成功
     */
    public Boolean setIfAbsent(String key, Object value, long timeout, TimeUnit unit) {
        validateKeyAndValue(key, value);
        validateTimeoutAndUnit(timeout, unit);
        return redisTemplate.opsForValue().setIfAbsent(key, value, timeout, unit);
    }

    /**
     * 设置缓存值,如果key不存在,则设置成功,并指定过期时间(单位:秒)
     *
     * @param key     键
     * @param value   值
     * @param timeout 过期时间
     * @return 是否设置成功
     */
    public Boolean setIfAbsent(String key, Object value, long timeout) {
        return setIfAbsent(key, value, timeout, TimeUnit.SECONDS);
    }

    /**
     * 获取缓存值并进行类型转换
     *
     * @param key  键
     * @param type 返回值的类型
     * @return 转换后的对象,若类型不匹配则抛出异常
     */
    public <T> T get(String key, Class<T> type) {
        Object value = redisTemplate.opsForValue().get(key);
        return convertValue(value, type);
    }

    /**
     * 获取缓存值并设置新值
     *
     * @param key   键
     * @param value 新值
     * @param type  返回值的类型
     * @param <T>   返回值的类型
     * @return 旧值,类型为 T
     */
    public <T> T getAndSet(String key, T value, Class<T> type) {
        Object oldValue = redisTemplate.opsForValue().getAndSet(key, value);
        return convertValue(oldValue, type);
    }

    /**
     * 根据 delta 值调整缓存中的数值
     *
     * @param key   键
     * @param delta 调整步长,正数表示增加,负数表示减少
     * @return 调整后的值
     */
    public Long changeByDelta(String key, long delta) {
        if (key == null) {
            throw new IllegalArgumentException("Key 不能为空!");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 验证键和值的合法性
     */
    private void validateKeyAndValue(String key, Object value) {
        if (key == null || value == null) {
            throw new IllegalArgumentException("Key 和 Value 不能为空!");
        }
    }

    /**
     * 验证超时时间和单位的合法性
     */
    private void validateTimeoutAndUnit(long timeout, TimeUnit unit) {
        if (timeout <= 0 || unit == null) {
            throw new IllegalArgumentException("超时时间必须大于 0,时间单位不能为空!");
        }
    }
}
3.RList.java
package com.sunxiansheng.redis.utils;

import org.springframework.data.redis.core.RedisTemplate;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * Description: Redis的List类型操作
 *
 * @Author sun
 * @Create 2024/11/14 14:50
 * @Version 1.0
 */
public class RList extends RBase {

    /**
     * 构造器给父类注入RedisTemplate
     *
     * @param redisTemplate RedisTemplate实例
     */
    public RList(RedisTemplate<String, Object> redisTemplate) {
        super(redisTemplate);
    }

    /**
     * 左侧添加单个值
     *
     * @param key   键
     * @param value 要添加的值
     * @return 添加后的List长度
     */
    public Long leftPush(String key, Object value) {
        return redisTemplate.opsForList().leftPush(key, value);
    }

    /**
     * 左侧批量添加多个值(使用List参数方式)
     *
     * @param key      键
     * @param dataList 要添加的值列表
     * @param <V>      值类型
     * @return 添加后的List长度,调用方可以忽略返回值
     */
    public <V> Long leftPushAll(String key, List<V> dataList) {
        return redisTemplate.opsForList().leftPushAll(key, dataList.toArray());
    }

    /**
     * 左侧批量添加多个值(使用Collection参数方式)
     *
     * @param key           键
     * @param dataCollection 要添加的值集合
     * @param <V>           值类型
     * @return 添加后的List长度
     */
    public <V> Long leftPushAll(String key, Collection<V> dataCollection) {
        return redisTemplate.opsForList().leftPushAll(key, dataCollection.toArray());
    }

    /**
     * 右侧添加单个值
     *
     * @param key   键
     * @param value 要添加的值
     * @return 添加后的List长度
     */
    public Long rightPush(String key, Object value) {
        return redisTemplate.opsForList().rightPush(key, value);
    }

    /**
     * 右侧批量添加多个值(使用List参数方式)
     *
     * @param key      键
     * @param dataList 要添加的值列表
     * @param <V>      值类型
     * @return 添加后的List长度
     */
    public <V> Long rightPushAll(String key, List<V> dataList) {
        return redisTemplate.opsForList().rightPushAll(key, dataList.toArray());
    }

    /**
     * 右侧批量添加多个值(使用Collection参数方式)
     *
     * @param key           键
     * @param dataCollection 要添加的值集合
     * @param <V>           值类型
     * @return 添加后的List长度
     */
    public <V> Long rightPushAll(String key, Collection<V> dataCollection) {
        return redisTemplate.opsForList().rightPushAll(key, dataCollection.toArray());
    }

    /**
     * 根据值移除指定数量的匹配元素
     *
     * @param key   键
     * @param count 要移除的元素数量
     * @param value 要移除的值
     * @return 移除的元素数量
     */
    public Long removeByValue(String key, long count, Object value) {
        return redisTemplate.opsForList().remove(key, count, value);
    }

    /**
     * 从右侧弹出元素并转换为指定类型
     *
     * @param key  键
     * @param type 期望的返回值类型
     * @param <T>  泛型,表示期望的返回类型
     * @return 弹出并转换后的元素
     */
    public <T> T popRight(String key, Class<T> type) {
        Object value = redisTemplate.opsForList().rightPop(key);
        return convertValue(value, type);
    }

    /**
     * 从左侧弹出元素并转换为指定类型
     *
     * @param key  键
     * @param type 期望的返回值类型
     * @param <T>  泛型,表示期望的返回类型
     * @return 弹出并转换后的元素
     */
    public <T> T popLeft(String key, Class<T> type) {
        Object value = redisTemplate.opsForList().leftPop(key);
        return convertValue(value, type);
    }

    /**
     * 根据索引设置List中的值
     *
     * @param key   键
     * @param index 索引位置,从0开始
     * @param value 设置的值
     */
    public void set(String key, final long index, Object value) {
        redisTemplate.opsForList().set(key, index, value);
    }

    /**
     * 获取List中的所有数据,并将每个元素转换为指定类型
     *
     * @param key  键
     * @param type 要转换的值类型
     * @param <T>  要转换的值类型
     * @return 转换后的List
     */
    public <T> List<T> rangeAll(String key, Class<T> type) {
        List<Object> range = redisTemplate.opsForList().range(key, 0, -1);
        List<T> result = new ArrayList<>();

        if (range != null) {
            for (Object item : range) {
                result.add(convertValue(item, type));
            }
        }
        return result;
    }

    /**
     * 根据索引获取List中的元素并转换为指定类型
     *
     * @param key   键
     * @param index 索引位置,从0开始
     * @param type  期望的返回值类型
     * @param <T>   泛型,表示期望的返回类型
     * @return 转换后的元素
     */
    public <T> T getElementByIndex(String key, long index, Class<T> type) {
        Object value = redisTemplate.opsForList().index(key, index);
        return convertValue(value, type);
    }

    /**
     * 获取List的长度
     *
     * @param key 键
     * @return List的长度
     */
    public Long size(String key) {
        return redisTemplate.opsForList().size(key);
    }
}
4.RSet.java
package com.sunxiansheng.redis.utils;

import org.springframework.data.redis.core.RedisTemplate;

import java.util.HashSet;
import java.util.Set;

/**
 * Description: Redis的Set类型操作
 *
 * @Author sun
 * @Create 2024/11/14 14:50
 * @Version 1.0
 */
public class RSet extends RBase {

    /**
     * 构造器给父类注入RedisTemplate
     *
     * @param redisTemplate RedisTemplate实例
     */
    public RSet(RedisTemplate<String, Object> redisTemplate) {
        super(redisTemplate);
    }

    /**
     * 添加一个元素
     *
     * @param key  键
     * @param data 值
     * @return 添加成功的个数
     */
    public Long add(String key, Object data) {
        return redisTemplate.opsForSet().add(key, data);
    }

    /**
     * 批量添加元素,并返回添加成功的个数
     *
     * @param key     键
     * @param dataSet 值集合
     * @param <T>     添加的元素类型
     * @return 添加成功的个数
     */
    public <T> Long addBatch(String key, Set<T> dataSet) {
        return redisTemplate.opsForSet().add(key, dataSet.toArray());
    }

    /**
     * 移除特定的元素,并返回移除成功的个数
     *
     * @param key     键
     * @param dataSet 要移除的元素集合
     * @param <T>     要移除的元素类型
     * @return 移除成功的个数
     */
    public <T> Long remove(String key, Set<T> dataSet) {
        return redisTemplate.opsForSet().remove(key, dataSet.toArray());
    }

    /**
     * 获取集合,并将每个元素转换为指定类型
     *
     * @param key  键
     * @param type 集合中元素的目标类型
     * @param <T>  元素的类型
     * @return 转换后的集合
     */
    public <T> Set<T> members(String key, Class<T> type) {
        Set<Object> members = redisTemplate.opsForSet().members(key);
        Set<T> result = new HashSet<>();

        if (members != null) {
            for (Object member : members) {
                result.add(convertValue(member, type));
            }
        }
        return result;
    }

    /**
     * 判断集合中是否有该值
     *
     * @param key  键
     * @param data 值
     * @return 是否包含该值
     */
    public Boolean isMember(String key, Object data) {
        return redisTemplate.opsForSet().isMember(key, data);
    }

    /**
     * 获取set的长度
     *
     * @param key 键
     * @return 集合的长度
     */
    public Long size(String key) {
        return redisTemplate.opsForSet().size(key);
    }
}
5.RHash.java
package com.sunxiansheng.redis.utils;

import org.springframework.data.redis.core.RedisTemplate;

import java.util.*;

/**
 * Description: Redis的Hash类型操作
 *
 * @Author sun
 * @Create 2024/11/14 14:50
 * @Version 1.1
 */
public class RHash extends RBase {

    /**
     * 构造器给父类注入RedisTemplate
     *
     * @param redisTemplate RedisTemplate实例
     */
    public RHash(RedisTemplate<String, Object> redisTemplate) {
        super(redisTemplate);
    }

    /**
     * 设置单个hash值
     *
     * @param key       key
     * @param hashKey   hashKey
     * @param hashValue hashValue
     */
    public void put(String key, String hashKey, Object hashValue) {
        redisTemplate.opsForHash().put(key, hashKey, hashValue);
    }

    /**
     * 设置多个hash值
     *
     * @param key key
     * @param map map
     */
    public void putAll(String key, Map<String, ?> map) {
        if (map == null || map.isEmpty()) {
            throw new IllegalArgumentException("Map不能为空!");
        }
        redisTemplate.opsForHash().putAll(key, map);
    }

    /**
     * 删除hash中的一些值
     *
     * @param key      key
     * @param hashKeys hashKeys
     * @return 删除的个数
     */
    public Long delete(String key, List<String> hashKeys) {
        if (hashKeys == null || hashKeys.isEmpty()) {
            return 0L;
        }
        return redisTemplate.opsForHash().delete(key, hashKeys.toArray());
    }

    /**
     * 删除hash中的一个值
     *
     * @param key     key
     * @param hashKey hashKey
     * @return 删除的个数
     */
    public Long delete(String key, String hashKey) {
        if (hashKey == null) {
            return 0L;
        }
        return redisTemplate.opsForHash().delete(key, hashKey);
    }

    /**
     * 获取单个hash值,并转换为指定类型
     *
     * @param key     key
     * @param hashKey hashKey
     * @param type    类型
     * @param <T>     要转换的类型
     * @return hash值
     */
    public <T> T getOneMapValue(String key, String hashKey, Class<T> type) {
        if (hashKey == null) {
            return null;
        }
        Object object = redisTemplate.opsForHash().get(key, hashKey);
        return convertValue(object, type);
    }

    /**
     * 获取多个hash值,并转换为指定类型
     *
     * @param key      Redis键
     * @param hashKeys Hash键集合
     * @param type     转换的目标类型
     * @param <T>      返回的泛型类型
     * @return 转换后的Hash对象集合
     */
    public <T> List<T> getMultiMapValue(String key, Collection<String> hashKeys, Class<T> type) {
        if (hashKeys == null || hashKeys.isEmpty()) {
            return Collections.emptyList();
        }

        Collection<Object> keys = new ArrayList<>(hashKeys);
        List<Object> objects = redisTemplate.opsForHash().multiGet(key, keys);

        List<T> result = new ArrayList<>();
        for (Object obj : objects) {
            result.add(convertValue(obj, type));
        }
        return result;
    }

    /**
     * 获取所有键值对,并将其转换为指定类型
     *
     * @param key  键
     * @param type 返回值的类型
     * @param <T>  值类型
     * @return 转换后的Map,键为String类型,值为T类型
     */
    public <T> Map<String, T> getAll(String key, Class<T> type) {
        Map<Object, Object> entries = redisTemplate.opsForHash().entries(key);

        if (entries.isEmpty()) {
            return Collections.emptyMap();
        }

        Map<String, T> result = new HashMap<>();
        for (Map.Entry<Object, Object> entry : entries.entrySet()) {
            if (entry.getKey() instanceof String) {
                String strKey = (String) entry.getKey();
                T value = convertValue(entry.getValue(), type);
                result.put(strKey, value);
            } else {
                throw new ClassCastException("Redis中Hash的键不是String类型:实际类型为 " + entry.getKey().getClass().getName());
            }
        }
        return result;
    }

    /**
     * 判断hash中是否存在某个键
     *
     * @param key     key
     * @param hashKey hashKey
     * @return 是否存在
     */
    public Boolean hasHashKey(String key, String hashKey) {
        if (hashKey == null) {
            return false;
        }
        return redisTemplate.opsForHash().hasKey(key, hashKey);
    }
}
6.RSortedSet.java
package com.sunxiansheng.redis.utils;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;

import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;

/**
 * Description: Redis的ZSet类型操作
 *
 * @Author sun
 * @Create 2024/11/14 14:50
 * @Version 1.0
 */
public class RSortedSet extends RBase {

    /**
     * 构造器给父类注入RedisTemplate
     *
     * @param redisTemplate RedisTemplate实例
     */
    public RSortedSet(RedisTemplate<String, Object> redisTemplate) {
        super(redisTemplate);
    }

    /**
     * 添加一个元素,并设置分数
     *
     * @param key   键
     * @param data  元素
     * @param score 分数
     * @return 是否添加成功,成功返回true
     */
    public Boolean add(String key, Object data, double score) {
        return redisTemplate.opsForZSet().add(key, data, score);
    }

    /**
     * 自定义的数据分数类型,用于批量添加元素
     *
     * @param <T> 元素的类型
     */
    public static class DataScore<T> {
        /**
         * 数据
         */
        private T data;
        /**
         * 分数
         */
        private Double score;

        public DataScore() {
        }

        public DataScore(T data, Double score) {
            this.data = data;
            this.score = score;
        }

        public T getData() {
            return data;
        }

        public void setData(T data) {
            this.data = data;
        }

        public Double getScore() {
            return score;
        }

        public void setScore(Double score) {
            this.score = score;
        }
    }

    /**
     * 批量添加元素,并设置分数
     *
     * @param key        键
     * @param dataScores 自定义数据结构集合,包含元素及分数
     * @param <T>        元素的类型
     * @return 添加成功的元素数量
     */
    public <T> Long addBatch(String key, Set<DataScore<T>> dataScores) {
        // 将 Set<DataScore<T>> 转换为 Set<ZSetOperations.TypedTuple<Object>>
        Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<>();
        for (DataScore<T> dataScore : dataScores) {
            tuples.add(new ZSetOperations.TypedTuple<Object>() {
                @Override
                public Object getValue() {
                    return dataScore.getData(); // 调用 getData 方法
                }

                @Override
                public Double getScore() {
                    return dataScore.getScore();
                }

                /**
                 * 比较器,从大到小排序
                 */
                @Override
                public int compareTo(ZSetOperations.TypedTuple<Object> o) {
                    return Double.compare(o.getScore(), this.getScore());
                }
            });
        }

        // 添加到 Redis 的 ZSet
        return redisTemplate.opsForZSet().add(key, tuples);
    }

    /**
     * 移除特定的元素
     *
     * @param key     键
     * @param dataSet 要移除的元素集合
     * @param <T>     元素类型
     * @return 移除成功的元素数量
     */
    public <T> Long remove(String key, Set<T> dataSet) {
        return redisTemplate.opsForZSet().remove(key, dataSet.toArray());
    }

    /**
     * 删除指定分数范围的元素
     *
     * @param key 键
     * @param min 最小分数
     * @param max 最大分数
     * @return 删除成功的元素数量
     */
    public Long removeRangeByScore(String key, double min, double max) {
        return redisTemplate.opsForZSet().removeRangeByScore(key, min, max);
    }

    /**
     * 根据delta值调整指定元素的分数
     *
     * @param key   键
     * @param data  元素
     * @param delta 增加或减少的分数值
     * @return 调整后的分数
     */
    public Double changeByDelta(String key, Object data, double delta) {
        return redisTemplate.opsForZSet().incrementScore(key, data, delta);
    }

    /**
     * 获取全部ZSet元素(分数从大到小),并将值转换为指定类型
     *
     * @param key  Redis键
     * @param type 元素的目标类型
     * @param <T>  元素类型
     * @return 转换后的ZSet集合,包含分值和对应的值
     */
    public <T> Set<ZSetOperations.TypedTuple<T>> reverseRangeWithScores(String key, Class<T> type) {
        // 获取 Redis 中的 ZSet 数据
        Set<ZSetOperations.TypedTuple<Object>> typedTuples = redisTemplate.opsForZSet().reverseRangeWithScores(key, 0, -1);
        // 使用 TreeSet 并提供自定义比较器,从大到小排序
        Set<ZSetOperations.TypedTuple<T>> result = new TreeSet<>((a, b) -> Double.compare(b.getScore(), a.getScore()));

        // 遍历并进行类型转换
        if (typedTuples != null) {
            for (ZSetOperations.TypedTuple<Object> tuple : typedTuples) {
                T value = convertValue(tuple.getValue(), type);
                Double score = tuple.getScore();
                result.add(new ZSetOperations.TypedTuple<T>() {
                    @Override
                    public T getValue() {
                        return value;
                    }

                    @Override
                    public Double getScore() {
                        return score;
                    }

                    /**
                     * 比较器,从大到小排序
                     */
                    @Override
                    public int compareTo(ZSetOperations.TypedTuple<T> o) {
                        return Double.compare(o.getScore(), this.getScore());
                    }
                });
            }
        }
        return result;
    }

    /**
     * 获取指定元素的分数
     *
     * @param key  键
     * @param data 元素
     * @return 元素的分数
     */
    public Double score(String key, Object data) {
        return redisTemplate.opsForZSet().score(key, data);
    }

    /**
     * 获取指定元素的排名(从大到小)
     *
     * @param key  键
     * @param data 元素
     * @return 排名(从0开始)
     */
    public Long reverseRank(String key, Object data) {
        return redisTemplate.boundZSetOps(key).reverseRank(data);
    }

    /**
     * 获取ZSet中的元素总数
     *
     * @param key 键
     * @return 元素个数
     */
    public Long zCard(String key) {
        return redisTemplate.opsForZSet().zCard(key);
    }

    /**
     * 获取指定分数范围内的元素数量
     *
     * @param key 键
     * @param min 最小分数
     * @param max 最大分数
     * @return 元素数量
     */
    public Long count(String key, double min, double max) {
        return redisTemplate.opsForZSet().count(key, min, max);
    }
}

4.测试

1.创建测试模块

CleanShot 2024-11-15 at 20.55.07@2x

2.引入依赖
<?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.sunxiansheng</groupId>
        <artifactId>sunrays-demo</artifactId>
        <version>1.0</version>
    </parent>

    <artifactId>common-redis-starter-demo</artifactId>

    <dependencies>
        <!-- 引入自定义的 common-redis-starter -->
        <dependency>
            <groupId>com.sunxiansheng</groupId>
            <artifactId>common-redis-starter</artifactId>
            <version>1.0</version>
        </dependency>
        <!-- 引入自定义的 common-log4j2-starter -->
        <dependency>
            <groupId>com.sunxiansheng</groupId>
            <artifactId>common-log4j2-starter</artifactId>
            <version>1.0</version>
        </dependency>
        <!-- 引入自定义的 common-web-starter -->
        <dependency>
            <groupId>com.sunxiansheng</groupId>
            <artifactId>common-web-starter</artifactId>
            <version>1.0</version>
        </dependency>
    </dependencies>

</project>
3.启动类
package com.sunxiansheng.redis;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Description: Redis启动类
 *
 * @Author sun
 * @Create 2024/11/15 20:56
 * @Version 1.0
 */
@SpringBootApplication
public class RedisApplication {

    public static void main(String[] args) {
        SpringApplication.run(RedisApplication.class, args);
    }
}

CleanShot 2024-11-15 at 21.01.33@2x

4.编写application.yml
spring:
  redis:
    host:  # Redis服务器地址
    port:  # Redis服务器端口
    password:  # Redis服务器密码
    database: 0 # 默认数据库为0号
    timeout: 1800000 # 连接超时时间是1800秒
    lettuce:
      pool:
        max-active: 20 # 最大活跃连接数,使用负值表示没有限制
        max-wait: -1 # 最大等待时间,单位为毫秒,使用负值表示没有限制
        max-idle: 10 # 最大空闲连接数
        min-idle: 0 # 最小空闲连接数
5.测试
1.RStringController.java
package com.sunxiansheng.redis.controller;

import com.sunxiansheng.redis.utils.RString;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * Description: 测试 RString 工具类的 Controller
 *
 * @Author sun
 * @Create 2024/11/14 15:20
 * @Version 1.0
 */
@RestController
@RequestMapping("/rstring")
public class RStringController {

    @Resource
    private RString rString;

    /**
     * 设置缓存值
     */
    @PostMapping("/set")
    public String set(@RequestParam String key, @RequestParam Long value) {
        rString.set(key, value);
        return "Value set successfully!";
    }

    /**
     * 设置缓存值并设置过期时间
     */
    @PostMapping("/setWithExpire")
    public String setWithExpire(@RequestParam String key,
                                @RequestParam Long value,
                                @RequestParam long timeout) {
        rString.setWithExpire(key, value, timeout);
        return "Value set with expiration successfully!";
    }

    /**
     * 设置缓存值并设置过期时间(自定义时间单位)
     */
    @PostMapping("/setWithExpireUnit")
    public String setWithExpireUnit(@RequestParam String key,
                                    @RequestParam Long value,
                                    @RequestParam long timeout) {
        rString.setWithExpire(key, value, timeout, TimeUnit.DAYS);
        return "Value set with custom expiration successfully!";
    }

    /**
     * 设置缓存值,如果key不存在,则设置成功
     */
    @PostMapping("/setIfAbsent")
    public String setIfAbsent(@RequestParam String key,
                              @RequestParam Long value,
                              @RequestParam long timeout) {
        boolean result = rString.setIfAbsent(key, value, timeout);
        return result ? "Value set successfully!" : "Key already exists!";
    }

    /**
     * 获取缓存值
     */
    @GetMapping("/get")
    public Long get(@RequestParam String key) {
        return rString.get(key, Long.class);
    }

    /**
     * 获取缓存值并设置新值
     */
    @PostMapping("/getAndSet")
    public Long getAndSet(@RequestParam String key, @RequestParam Long value) {
        return rString.getAndSet(key, value, Long.class);
    }

    /**
     * 根据 delta 值调整缓存中的数值
     */
    @PostMapping("/changeByDelta")
    public Long changeByDelta(@RequestParam String key, @RequestParam long delta) {
        return rString.changeByDelta(key, delta);
    }
}
2.RListController.java
package com.sunxiansheng.redis.controller;

import com.sunxiansheng.redis.utils.RList;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * 测试 RList 工具类的 Controller
 *
 * @Author sun
 * @Create 2024/11/14 16:00
 * @Version 1.0
 */
@RestController
@RequestMapping("/rlist")
public class RListController {

    @Autowired
    private RList rList;

    /**
     * 左侧添加单个值
     */
    @PostMapping("/leftPush")
    public String leftPush(@RequestParam String key, @RequestBody User user) {
        rList.leftPush(key, user);
        return "User added to the left of the list.";
    }

    /**
     * 左侧批量添加多个值
     */
    @PostMapping("/leftPushAll")
    public String leftPushAll(@RequestParam String key, @RequestBody List<User> users) {
        rList.leftPushAll(key, users);
        return "Users added to the left of the list.";
    }

    /**
     * 右侧添加单个值
     */
    @PostMapping("/rightPush")
    public String rightPush(@RequestParam String key, @RequestBody User user) {
        rList.rightPush(key, user);
        return "User added to the right of the list.";
    }

    /**
     * 右侧批量添加多个值
     */
    @PostMapping("/rightPushAll")
    public String rightPushAll(@RequestParam String key, @RequestBody List<User> users) {
        rList.rightPushAll(key, users);
        return "Users added to the right of the list.";
    }

    /**
     * 根据索引设置List中的值
     */
    @PutMapping("/set")
    public String set(@RequestParam String key, @RequestParam int index, @RequestBody User user) {
        rList.set(key, index, user);
        return "User updated at index " + index;
    }

    /**
     * 获取List中的所有数据
     */
    @GetMapping("/rangeAll")
    public List<User> rangeAll(@RequestParam String key) {
        return rList.rangeAll(key, User.class);
    }

    /**
     * 根据索引获取List中的元素
     */
    @GetMapping("/getElementByIndex")
    public User getElementByIndex(@RequestParam String key, @RequestParam int index) {
        return rList.getElementByIndex(key, index, User.class);
    }

    /**
     * 获取List的长度
     */
    @GetMapping("/size")
    public Long size(@RequestParam String key) {
        return rList.size(key);
    }

    /**
     * 从右侧弹出元素
     */
    @DeleteMapping("/popRight")
    public User popRight(@RequestParam String key) {
        return rList.popRight(key, User.class);
    }

    /**
     * 从左侧弹出元素
     */
    @DeleteMapping("/popLeft")
    public User popLeft(@RequestParam String key) {
        return rList.popLeft(key, User.class);
    }

    /**
     * 根据值移除指定数量的匹配元素
     */
    @DeleteMapping("/removeByValue")
    public String removeByValue(@RequestParam String key, @RequestParam int count, @RequestBody User user) {
        Long removedCount = rList.removeByValue(key, count, user);
        return removedCount + " matching users removed.";
    }
}


/**
 * 简单的自定义类型 User
 *
 * @Author sun
 * @Create 2024/11/14 15:50
 * @Version 1.0
 */
@NoArgsConstructor
@Data
@AllArgsConstructor
class User implements java.io.Serializable {
    private String id;
    private String name;
}
3.RSetController.java
package com.sunxiansheng.redis.controller;

import com.sunxiansheng.redis.utils.RSet;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.io.Serializable;
import java.util.Set;

/**
 * Description: RSet的测试Controller
 *
 * @Author sun
 * @Create 2024/11/15
 * @Version 1.0
 */
@RestController
@RequestMapping("/rset")
public class RSetController {

    @Autowired
    private RSet rSet;

    /**
     * 静态内部类表示简单的自定义对象
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Element implements Serializable {
        private Long id;
        private String name;
    }

    /**
     * 添加一个元素
     */
    @PostMapping("/add")
    public Long add(@RequestParam String key, @RequestBody Element element) {
        return rSet.add(key, element);
    }

    /**
     * 批量添加元素
     */
    @PostMapping("/addBatch")
    public Long addBatch(@RequestParam String key, @RequestBody Set<Element> elements) {
        return rSet.addBatch(key, elements);
    }

    /**
     * 移除元素
     */
    @PostMapping("/remove")
    public Long remove(@RequestParam String key, @RequestBody Set<Element> elements) {
        return rSet.remove(key, elements);
    }

    /**
     * 获取集合
     */
    @GetMapping("/members")
    public Set<Element> members(@RequestParam String key) {
        return rSet.members(key, Element.class);
    }

    /**
     * 判断是否包含某元素
     */
    @GetMapping("/isMember")
    public Boolean isMember(@RequestParam String key, @RequestBody Element element) {
        return rSet.isMember(key, element);
    }

    /**
     * 获取集合大小
     */
    @GetMapping("/size")
    public Long size(@RequestParam String key) {
        return rSet.size(key);
    }
}
4.RHashController.java
package com.sunxiansheng.redis.controller;

import com.sunxiansheng.redis.utils.RHash;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.web.bind.annotation.*;

import java.util.*;

@RestController
@RequestMapping("/rhash")
public class RHashController {

    private final RHash rHash;

    public RHashController(RHash rHash) {
        this.rHash = rHash;
    }

    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    public static class User {
        private Long id;
        private String name;
        private Integer age;
    }

    /**
     * 设置单个hash值
     */
    @PostMapping("/put")
    public void put(@RequestParam String key, @RequestParam String hashKey, @RequestBody User user) {
        rHash.put(key, hashKey, user);
    }

    /**
     * 设置多个hash值
     */
    @PostMapping("/putAll")
    public void putAll(@RequestParam String key, @RequestBody Map<String, User> userMap) {
        rHash.putAll(key, userMap);
    }

    /**
     * 删除hash中的多个值
     */
    @DeleteMapping("/deleteMultiple")
    public Long deleteMultiple(@RequestParam String key, @RequestBody List<String> hashKeys) {
        return rHash.delete(key, hashKeys);
    }

    /**
     * 删除hash中的单个值
     */
    @DeleteMapping("/deleteSingle")
    public Long deleteSingle(@RequestParam String key, @RequestParam String hashKey) {
        return rHash.delete(key, hashKey);
    }

    /**
     * 获取单个hash值并转换为指定类型
     */
    @GetMapping("/getOne")
    public User getOneMapValue(@RequestParam String key, @RequestParam String hashKey) {
        return rHash.getOneMapValue(key, hashKey, User.class);
    }

    /**
     * 获取多个hash值并转换为指定类型
     */
    @GetMapping("/getMulti")
    public List<User> getMultiMapValue(@RequestParam String key, @RequestBody List<String> hashKeys) {
        return rHash.getMultiMapValue(key, hashKeys, User.class);
    }

    /**
     * 获取所有键值对并转换为指定类型
     */
    @GetMapping("/getAll")
    public Map<String, User> getAll(@RequestParam String key) {
        return rHash.getAll(key, User.class);
    }

    /**
     * 判断hash中是否存在某个键
     */
    @GetMapping("/hasHashKey")
    public Boolean hasHashKey(@RequestParam String key, @RequestParam String hashKey) {
        return rHash.hasHashKey(key, hashKey);
    }
}
5.RSortedSetController.java
package com.sunxiansheng.redis.controller;

import com.sunxiansheng.redis.utils.RSortedSet;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.web.bind.annotation.*;

import java.util.Set;

/**
 * Description: 测试 RSortedSet 工具类
 *
 * @Author sun
 * @Create 2024/11/16
 * @Version 1.0
 */
@RestController
@RequestMapping("/rsortedset")
public class RSortedSetController {

    @Autowired
    private RSortedSet rSortedSet;

    // 自定义类型
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class CustomValue {
        private Long id;
        private String name;
    }

    @PostMapping("/add")
    public Boolean add(@RequestParam String key, @RequestBody CustomValue value, @RequestParam double score) {
        return rSortedSet.add(key, value, score);
    }

    @PostMapping("/addBatch")
    public Long addBatch(@RequestParam String key, @RequestBody Set<RSortedSet.DataScore<CustomValue>> dataScores) {
        return rSortedSet.addBatch(key, dataScores);
    }

    @PostMapping("/remove")
    public Long remove(@RequestParam String key, @RequestBody Set<CustomValue> values) {
        return rSortedSet.remove(key, values);
    }

    @PostMapping("/removeRangeByScore")
    public Long removeRangeByScore(@RequestParam String key, @RequestParam double min, @RequestParam double max) {
        return rSortedSet.removeRangeByScore(key, min, max);
    }

    @PostMapping("/changeByDelta")
    public Double changeByDelta(@RequestParam String key, @RequestBody CustomValue value, @RequestParam double delta) {
        return rSortedSet.changeByDelta(key, value, delta);
    }

    @GetMapping("/reverseRangeWithScores")
    public Set<ZSetOperations.TypedTuple<CustomValue>> reverseRangeWithScores(@RequestParam String key) {
        return rSortedSet.reverseRangeWithScores(key, CustomValue.class);
    }

    @GetMapping("/score")
    public Double score(@RequestParam String key, @RequestBody CustomValue value) {
        return rSortedSet.score(key, value);
    }

    @GetMapping("/reverseRank")
    public Long reverseRank(@RequestParam String key, @RequestBody CustomValue value) {
        return rSortedSet.reverseRank(key, value);
    }

    @GetMapping("/zCard")
    public Long zCard(@RequestParam String key) {
        return rSortedSet.zCard(key);
    }

    @GetMapping("/count")
    public Long count(@RequestParam String key, @RequestParam double min, @RequestParam double max) {
        return rSortedSet.count(key, min, max);
    }
}

原文地址:https://blog.csdn.net/m0_64637029/article/details/145191503

免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!