Redis——(自定义工具类&Redis的Java配置类)

一、Redis自定义工具类

1.1 工具类

/**
 * @Description 操作redis键值的工具类
 */
@Component
public class RedisUtil {

    @Autowired
    private RedisTemplate redisTemplate;

    /***************key的通用操作**************************/
    /**
     * [key]设置 key 的过期时间
     * @param key 键
     * @param time	过期时间(秒)
     * @return	操作是否成功
     */
    private boolean expire(String key, long time) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * [key]根据 key 获取过期时间
     * @param key 键 不能为null
     * @return 时间(秒)
     */
    public long getExpire(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * [key]判断 key 是否存在
     * @param key 键
     * @return true 存在;false不存在
     */
    public boolean hasKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * [key]删除指定的 key
     * @param keys 可以传一个或多个待删除的key
     */
    public void del(String... keys) {
        if (keys != null && keys.length > 0) {
            if (keys.length == 1) {
                redisTemplate.delete(keys[0]);
            } else {
                redisTemplate.delete(CollectionUtils.arrayToList(keys));
            }
        }
    }

    /***************String类型操作**************************/
    /**
     * [String]根据 key 获取值其 value
     * @param key 键
     * @return 键对应的值
     */
    public Object get(String key) {
        return key == null ? null : redisTemplate.boundValueOps(key).get();
    }

    /**
     * [String]根据key 存入 value
     * @param key 操作的键
     * @param value 值
     */
    public void set(String key, Object value) {
        redisTemplate.boundValueOps(key).set(value);
    }

    /**
     * [String]根据key 存入 value,并设置过期时间
     * @param key 键
     * @param value 值
     * @param time 过期时间(秒)
     */
    public void set(String key, Object value, long time) {
        redisTemplate.boundValueOps(key).set(value, time, TimeUnit.SECONDS);
    }

    /**
     * [String]为键 key 储存的数字值加上一。
     * 1.如果键 key 不存在, 那么它的值会先被初始化为 0 , 然后再执行 INCR 命令。
     * 2.如果键 key 储存的值不能被解释为数字, 那么 INCR 命令将返回一个错误。
     *
     * @param key  键
     * @param data 要增加的数值(>=1)
     * @return 该命令会返回键 key 在执行加一操作之后的值。
     */
    public long incr(String key, Long data) {
        BoundValueOperations opt = redisTemplate.boundValueOps(key);
        try {
            int i = Integer.parseInt(data.toString());
            if (i <=0){
                throw new RuntimeException("递增数值要大于1,且不能为负数");
            }else {
                return redisTemplate.boundValueOps(key).increment(data);
            }
        } catch (NumberFormatException e) {
            throw new RuntimeException("值必须是数字,才能执行递增");
        }
    }

    /**
     * [String]为键 key 储存的数字值减去一。
     * 1.如果键 key 不存在, 那么键 key 的值会先被初始化为 0 , 然后再执行 DECR 操作。
     * 2.如果键 key 储存的值不能被解释为数字, 那么 DECR 命令将返回一个错误。
     *
     * @param key  键
     * @param data 要减少的数值(>=1)
     * @return 该命令会返回键 key 在执行减一操作之后的值。
     */
    public long decr(String key, Long data) {
        BoundValueOperations opt = redisTemplate.boundValueOps(key);
        try {
            int i = Integer.parseInt(data.toString());
            if (i <= 0){
                throw new RuntimeException("递减数值要大于1,且不能为负数");
            }else {
                return redisTemplate.boundValueOps(key).decrement(data);
            }
        } catch (NumberFormatException e) {
            throw new RuntimeException("值必须是数字,才能执行递减");
        }
    }

    /**
     * [String]同时为多个键设置值。
     * 1.如果某个给定键已经存在, 那么 MSET 将使用新值去覆盖旧值,
     *
     * @param keyValueMap
     * @return OK
     */
    public String mSet(Map<String,Object> keyValueMap){
        if (keyValueMap.size() == 0){
            throw new RuntimeException("map集合为空!!!");
        }else {
            for (Map.Entry<String, Object> entry : keyValueMap.entrySet()) {
                BoundValueOperations ops = redisTemplate.boundValueOps(entry.getKey());
                ops.set(entry.getValue());
            }
            return "OK";
        }
    }

    /**
     * [String]返回给定的一个或多个字符串键和对应的值。(key-value)
     *
     * @param keyList key的集合
     * @return 此命令将返回一个集合列表, 列表中包含了所有给定键和值。
     */
    public Map<String,Object> mGet(List<String> keyList){
        Map<String,Object> keyValueMap = new LinkedHashMap<>();
        for (String key : keyList) {
            Object value = redisTemplate.boundValueOps(key).get();
            keyValueMap.put(key,value);
        }
        return keyValueMap;
    }

    /***************Set类型操作**************************/
    /**
     * [Set]根据key获取Set中的所有成员
     *
     * @param key 键
     * @return 集合中的所有成员
     */
    public Set sMembers(String key) {
        try {
            return redisTemplate.boundSetOps(key).members();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * [Set]判断 value 元素是否集合 key 的成员。
     * 1.如果 member 元素是集合的成员,返回 true 。
     * 2.如果 member 元素不是集合的成员,或 key 不存在,返回 false 。
     *
     * @param key 要查询的 key
     * @param value 要查询的key集合中的成员
     * @return true或false
     */
    public boolean sIsMember(String key, Object value) {
        try {
            return redisTemplate.boundSetOps(key).isMember(value);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * [Set]将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。
     * 1.假如 key 不存在,则创建一个只包含 member 元素作成员的集合。
     * 2.当 key 不是集合类型时,返回一个错误。
     *
     * @param key    键
     * @param values 值 (可以是多个)
     * @return 成功个数
     */
    public long sAdd(String key, Object... values) {
        try {
            return redisTemplate.boundSetOps(key).add(values);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * [Set]将一个或多个 member 元素加入到集合 key 当中,并设置有效时间,已经存在于集合的 member 元素将被忽略。
     * 1.假如 key 不存在,则创建一个只包含 member 元素作成员的集合。
     * 2.当 key 不是集合类型时,返回一个错误。
     *
     * @param key 键
     * @param time 过期时间(秒)
     * @param values 值(可以有多个)
     * @return 成功的个数
     */
    public long sAdd(String key, long time, Object... values) {
        try {
            Long count = redisTemplate.boundSetOps(key).add(values);
            this.expire(key, time);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * [Set]返回集合 key 的基数(集合中元素的数量)。
     *
     * @param key 键
     * @return 集合的基数。 当 key 不存在时,返回 0 。
     */
    public long sCard(String key) {
        try {
            return redisTemplate.boundSetOps(key).size();
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * [Set]移除集合 key 中的一个或多个 value 元素,不存在的 value 元素会被忽略。
     * 1.当 key 不是集合类型,返回一个错误。
     *
     * @param key    键
     * @param values 值(可以是多个)
     * @return 被成功移除的元素的数量,不包括被忽略的元素。
     */
    public long sRemove(String key, Object... values) {
        try {
            Long count = redisTemplate.boundSetOps(key).remove(values);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /***************List类型操作**************************/
    /**
     * [List]从绑定键的列表中获取begin和end之间的元素。
     * 1.负数下标:-1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
     *
     * @param key   键
     * @param start 开始下标(从0开始)
     * @param end   结束下标(-1:最后一个元素)
     * @return
     */
    public List lRange(String key, long start, long end) {
        try {
            return redisTemplate.boundListOps(key).range(start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * [List]获取列表 key 的长度。
     * 1.如果 key 不存在,则 key 被解释为一个空列表,返回 0 .
     * 2.如果 key 不是列表类型,返回一个错误。
     *
     * @param key 键
     * @return key列表的长度
     */
    public long lLen(String key) {
        try {
            return redisTemplate.boundListOps(key).size();
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * [List]返回列表 key 中,下标为 index 的元素。
     *
     * @param key   键
     * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;
     *                  index<0时,-1,表尾,-2倒数第二个元素,依次类推
     * @return 列表中下标为 index 的元素。 如果 index 参数的值不在列表的区间范围内(out of range),返回 null 。
     */
    public Object lIndex(String key, long index) {
        try {
            return redisTemplate.boundListOps(key).index(index);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * [List]将一个或多个值 value 插入到列表 key 的表尾(最右边)。
     * 1.如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表尾。
     *
     * @param key 键
     * @param value 要存入的值(一个或多个)
     * @return 执行 RPUSH 操作后,表的长度。
     */
    public long lrRushAll(String key, Object... value) {
        return redisTemplate.boundListOps(key).rightPushAll(value);
    }

    /**
     * [List]将一个或多个值 value 插入到列表 key 的表尾(最右边)。并设置过期时间。
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     * @return
     */
    public void lrRushAll(String key, long time, Object... value) {
        redisTemplate.boundListOps(key).rightPushAll(value);
        //设置过期时间
        this.expire(key, time);
    }

    /**
     * [List]根据索引修改list中的某条数据
     *
     * @param key   键
     * @param index 索引
     * @param value 值
     * @return true/false
     */
    public boolean lUpdateIndex(String key, long index, Object value) {
        try {
            redisTemplate.boundListOps(key).set(index, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * [List]移除N个值为value的成员(从左到右)
     *
     * @param key   键
     * @param count 移除多少个
     * @param value 值
     * @return 移除的个数
     */
    public long lRemove(String key, long count, Object value) {
        try {
            Long remove = redisTemplate.boundListOps(key).remove(count, value);
            return remove;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /***************ZSet类型操作**************************/
    /**
     * [ZSet]将value添加到绑定键的排序集中,或者如果它已经存在则更新其score 。
     *
     * @param key 键
     * @param value 成员
     * @param score 成员的分数
     * @return 是否添加成功
     */
    public Boolean zAdd(String key,Object value,Long score){
        return redisTemplate.boundZSetOps(key).add(value, score);
    }

    /**
     * [ZSet]将value-score的集合添加到绑定键的排序集中,或者如果它已经存在则更新其score 。
     * 1.注意value和score的封装格式,伪代码:List<Map<value,score>>
     *
     * @param key 键
     * @param valueScoreList 要添加的 成员-分数 集合
     * @return 添加成功的个数
     */
    public Long zAdd(String key,List<Map<Object,Long>> valueScoreList){
        Long count = 0L;
        for (Map<Object,Long> map : valueScoreList) {
            for (Map.Entry<Object, Long> entry : map.entrySet()) {
                Boolean isAdd = redisTemplate.boundZSetOps(key).add(entry.getKey(), entry.getValue());
                if (isAdd){
                    count++;
                }
            }
        }
        return count;
    }

    /**
     * [ZSet]返回有序集 key 中,成员 member 的 score 值。
     *
     * @param key 键
     * @param member 指定键对应集合中的成员
     * @return 指定成员的分数
     */
    public Double zScore(String key,Object member){
        return redisTemplate.boundZSetOps(key).score(member);
    }


    /***************Hash类型操作**************************/

}

1.2 工具类的使用测试

@SpringBootTest
class SpringbootRedisPracticeApplicationTests {

    @Autowired
    private RedisUtil redisUtil;

    @Test
    void contextLoads() {
        long count = redisUtil.sadd("city", "wuhan", "hagnzhou", "shagnhai", "anhui");
        System.out.println(count); //4
    }

}

二、Redis的Java配置类

/**
 * @Description redis的配置类,覆盖自动配置的redis配置类中的原有方法
 * @Author cb
 * @Date 2021-11-22 21:23
 **/
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {

    // 在给定对象和 Redis 存储中的底层二进制数据之间执行自动序列化/反序列化。
    // 如果使用自动配置类中的RedisTemplate对象,该对象默认对key和value都采用JDK序列化器来序列化
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        // 构造一个新的RedisTemplate实例。(如果只是操作字符串,还可以用 StringRedisTemplate)
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 设置连接工厂。
        template.setConnectionFactory(factory);
        // 使用Jackson2JsonRedisSerialize 替换默认的jdkSerializeable序列化
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        /**
         * ObjectMapper 提供了读取和写入 JSON 的功能,
         *      可以与基本 POJO(Plain Old Java Objects)
         *      或通用 JSON 树模型 ( JsonNode ) 之间进行读取和写入,以及用于执行转换的相关功能。
         */
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        //简单String到字节 [](和返回)序列化程序。
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }

    //Spring 的中央缓存管理器 SPI。
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        /**
         * 不指定序列化输入类型时存储到redis中的数据将是没有类型的纯json数据,如:
         *      [{"id":72,"name":"ZhangSan"}]
         *
         * 指定序列化输入类型(存储到redis里的数据将是有类型的json数据)
         *      ["java.util.ArrayList",[{"@class":"com.pojo.user","id":72,"name":"ZhangSan"}]]
         *      这样java获取到数据后,将会将数据自动转化为java.util.ArrayList和com.pojo.user,方便直接使用。
         *
         * NON_FINAL :除final外的的属性信息都需要被序列化和反序列化。
         */
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // 配置序列化(解决乱码的问题),过期时间 600 秒
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(600))
                .serializeKeysWith(RedisSerializationContext.SerializationPair
                        .fromSerializer(redisSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.
                        fromSerializer(jackson2JsonRedisSerializer))
                .disableCachingNullValues();
        RedisCacheManager cacheManager = RedisCacheManager.builder(factory).cacheDefaults(config).build();
        return cacheManager;
    }

}

部分有关配置可以参考博客:ObjectMapper的enableDefaultTyping()方法过期解决

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值