九、SpringBoot 整合 Redis
整合测试
- 创建一个 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);
}
- 导入依赖
<!--操作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>
- 配置连接
# SpringBoot 所有的配置类,都有一个自动配置类 RedisAutoConfiguration
# 自动配置类都会绑定一个properties 配置文件 RedisProperties
# redis服务运行的ip地址
spring.redis.host=127.0.0.1
# redis服务运行的端口号
spring.redis.port=6379
- 编写实体类User.class
@AllArgsConstructor
@NoArgsConstructor
@Data
@Accessors(chain = true)
@Component
//在企业中,所有的 pojo 都需要序列化
public class User implements Serializable{
private String name;
private int age;
}
- 测试类中测试
@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;
}
}