Redis(九)【序列化&RedisUtils工具类】

九、SpringBoot 整合 Redis


整合测试

  1. 创建一个 springboot 项目

在这里插入图片描述

说明:再SpringBoot2.x 之后,原来使用的 jedis 被替换成了 lettuce

jedis:采用的是直连,多个线程操作的话,是不安全的。想要避免不安全的,使用 jedis pool 连接池!更像 BIO

lettuce:采用netty,实例可以在多个线程中进行共享,不存在线程不安全的情况!可以减少线程数据,更像 NIO

源码分析:

  • 在jar包中找到
    在这里插入图片描述

@ConditionalOnSingleCandidate

表示当指定 Bean 在容器中只有一个,或者虽然有多个但是指定首选 Bean,这个组合了 @Conditional 元注解,只是使用了不同的条件(Conditional)

@Bean
@ConditionalOnMissingBean(	//我们可以自己定义一个redisTemplate来替换这个默认的
    name = {"redisTemplate"}
)
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)	
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
    //默认的ReidsTemplate没有过多的设置,redis对象都是需要序列化的
    //两个泛型都是Object的类型,后续需要强制转换RedisTemplate<String, Object>
    RedisTemplate<Object, Object> template = new RedisTemplate();
    template.setConnectionFactory(redisConnectionFactory);
    return template;
}

@Bean
@ConditionalOnMissingBean
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
    return new StringRedisTemplate(redisConnectionFactory);
}
  1. 导入依赖
<!--操作Redis-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--如果有报错,就是连接池问题,需要导入下面这个依赖-->
<!--如果加入连接池依赖都没有用,则需要降低SpringBoot版本-->
<!--连接池依赖-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
  1. 配置连接
# SpringBoot 所有的配置类,都有一个自动配置类   RedisAutoConfiguration
# 自动配置类都会绑定一个properties 配置文件    RedisProperties
# redis服务运行的ip地址
spring.redis.host=127.0.0.1
# redis服务运行的端口号
spring.redis.port=6379
  1. 编写实体类User.class

@AllArgsConstructor
@NoArgsConstructor
@Data
@Accessors(chain = true)
@Component
//在企业中,所有的 pojo 都需要序列化
public class User implements Serializable{

    private String name;
    private int age;
}

  1. 测试类中测试
@SpringBootTest
class SpringbootRedisApplicationTests {

    @Autowired
    RedisTemplate redisTemplate;

    @Test
    void contextLoads() {

/**
        //redisTemplate
        //opsForValue   操作字符串的 类似String
        //opsForList    操作列表    类似List
        //opsForSet
        //opsForZSet
        //opsForHash    操作哈希    类似Hash
        //opsForGeo
        //opsForHyperLogLog
        //...
*/
        //除了基本的操作,我们常用的方法都可以直接通过 redisTemplate 来操作,比如事务和基本的CURD
/**
        //获取redis的连接对象
        RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
        connection.flushDb();
        connection.flushAll();
*/
        redisTemplate.opsForValue().set("mykey","我就是太阳");
        System.out.println(redisTemplate.opsForValue().get("mykey"));

    }

}

9.1 自定义RedisTemplate 序列化

当我们使用Java代码实现Redis时,可能会出现以下情况

  • 测试代码

    @Test
    public void test() throws JsonProcessingException {
        // 真实的开发一般都是用JSON来传递对象
        User user = new User("张三", 12);
        String jsonUser = new ObjectMapper().writeValueAsString(user);
        redisTemplate.opsForValue().set("user",user);
        User user1 = (User) redisTemplate.opsForValue().get("user");
        System.out.println(user1);
    }

  • redis-cli.exe客户端获取

在这里插入图片描述

但是在控制台字符是正常的!

源码分析

在这里插入图片描述

在这里插入图片描述

  • 关于对象的保存,大多数都是通过Json格式来保存的

在这里插入图片描述

  • RedisConfiguration.class 配置类
package com.vinjcent.config.redis;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
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.StringRedisSerializer;

import java.text.SimpleDateFormat;

/**
 * @author vinjcent
 * 配置redis序列化json
 */
@Configuration
public class RedisConfiguration {


    @Bean
    /**
     * 若有相同类型的Bean时,优先使用此注解标注的Bean
     */
    @Primary
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        // 为了开发方便,一般直接使用<String, Object>
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        // 配置具体的序列化方式
        // JSON解析任意对象
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
        // 指定要序列化的域field,get和set,以及修饰符范围,ANY是都有包括private和public
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会抛出异常
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
        // 设置日期格式
        om.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // String的序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();


        // key采用String的序列化
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化
        template.setHashKeySerializer(stringRedisSerializer);
        // value的序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        // 设置所有配置
        template.afterPropertiesSet();

        return template;
    }
}




Jackson ObjectMapper 中的enableDefaultTyping方法由于安全原因,从 2.10.0 开始标记为过期,建议用activateDefaultTyping方法代替,所以如果继续使用enableDefaultTyping会有警告出现,我们现在要消除这个警告

在这里插入图片描述

再次测试,并替换原来使用的 RedisTemplate
在这里插入图片描述

在这里插入图片描述

9.2 RedisUtils 工具类


package com.vinjcent.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;


/**
 * @author vinjcent
 */
@Component
public final class RedisUtils {

    private final RedisTemplate<String, Object> redisTemplate;

    /**
     * 可按自己需求生成"起始时间戳"
     */
    private static final long BEGIN_TIMESTAMP = 1640995200L;

    /**
     * 用于时间戳左移32位
     */
    public static final int MOVE_BITS = 32;

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

    //=============================common===================================

    /**
     * 指定缓存失效时间
     * @param key   键
     * @param time  时间(秒)
     * @return  whether the key has expired
     */
    public 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;
        }
    }

    /**
     * 指定缓存失效时间(自定义时间单位)
     * @param key   键
     * @param time  时间(秒)
     * @return  whether the key has expired
     */
    public boolean expire(String key, long time, TimeUnit unit){
        try {
            if(time > 0){
                redisTemplate.expire(key, time, unit);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据key获取过期时间(默认获取的是秒单位)
     * @param key   键(不能为null)
     * @return      the remaining time, "0" means never expire
     */
    public long getExpire(String key){
        Long time = redisTemplate.getExpire(key, TimeUnit.SECONDS);
        if (time != null) {
            return time;
        }
        return -1L;
    }

    /**
     * 根据key获取过期时间(自定义时间单位)
     * @param key   键(不能为null)
     * @return      the remaining time, "0" means never expire
     */
    public long getExpire(String key, TimeUnit unit){
        Long time = redisTemplate.getExpire(key, unit);
        if (time != null) {
            return time;
        }
        return -1L;
    }

    /**
     * 判断key是否存在
     * @param key   键
     * @return      whether the key exist
     */
    public boolean hasKey(String key) {
        Boolean flag = redisTemplate.hasKey(key);
        try {
            return Boolean.TRUE.equals(flag);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除缓存
     * @param key   键,可以传递一个值或多个
     */
    public void del(String... key) {
        if(key != null && key.length > 0){
            if (key.length == 1){
                redisTemplate.delete(key[0]);
            }else {
                redisTemplate.delete(Arrays.asList(key));
            }
        }
    }


    //=============================String===================================

    /**
     * 普通缓存获取(泛型)
     * @param key   key键
     * @return      the value corresponding the key
     */
    public Object get(String key){ return key == null ? null : redisTemplate.opsForValue().get(key);}


    /**
     * 普通缓存获取(泛型)
     * @param key   key键
     * @return      the value corresponding the key
     * @param targetType    目标类型
     * @param <T>           目标类型参数
     * @return      the generic value corresponding the key
     */
    public <T> T get(String key, Class<T> targetType){ return key == null ? null : JsonUtils.objParse(redisTemplate.opsForValue().get(key), targetType);}

    /**
     * 普通缓存放入
     * @param key   键
     * @param value 值
     * @return      whether true or false
     */
    public boolean set(String key, Object value){
        try {
            redisTemplate.opsForValue().set(key,value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 普通缓存放入并设置时间
     * @param key   键
     * @param value 值
     * @param time  时间(秒) --- time要大于0,如果time小于0,将设置为无期限
     * @return      whether true or false
     */
    public boolean set(String key, Object value, long time){
        try {
            if(time > 0){
                redisTemplate.opsForValue().set(key,value,time,TimeUnit.SECONDS);
            }else {
                set(key,value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 普通缓存放入并设置时间和时间单位
     * @param key   键
     * @param value 值
     * @param time  时间(秒) --- time要大于0,如果time小于0,将设置为无期限
     * @param timeUnit  时间单位
     * @return  whether true or false
     */
    public boolean set(String key, Object value, long time, TimeUnit timeUnit){
        try {
            if(time > 0){
                redisTemplate.opsForValue().set(key, value, time, timeUnit);
            }else {
                set(key,value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 递增
     * @param key   键
     * @param delta 要增加几(大于0)
     * @return      the value after increment
     */
    public long incr(String key, long delta){
        if(delta < 0){
            throw new RuntimeException("递增因子必须大于0");
        }
        Long increment = redisTemplate.opsForValue().increment(key, delta);
        return increment != null ? increment : 0L;
    }

    /**
     * 递减
     * @param key   键
     * @param delta 要增加几(小于0)
     * @return      the value after decrement
     */
    public long decr(String key, long delta){
        if(delta < 0){
            throw new RuntimeException("递减因子必须大于0");
        }
        Long increment = redisTemplate.opsForValue().increment(key, delta);
        return increment != null ? increment : 0L;    }

    //=============================Map===================================

    /**
     * 根据hashKey获取hash列表有多少元素
     * @param key   键(hashKey)
     * @return      the size of map
     */
    public long hsize(String key) {
        try {
            return redisTemplate.opsForHash().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0L;
        }
    }

    /**
     * HashGet  根据"项 中的 键 获取列表"
     * @param key   键(hashKey)能为null
     * @param item  项不能为null
     * @return      the value of the corresponding key
     */
    public Object hget(String key, String item){ return redisTemplate.opsForHash().get(key, item);}

    /**
     * 获取HashKey对应的所有键值
     * @param key   键(hashKey)
     * @return      对应的多个键值
     */
    public Map<Object, Object> hmget(String key) { return redisTemplate.opsForHash().entries(key);}

    /**
     * 获取HashKey对应的所有键值
     * @param key   键(hashKey)
     * @param keyType   键类型
     * @param valueType 值类型
     * @param <K>       键类型参数
     * @param <V>       值类型参数
     * @return      a map
     */
    public <K, V> Map<K, V> hmget(String key, Class<K> keyType, Class<V> valueType) {
        return JsonUtils.mapParse(redisTemplate.opsForHash().entries(key), keyType, valueType);}

    /**
     * HashSet  存入多个键值对
     * @param key   键(hashKey)
     * @param map   map 对应多个键值对
     */
    public void hmset(String key, Map<String, Object> map) {
        try {
            redisTemplate.opsForHash().putAll(key,map);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * HashSet存入并设置时间
     * @param key   键(hashKey)
     * @param map   对应多个键值
     * @param time  时间(秒)
     * @return  whether true or false
     */
    public boolean hmset(String key, Map<String, Object> map, long time){
        try {
            redisTemplate.opsForHash().putAll(key,map);
            if (time > 0){
                expire(key,time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     * @param key   键(hashKey)
     * @param item  项
     * @param value 值
     * @return  whether true or false
     */
    public boolean hset(String key, String item, Object value){
        try {
            redisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建,并设置有效时间
     * @param key   键(hashKey)
     * @param item  项
     * @param value 值
     * @param time  时间(秒)   注意: 如果已经在hash表有时间,这里将会替换所有的时间
     * @return  whether true or false
     */
    public boolean hset(String key, String item, Object value, long time){
        try {
            redisTemplate.opsForHash().put(key, item, value);
            if (time > 0){
                expire(key,time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 放入map集合数据,如果不存在将创建
     * @param key   键(hashKey)
     * @param value map集合
     * @param <K>   map集合键参数类型
     * @param <V>   map集合值参数类型
     * @return  whether true or false
     */
    public <K, V> boolean hsetMap(String key, Map<K, V> value) {
        try {
            redisTemplate.opsForHash().putAll(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 获取key对应的所有map键值对
     * @param key   键(hashKey)
     * @return      the Map
     */
    public Map<Object, Object> hgetMap(String key) {
        try {
            return redisTemplate.opsForHash().entries(key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 获取key对应的所有map键值对(泛型)
     * @param key   键(hashKey)
     * @param keyType   键类型
     * @param valueType 值类型
     * @param <K>       键类型参数
     * @param <V>       值类型参数
     * @return      the Map
     */
    public <K, V> Map<K, V> hgetMap(String key, Class<K> keyType, Class<V> valueType) {
        try {
            return JsonUtils.mapParse(redisTemplate.opsForHash().entries(key), keyType, valueType);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 删除hash表中的值
     * @param key   键(hashKey)   不能为null
     * @param item  项可以是多个    不能为null
     */
    public void hdel(String key, Object... item){
        redisTemplate.opsForHash().delete(key,item);
    }

    /**
     * 判断hash表是否有该项的值
     * @param key   键(hashKey)不能为null
     * @param item  项不能为null
     * @return  whether true or false
     */
    public boolean hHasKey(String key, String item){
        return redisTemplate.opsForHash().hasKey(key, item);
    }

    /**
     * hash递增,如果不存在,就会创建一个,并把新增后的值返回
     * @param key   键(hashKey)
     * @param item  项
     * @param by    要增加几(大于0)
     * @return  the value of the corresponding key after increment in one Map
     */
    public double hincr(String key, String item, double by){
        return redisTemplate.opsForHash().increment(key, item, by);
    }

    /**
     * hash递减
     * @param key   键(hashKey)
     * @param item  项
     * @param by    要减少几(小于0)
     * @return  the value of the corresponding key after decrement in one Map
     */
    public double hdecr(String key, String item, double by){
        return redisTemplate.opsForHash().increment(key, item, -by);
    }

    //=============================Set===================================

    /**
     * 根据key获取Set中的所有值
     * @param key   键
     * @return      all values in one Set
     */
    public Set<Object> sGet(String key){
        try {
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据value从一个Set集合中查询一个值,是否存在
     * @param key   键
     * @param value 值
     * @return  whether true or false
     */
    public boolean sHasKey(String key, Object value){
        try {
            Boolean flag = redisTemplate.opsForSet().isMember(key, value);
            return Boolean.TRUE.equals(flag);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将数据放入set缓存
     * @param key       键
     * @param values    值
     * @return  the number of adding successfully
     */
    public long sSet(String key, Object... values){
        try {
            Long nums = redisTemplate.opsForSet().add(key, values);
            return nums != null ? nums : 0L;
        } catch (Exception e) {
            e.printStackTrace();
            return 0L;
        }
    }

    /**
     * 将set数据放入缓存,并设置有效时间
     * @param key       键
     * @param time      时间(秒)
     * @param values    值,可以是多个
     * @return  the number of adding successfully
     */
    public long sSetAndTime(String key, long time, Object... values){
        try {
            Long count = redisTemplate.opsForSet().add(key, values);
            if(time > 0){
                expire(key, time);
            }
            return count != null ? count : 0L;
        } catch (Exception e) {
            e.printStackTrace();
            return 0L;
        }
    }

    /**
     * 获取set缓存的长度
     * @param key   键
     * @return      the size of the Set
     */
    public long sGetSetSize(String key){
        try {
            Long size = redisTemplate.opsForSet().size(key);
            return size != null ? size : 0L;
        } catch (Exception e) {
            e.printStackTrace();
            return 0L;
        }
    }

    /**
     * 移除值为values的
     * @param key       键
     * @param values    值(可以是多个)
     * @return          the number of removal
     */
    public long setRemove(String key, Object... values){
        try {
            Long nums = redisTemplate.opsForSet().remove(key, values);
            return nums != null ? nums : 0L;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    //=============================List===================================

    /**
     * 获取list列表数据
     * @param key       键
     * @return          all values of one List
     */
    public List<Object> lget(String key) {
        try {
            return redisTemplate.opsForList().range(key, 0, -1);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     /**
     * 获取list列表数据(泛型)
     * @param key       键
     * @param targetType    目标类型
     * @param <T>           目标类型参数
     * @return      all values of one List
     */
    public <T> List<T> lget(String key, Class<T> targetType) {
        try {
            return JsonUtils.listParse(redisTemplate.opsForList().range(key, 0, -1), targetType);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取list缓存的长度
     * @param key   键
     * @return      the length of the List
     */
    public long lGetListSize(String key){
        try {
            Long size = redisTemplate.opsForList().size(key);
            return size != null ? size : 0L;
        } catch (Exception e) {
            e.printStackTrace();
            return 0L;
        }
    }

    /**
     * 通过索引获取list中的值
     * @param key   键
     * @param index 索引 index >= 0 时, 0:表头, 1:第二个元素,以此类推...    index < 0 时, -1:表尾, -2:倒数第二个元素,以此类推
     * @return  the value of the specified index in one List
     */
    public Object lgetIndex(String key, long index){
        try {
            return redisTemplate.opsForList().index(key, index);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 通过索引获取list中的值(泛型)
     * @param key   键
     * @param index 索引 index >= 0 时, 0:表头, 1:第二个元素,以此类推...    index < 0 时, -1:表尾, -2:倒数第二个元素,以此类推
     * @return  the value of the specified index in one List
     * @param targetType    目标类型
     * @param <T>           目标类型参数
     * @return  the generic value of the specified index in one List
     */
    public <T> T lgetIndex(String key, long index, Class<T> targetType) {
        try {
            return JsonUtils.objParse(redisTemplate.opsForList().index(key, index), targetType);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 将list放入缓存
     * @param key   键
     * @param value 值
     * @return  whether true or false
     */
    public boolean lSet(String key, Object value){
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     * @return  whether true or false
     */
    public boolean lSet(String key, Object value, long time){
        try {
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0){
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list集合放入缓存
     * @param key       键
     * @param values    值
     * @return  whether true or false
     */
    public <T> boolean lSet(String key, List<T> values){
        try {
            Long nums = redisTemplate.opsForList().rightPushAll(key, values);
            return nums != null;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list集合放入缓存,并设置有效时间
     * @param key       键
     * @param values    值
     * @param time      时间(秒)
     * @return  whether true or false
     */
    public boolean lSet(String key, List<Object> values, long time){
        try {
            redisTemplate.opsForList().rightPushAll(key, values);
            if (time > 0){
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

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

    /**
     * 移除N个值为value
     * @param key       键
     * @param value     值
     * @param number    移除多少个
     * @return          返回移除的个数
     */
    public long lRemove(String key, Object value, long number){
        try {
            Long count = redisTemplate.opsForList().remove(key, number, value);
            return count != null ? count : 0L;
        } catch (Exception e) {
            e.printStackTrace();
            return 0L;
        }
    }

    //=============================Lock===================================

    /**
     * 解决缓存加锁问题
     * @param key   锁名称
     * @param value 锁值
     * @param timeout   超时时间
     * @param unit  时间单位
     * @param <T>   锁值的数据类型
     * @return  返回加锁成功状态
     */
    public <T> boolean tryLock(String key, T value, long timeout, TimeUnit unit) {
        Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, value, timeout, unit);
        return Boolean.TRUE.equals(flag);
    }

    /**
     * 解决缓存解锁操作
     * @param key   锁名称
     * @return  返回解锁成功状态
     */
    public boolean unLock(String key) {
        Boolean flag = redisTemplate.delete(key);
        return Boolean.TRUE.equals(flag);
    }

    /**
     * 全局生成唯一ID策略
     * 设计: 符号位(1位) - 时间戳(32位) - 序列号(31位)
     * @param keyPrefix     key的前缀
     * @return  返回唯一ID
     */
    public long globalUniqueKey(String keyPrefix) {

        // 1. 生成时间戳
        LocalDateTime now = LocalDateTime.now();

        // 东八区时间
        long nowSecond = now.toEpochSecond(ZoneOffset.UTC);
        // 相减获取时间戳
        long timestamp = nowSecond - BEGIN_TIMESTAMP;

        // 2. 生成序列号(使用日期作为redis自增长超2^64限制,灵活使用年、月、日来存储)
        // 获取当天日期
        String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
        // 自增长
        Long increment = redisTemplate.opsForValue().increment("icr:" + keyPrefix + ":" + date);
        long count = increment != null ? increment : 0L;

        // 3. 拼接并返回(使用二进制或运算)
        return timestamp << MOVE_BITS | count;
    }

}



9.3 JsonUtils 泛型序列化工具类

package com.vinjcent.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.List;
import java.util.Map;

/**
 * @author vinjcent
 * Json序列化工具类
 */
public class JsonUtils {
    public static final ObjectMapper OBJ_MAPPER = new ObjectMapper();


    /**
     * 普通对象之间类型的转化
     *
     * @param source 原对象
     * @param target 目标类型
     * @param <T>    目标参数类型
     * @return object after transformation
     */
    public static <T> T objParse(Object source, Class<T> target) {
        try {
            if (source.getClass().equals(target)) {
                return OBJ_MAPPER.convertValue(source, target);
            }
        } catch (Exception ignored) {
        }
        return null;
    }

    /**
     * 普通列表之间类型的转化
     *
     * @param source 原列表
     * @param target 目标列表类型
     * @param <T>    目标列表参数类型
     * @return list after transformation
     */
    public static <S, T> List<T> listParse(List<S> source, Class<T> target) {
        try {
            return OBJ_MAPPER.convertValue(source, OBJ_MAPPER.getTypeFactory().constructCollectionType(List.class, target));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 普通哈希列表之间类型的转化
     *
     * @param source    原哈希列表
     * @param keyType   键类型
     * @param valueType 值类型
     * @param <SK>      原键类型
     * @param <SV>      原值类型
     * @param <TK>      目标键类型
     * @param <TV>      目标值类型
     * @return map after transformation
     */
    public static <SK, SV, TK, TV> Map<TK, TV> mapParse(Map<SK, SV> source, Class<TK> keyType, Class<TV> valueType) {
        try {
            return OBJ_MAPPER.convertValue(source, OBJ_MAPPER.getTypeFactory().constructMapType(Map.class, keyType, valueType));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将对象转换成json字符串(序列化)
     *
     * @param obj 原对象
     * @return string after serialized object
     */
    public static String objToJson(Object obj) {
        if (obj == null) {
            return null;
        }
        try {
            return OBJ_MAPPER.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return "";
    }


    /**
     * 将json转化为对象(反序列化)
     *
     * @param source 原对象json
     * @param target 目标类型
     * @param <T>    目标类参数类型
     * @return deserialized object
     */
    public static <T> T jsonToObj(String source, Class<T> target) {
        OBJ_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        try {
            return OBJ_MAPPER.readValue(source, target);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将列表json转化为对象集合
     *
     * @param source 原对象json
     * @param target 目标类型
     * @param <T>    目标类参数类型
     * @return deserialized object collection
     */
    public static <T> List<T> jsonToList(String source, Class<T> target) {
        try {
            return OBJ_MAPPER.readValue(source, OBJ_MAPPER.getTypeFactory().constructCollectionType(List.class, target));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 将哈希表json转化为对象集合
     *
     * @param source    原对象json
     * @param keyType   键类型
     * @param valueType 值类型
     * @param <K>       键参数类型
     * @param <V>       值参数类型
     * @return deserialized map collection
     */
    public static <K, V> Map<K, V> jsonToMap(String source, Class<K> keyType, Class<V> valueType) {
        try {
            return OBJ_MAPPER.readValue(source, OBJ_MAPPER.getTypeFactory().constructMapType(Map.class, keyType, valueType));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


}


  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Naijia_OvO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值