在 Spring Boot 应用中,序列化和反序列化是两个核心概念,尤其是在处理 Web 层的 JSON 数据和 Redis 缓存数据时。本文将详细探讨 Spring Boot 中的序列化和反序列化机制,特别是在 Web 层和 Redis 缓存中的应用。
在 Web 应用中,序列化和反序列化主要涉及将 Java 对象转换为 JSON 格式的数据,以及将 JSON 数据转换回 Java 对象。这在处理 RESTful API 的请求和响应时尤为重要。
JavaTimeModule:为了支持 Java 8 的日期和时间 API,我们使用 JavaTimeModule
。这允许我们自定义 LocalDateTime
、LocalDate
和 LocalTime
的格式,确保它们按预期格式序列化和反序列化。
自定义格式:通过 DateTimeFormatter
的模式字符串,我们可以定义日期和时间的具体展现形式。这对于保持 API 的一致性和可读性至关重要。
长整型处理:对于长整型(Long)的处理,我们通常将其序列化为字符串,以避免在某些客户端(如 JavaScript)中处理大数字时的精度问题。
javaimport cn.hutool.core.date.DatePattern;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.Order;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
/**
* @author Jack Wei
* @date 2022/2/25 11:08
*/
@Configuration
public class JacksonConfig {
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return builder -> builder.modules(new JavaTimeModule())
.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)))
.serializerByType(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)))
.serializerByType(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)))
.deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)))
.deserializerByType(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)))
.deserializerByType(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)))
.serializerByType(Long.class, ToStringSerializer.instance)
.serializerByType(Long.TYPE, ToStringSerializer.instance);
}
}
在使用 Redis 作为缓存时,序列化和反序列化涉及将 Java 对象转换为可以存储在 Redis 中的格式,通常是 JSON,以及从 Redis 中检索并转换回 Java 对象。
自定义 ObjectMapper:对于 Redis,我们通常使用独立于 Web 层的 ObjectMapper
配置。这是因为 Redis 缓存的需求可能与 HTTP 请求/响应的处理不同。
安全措施:使用 PolymorphicTypeValidator
可以帮助我们防止潜在的安全风险,例如远程代码执行漏洞。
数据类型处理:类似于 Web 层,我们也需要处理各种数据类型,尤其是日期和时间类型的正确序列化和反序列化。
javaimport cn.hutool.core.date.DatePattern;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator;
import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
/**
* redis配置
*
* @author CTGU_LLZ(404name)
* @date 2021/07/28
*/
@Configuration
public class RedisConfig {
final ObjectMapper objectMapper = JsonMapper.builder().addModule(new SimpleModule()).build();
@Bean
@SuppressWarnings("all")
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(lettuceConnectionFactory);
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = myJasonRedisSerializer();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
private Jackson2JsonRedisSerializer<Object> myJasonRedisSerializer() {
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
// 精确地控制哪些类型是允许的,以防止潜在的安全漏洞,如远程代码执行(RCE)
PolymorphicTypeValidator ptv = BasicPolymorphicTypeValidator.builder()
.allowIfBaseType("com.code.generator")
.build();
// Json序列化配置
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.activateDefaultTyping(ptv, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
objectMapper.registerModule(new JavaTimeModule());
// 将日期序列化为可读字符串而不是时间戳
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// 设置时间模块(格式化,不设置,则输出默认格式)
JavaTimeModule timeModule = new JavaTimeModule();
// LocalDateTime
timeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
timeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
// LocalDate
timeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
timeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
// LocalTime
timeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)));
timeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)));
// 设置自定义时间模块
objectMapper.registerModule(timeModule);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
return jackson2JsonRedisSerializer;
}
}
提示
使用了fastjson2工具
javaimport cn.hutool.core.collection.CollUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson2.JSON;
import com.google.common.base.Preconditions;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@Slf4j
@Component
@SuppressWarnings({"unchecked", "unused"})
public class RedisUtil {
// ============================common=============================
/**
* 设置有效时长,单位:秒
*
* @param key 键
* @param timeout 时间(秒)
* @return 是否成功
*/
public static Boolean setExpire(String key, long timeout) {
Preconditions.checkArgument(Objects.nonNull(key), key + "键不存在");
return SpringUtil.getBean(RedisTemplate.class).expire(key, timeout, TimeUnit.SECONDS);
}
/**
* 获取有效时长,单位:秒
*
* @param key 键 不能为null
* @return 时间(秒) 返回0 代表为永久有效
*/
public static Long getExpire(String key) {
Preconditions.checkArgument(Objects.nonNull(key), key + "键不存在");
return SpringUtil.getBean(RedisTemplate.class).getExpire(key, TimeUnit.SECONDS);
}
/**
* 键是否存在
*
* @param key 键
* @return {@link Boolean}
*/
public static Boolean hasKey(String key) {
return SpringUtil.getBean(RedisTemplate.class).hasKey(key);
}
/**
* 根据键删除
*
* @param key 一个或多个键
*/
public static void delete(String... key) {
SpringUtil.getBean(RedisTemplate.class).delete(CollUtil.toList(key));
}
/**
* 获取所有键
*
* @param pattern 模式,例如*代表任意多个字符,?代表一个字符,[abc]代表任意一个列在括号中的字符
* @return {@link Set}<{@link String}>
*/
public static Set<String> getKeys(String pattern) {
return SpringUtil.getBean(RedisTemplate.class).keys(pattern);
}
// ============================String=============================
/**
* 普通:根据key获取value---对象
*
* @param key 键
* @param tClass 类型
* @return 值
*/
public static <T> T get(String key, Class<T> tClass) {
Object object = SpringUtil.getBean(RedisTemplate.class).opsForValue().get(key);
if (object == null) {
return null;
}
return JSON.to(tClass, object);
}
/**
* 普通:根据key获取value---字符串
*
* @param key 键
* @return 值---字符串
*/
public static String getStr(String key) {
return get(key, String.class);
}
/**
* 普通:缓存放入,默认有效时间为永久
*
* @param key 键
* @param value 值
*/
public static void set(String key, Object value) {
SpringUtil.getBean(RedisTemplate.class).opsForValue().set(key, value);
}
/**
* 普通:缓存放入并设置有效时间(单位秒)
*
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0
*/
public static void set(String key, Object value, long time) {
SpringUtil.getBean(RedisTemplate.class).opsForValue().set(key, value, time, TimeUnit.SECONDS);
}
/**
* 普通:键如果不存在则缓存,否则返回false(单位毫秒)
*
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
*/
public static Boolean setIfAbsent(String key, Object value, long time) {
return SpringUtil.getBean(RedisTemplate.class).opsForValue().setIfAbsent(key, value, time, TimeUnit.MILLISECONDS);
}
/**
* 普通:缓存放入并设置有效时间(单位秒)
*
* @param key 键
* @param value 值
* @param duration 时间(秒) time要大于0 如果time小于等于0 将设置无限期
*/
public static void set(String key, Object value, Duration duration) {
SpringUtil.getBean(RedisTemplate.class).opsForValue().set(key, value, duration);
}
/**
* 递增
*
* @param key 键
* @param delta 要增加几
* @return 递增之后的值
*/
public static Long increment(String key, long delta) {
Preconditions.checkArgument(Objects.nonNull(key), key + "键不存在");
return SpringUtil.getBean(RedisTemplate.class).opsForValue().increment(key, delta);
}
/**
* 递减
*
* @param key 键
* @param delta 要减少几
* @return 递减之后的值
*/
public static Long decrement(String key, long delta) {
Preconditions.checkArgument(Objects.nonNull(key), key + "键不存在");
return SpringUtil.getBean(RedisTemplate.class).opsForValue().decrement(key, delta);
}
// ================================HashMap=================================
/**
* HashGet
*
* @param key 键 不能为null
* @param hashKey hash键 不能为null
* @param tClass 类型 不能为null
* @return 值
*/
public static <T> T hashGet(String key, String hashKey, Class<T> tClass) {
return JSON.to(tClass, SpringUtil.getBean(RedisTemplate.class).opsForHash().get(key, hashKey));
}
/**
* 获取hashKey对应的所有键值
*
* @param key 键
* @return 对应的多个键值
*/
public static Map<Object, Object> hashGetMap(String key) {
return SpringUtil.getBean(RedisTemplate.class).opsForHash().entries(key);
}
/**
* 获取变量中的键
*
* @param key hash键集合
* @return 值集合
*/
public static Set<Object> hashKeys(String key) {
return SpringUtil.getBean(RedisTemplate.class).opsForHash().keys(key);
}
/**
* HashSet
*
* @param key 键
* @param map 对应多个键值
*/
public static void hashSetMap(String key, Map<Object, Object> map) {
SpringUtil.getBean(RedisTemplate.class).opsForHash().putAll(key, map);
}
/**
* 向一张hash表中放入数据,如果不存在将创建,有效时间为永久
*
* @param key 键
* @param item hash键
* @param value 值
*/
public static void hashPut(String key, String item, Object value) {
SpringUtil.getBean(RedisTemplate.class).opsForHash().put(key, item, value);
}
/**
* 数据不存在添加,存在则不添加
*
* @param key 键
* @param item hash键
* @param value 值
*/
public static void hashPutIfAbsent(String key, String item, Object value) {
SpringUtil.getBean(RedisTemplate.class).opsForHash().putIfAbsent(key, item, value);
}
/**
* 数据不存在添加,存在则不添加
*
* @param key 键
* @param item hash键
* @param value 值
* @param time 时间
*/
public static void hashPutIfAbsent(String key, String item, Object value, long time) {
SpringUtil.getBean(RedisTemplate.class).opsForHash().putIfAbsent(key, item, value);
setExpire(key, time);
}
/**
* 删除hash表中的值
*
* @param key 键 不能为null
* @param item 项 可以使多个 不能为null
*/
public static void hashDelete(String key, Object... item) {
SpringUtil.getBean(RedisTemplate.class).opsForHash().delete(key, item);
}
/**
* 判断hash表中是否有该项的值
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return true 存在 false不存在
*/
public static Boolean hasHashKey(String key, String item) {
return SpringUtil.getBean(RedisTemplate.class).opsForHash().hasKey(key, item);
}
/**
* hash递增 如果不存在,就会创建一个 并把新增后的值返回(Double类型)
*
* @param key 键
* @param item 项
* @param delta 要增加几
*/
public static Double increment(String key, String item, Double delta) {
Preconditions.checkArgument(Objects.nonNull(key), key + "键不存在");
return SpringUtil.getBean(RedisTemplate.class).opsForHash().increment(key, item, delta);
}
/**
* hash递增 如果不存在,就会创建一个 并把新增后的值返回(Long类型)
*
* @param key 键
* @param item 项
* @param delta 要增加几
*/
public static Long increment(String key, String item, Long delta) {
Preconditions.checkArgument(Objects.nonNull(key), key + "键不存在");
return SpringUtil.getBean(RedisTemplate.class).opsForHash().increment(key, item, delta);
}
/**
* hash递减
*
* @param key 键
* @param item 项
* @param delta 要减少几
*/
public static Double decrement(String key, String item, Double delta) {
Preconditions.checkArgument(Objects.nonNull(key), key + "键不存在");
return SpringUtil.getBean(RedisTemplate.class).opsForHash().increment(key, item, -delta);
}
/**
* hash集合中元素的数量
*
* @param key 键
* @return 数量
*/
public static Long hashSize(String key) {
Preconditions.checkArgument(Objects.nonNull(key), key + "键不存在");
return SpringUtil.getBean(RedisTemplate.class).opsForHash().size(key);
}
// ============================set=============================
/**
* 设置get
* 根据key获取Set中的所有值
*
* @param key 键
* @return {@link Set}<{@link Object}>
*/
public static Set<Object> setGet(String key) {
return SpringUtil.getBean(RedisTemplate.class).opsForSet().members(key);
}
/**
* 根据键获取跳表全量集合
*
* @param key 键
* @return {@link Set}<{@link Object}>
*/
public static <T> Set<T> getZset(String key, Class<T> tClass) {
return (Set<T>) SpringUtil.getBean(RedisTemplate.class).opsForZSet().range(key, 0, -1);
}
/**
* 根据value从一个set中查询,是否存在
*
* @param key 键
* @param value 值
* @return true 存在 false不存在
*/
public static Boolean setHasKey(String key, Object value) {
Preconditions.checkArgument(Objects.nonNull(key), key + "键不存在");
return SpringUtil.getBean(RedisTemplate.class).opsForSet().isMember(key, value);
}
/**
* 将数据放入set缓存
*
* @param key 键
* @param values 值 可以是多个
* @return 成功个数
*/
public static Long setSet(String key, Object... values) {
return SpringUtil.getBean(RedisTemplate.class).opsForSet().add(key, values);
}
/**
* 将set数据放入缓存
*
* @param key 键
* @param time 时间(秒)
* @param values 值 可以是多个
* @return 成功个数
*/
public static Long setSetAndTime(String key, long time, Object... values) {
return SpringUtil.getBean(RedisTemplate.class).opsForSet().add(key, values);
}
/**
* 设置获取设置大小
* 获取set缓存的长度
*
* @param key 键
* @return {@link Long}
*/
public static Long setGetSetSize(String key) {
Preconditions.checkArgument(Objects.nonNull(key), key + "键不存在");
return SpringUtil.getBean(RedisTemplate.class).opsForSet().size(key);
}
/**
* 移除值为value的
*
* @param key 键
* @param values 值 可以是多个
* @return 移除的个数
*/
public static Long setRemove(String key, Object... values) {
Preconditions.checkArgument(Objects.nonNull(key), key + "键不存在");
return SpringUtil.getBean(RedisTemplate.class).opsForSet().remove(key, values);
}
// ===============================ZSet=================================
/**
* 获取zSet集合中指定分数区间内的成员,分数由高到低排序
*
* @param start 起始位置
* @param end 结束位置
* @param key 键
* @return {@link Set}<{@link ZSetOperations.TypedTuple}<{@link Object}>>
*/
public static Set<ZSetOperations.TypedTuple<Object>> zSetRangeWithScores(String key, Long start, Long end) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForZSet().rangeWithScores(key, start, end);
} catch (Exception e) {
log.error("缓存使用异常", e);
return null;
}
}
/**
* zSet秩
* 获取zSet变量指定区间的元素
*
* @param key 键
* @param start 开始
* @param end 终止
* @return {@link Set}<{@link Object}>
*/
public static Set<Object> ZSetRang(String key, Long start, Long end) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForZSet().range(key, start, end);
} catch (Exception e) {
return null;
}
}
/**
* zSet添加缓存
*
* @param key 键
* @param value 值
* @param score 分数
*/
public static void ZSetAdd(String key, Object value, Number score) {
try {
SpringUtil.getBean(RedisTemplate.class).opsForZSet().add(key, value, score.doubleValue());
} catch (Exception e) {
log.error("缓存使用异常", e);
}
}
/**
* zSet添加缓存
*
* @param key 键
* @param value 值
* @param score 分数
* @param timeout 超时
*/
public static void ZSetAdd(String key, Object value, Number score, long timeout) {
try {
setExpire(key, timeout);
SpringUtil.getBean(RedisTemplate.class).opsForZSet().add(key, value, score.doubleValue());
} catch (Exception e) {
log.error("缓存使用异常", e);
}
}
/**
* zSet添加
* zSet通过TypedTuple方式新增数据
*
* @param key 键
* @param tuples 元组
* @return {@link Long}
*/
public static Long ZSetAdd(String key, Set<ZSetOperations.TypedTuple<Object>> tuples) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForZSet().add(key, tuples);
} catch (Exception e) {
log.error("缓存使用异常", e);
return null;
}
}
/**
* 按分数设置范围
* zSet根据设置的score获取区间值
*
* @param key 键
* @param min 最小
* @param max 最大值
* @return {@link Set}<{@link Object}>
*/
public static Set<Object> ZSetRangeByScore(String key, Double min, Double max) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForZSet().rangeByScore(key, min, max);
} catch (Exception e) {
log.error("缓存使用异常", e);
return null;
}
}
/**
* 按分数设置范围
* zSet根据设置的score获取区间值从给定下标和给定长度获取最终值
*
* @param key 键
* @param min 最小
* @param max 最大值
* @param offset 抵消
* @param count 计数
* @return {@link Set}<{@link Object}>
*/
public static Set<Object> ZSetRangeByScore(String key, Double min, Double max, Long offset, Long count) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForZSet().rangeByScore(key, min, max, offset, count);
} catch (Exception e) {
log.error("缓存使用异常", e);
return null;
}
}
/**
* zSet按分数设置范围
* 获取RedisZSetCommands.Tuples的区间值通过分值
*
* @param key 键
* @param min 最小
* @param max 最大值
* @return {@link Set}<{@link ZSetOperations.TypedTuple}<{@link Object}>>
*/
public static Set<ZSetOperations.TypedTuple<Object>> ZSetRangeByScoreWithScores(String key, Double min, Double max) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForZSet().rangeByScoreWithScores(key, min, max);
} catch (Exception e) {
log.error("缓存使用异常", e);
return null;
}
}
/**
* zSet按分数设置范围
* 获取RedisZSetCommands.Tuples的区间值从给定下标和给定长度获取最终值通过分值
*
* @param key 键
* @param min 最小
* @param max 最大值
* @param offset 抵消
* @param count 计数
* @return {@link Set}<{@link ZSetOperations.TypedTuple}<{@link Object}>>
*/
public static Set<ZSetOperations.TypedTuple<Object>> ZSetRangeByScoreWithScores(String key, Double min, Double max, Long offset, Long count) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForZSet().rangeByScoreWithScores(key, min, max, offset, count);
} catch (Exception e) {
log.error("缓存使用异常", e);
return null;
}
}
/**
* zSet计数
* 获取区间值的个数
*
* @param key 键
* @param min 最小
* @param max 最大值
* @return {@link Long}
*/
public static Long ZSetCount(String key, Double min, Double max) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForZSet().count(key, min, max);
} catch (Exception e) {
log.error("缓存使用异常", e);
return null;
}
}
/**
* zSet秩
* 获取变量中元素的索引,下标开始位置为0
*
* @param key 键
* @param o o
* @return {@link Long}
*/
public static Long ZSetRank(String key, Object o) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForZSet().rank(key, o);
} catch (Exception e) {
log.error("缓存使用异常", e);
return null;
}
}
/**
* zSet分数
* 获取元素的分值
*
* @param key 键
* @param o o
* @return {@link Double}
*/
public static Double ZSetScore(String key, Object o) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForZSet().score(key, o);
} catch (Exception e) {
log.error("缓存使用异常", e);
return null;
}
}
/**
* zSet卡
* 获取变量中元素的个数
*
* @param key 键
* @return {@link Long}
*/
public static Long ZSetCard(String key) {
return Objects.isNull(SpringUtil.getBean(RedisTemplate.class).opsForZSet().zCard(key)) ? Long.valueOf(0L) : SpringUtil.getBean(RedisTemplate.class).opsForZSet().zCard(key);
}
/**
* zSet增量分数
* 修改变量中的元素的分值
*
* @param key 键
* @param value 价值
* @param delta 希腊字母表第4个字母
* @return {@link Double}
*/
public static Double ZSetIncrementScore(String key, Object value, double delta) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForZSet().incrementScore(key, value, delta);
} catch (Exception e) {
return null;
}
}
/**
* zSet反向范围
* 索引倒序排列指定区间的元素
* 返回有序集合中,score大的在前面
* 0 -1 表示获取全部的集合内容
*
* @param key 键
* @param start 开始
* @param end 终止
* @return {@link Set}<{@link Object}>
*/
public static Set<Object> ZSetReverseRange(String key, Long start, Long end) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForZSet().reverseRange(key, start, end);
} catch (Exception e) {
return null;
}
}
/**
* 按分数设置反向范围
* 倒序排列指定分值区间元素
*
* @param key 键
* @param min 最小
* @param max 最大值
* @return {@link Set}<{@link Object}>
*/
public static Set<Object> ZSetReverseRangeByScore(String key, Double min, Double max) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForZSet().reverseRangeByScore(key, min, max);
} catch (Exception e) {
log.error("缓存使用异常", e);
return null;
}
}
/**
* 按分数设置反向范围
* 倒序排列从给定下标和给定长度分值区间元素
*
* @param key 键
* @param min 最小
* @param max 最大值
* @param offset 抵消
* @param count 计数
* @return {@link Set}<{@link Object}>
*/
public static Set<Object> ZSetReverseRangeByScore(String key, Double min, Double max, Long offset, Long count) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForZSet().reverseRangeByScore(key, min, max, offset, count);
} catch (Exception e) {
log.error("缓存使用异常", e);
return null;
}
}
/**
* zSet通过分数设置反向范围
* 倒序排序获取RedisZSetCommands.Tuples的分值区间值
*
* @param key 键
* @param min 最小
* @param max 最大值
* @param offset 抵消
* @param count 计数
* @return {@link Set}<{@link ZSetOperations.TypedTuple}<{@link Object}>>
*/
public static Set<ZSetOperations.TypedTuple<Object>> ZSetReverseRangeByScoreWithScores(String key, Double min, Double max, Long offset, Long count) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForZSet().reverseRangeByScoreWithScores(key, min, max, offset, count);
} catch (Exception e) {
log.error("缓存使用异常", e);
return null;
}
}
/**
* zSet通过分数设置反向范围
* 倒序排序获取RedisZSetCommands.Tuples的从给定下标和给定长度分值区间值
*
* @param key 键
* @param min 最小
* @param max 最大值
* @return {@link Set}<{@link ZSetOperations.TypedTuple}<{@link Object}>>
*/
public static Set<ZSetOperations.TypedTuple<Object>> ZSetReverseRangeByScoreWithScores(String key, Double min, Double max) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForZSet().reverseRangeByScoreWithScores(key, min, max);
} catch (Exception e) {
log.error("缓存使用异常", e);
return null;
}
}
/**
* 带分数zSet反向范围
* 索引倒序排列区间值
*
* @param key 键
* @param start 开始
* @param end 终止
* @return {@link Set}<{@link ZSetOperations.TypedTuple}<{@link Object}>>
*/
public static Set<ZSetOperations.TypedTuple<Object>> ZSetReverseRangeWithScores(String key, Long start, Long end) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForZSet().reverseRangeWithScores(key, start, end);
} catch (Exception e) {
log.error("缓存使用异常", e);
return null;
}
}
/**
* zSet反向秩
* 获取倒序排列的索引值
*
* @param key 键
* @param o o
* @return {@link Long}
*/
public static Long ZSetReverseRank(String key, Object o) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForZSet().reverseRank(key, o);
} catch (Exception e) {
log.error("缓存使用异常", e);
return null;
}
}
/**
* zSet删除
* 批量移除元素根据元素值
*
* @param key 键
* @param values 价值观
* @return {@link Long}
*/
public static Long ZSetRemove(String key, Object... values) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForZSet().remove(key, values);
} catch (Exception e) {
log.error("缓存使用异常", e);
return null;
}
}
/**
* zSet 按分数范围删除
*
* @param key 键
* @param min 分数最小值
* @param max 分数最大值
*/
public static void ZSetRemoveRangeByScore(String key, Number min, Number max) {
try {
SpringUtil.getBean(RedisTemplate.class).opsForZSet().removeRangeByScore(key, min.doubleValue(), max.doubleValue());
} catch (Exception e) {
log.error("缓存使用异常", e);
}
}
/**
* zSet 根据索引值移除区间元素
*
* @param key 键
* @param start 开始
* @param end 终止
* @return {@link Long}
*/
public static Long ZSetRemoveRange(String key, Long start, Long end) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForZSet().removeRange(key, start, end);
} catch (Exception e) {
log.error("缓存使用异常", e);
return null;
}
}
// ===============================list=================================
/**
* list 获取区间内的内容
*
* @param key 键
* @param start 开始
* @param end 结束 0 到 -1 代表所有值
* @return {@link List}<{@link Object}>
*/
public static List<Object> lGet(String key, long start, long end) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForList().range(key, start, end);
} catch (Exception e) {
log.error("缓存使用异常", e);
return null;
}
}
/**
* list 获取缓存的长度
*
* @param key 键
* @return long
*/
public static Long lGetListSize(String key) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForList().size(key);
} catch (Exception e) {
log.error("缓存使用异常", e);
return 0L;
}
}
/**
* list 通过下标索引获取值
*
* @param key 键
* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
* @return {@link Object}
*/
public static Object lGetIndex(String key, long index) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForList().index(key, index);
} catch (Exception e) {
log.error("缓存使用异常", e);
return null;
}
}
/**
* list 在尾部添加元素
*
* @param key 键
* @param value 值
* @return boolean
*/
public static boolean lRightPush(String key, Object value) {
try {
Long result = SpringUtil.getBean(RedisTemplate.class).opsForList().rightPush(key, value);
return result != null && result.intValue() > 0;
} catch (Exception e) {
log.error("缓存使用异常", e);
return false;
}
}
/**
* list 在尾部添加元素(每次添加元素都重置key的过期时间)
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return boolean
*/
public static boolean lRightPush(String key, Object value, long time) {
try {
Long result = SpringUtil.getBean(RedisTemplate.class).opsForList().rightPush(key, value);
return result != null && result.intValue() > 0 && time > 0 && setExpire(key, time);
} catch (Exception e) {
log.error("缓存使用异常", e);
return false;
}
}
/**
* list 在尾部批量添加元素
*
* @param key 键
* @param value 值
* @return 是否成功
*/
public static boolean lRightPush(String key, List<Object> value) {
try {
Long result = SpringUtil.getBean(RedisTemplate.class).opsForList().rightPushAll(key, value);
return result != null && result.intValue() > 0;
} catch (Exception e) {
log.error("缓存使用异常", e);
return false;
}
}
/**
* list 在尾部批量添加元素(每次添加元素都重置key的过期时间)
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return 是否成功
*/
public static boolean lRightPush(String key, List<Object> value, long time) {
try {
Long result = SpringUtil.getBean(RedisTemplate.class).opsForList().rightPushAll(key, value);
if (result != null && result.intValue() > 0) {
if (time > 0) {
setExpire(key, time);
}
return true;
} else {
return false;
}
} catch (Exception e) {
log.error("缓存使用异常", e);
return false;
}
}
/**
* list 在尾部批量添加元素(不存在就添加)
*
* @param key 键
* @param value 值
* @return 是否成功
*/
public static boolean lRightSetIfPresent(String key, Object value) {
try {
Long result = SpringUtil.getBean(RedisTemplate.class).opsForList().rightPushIfPresent(key, value);
return result != null && result.intValue() > 0;
} catch (Exception e) {
log.error("缓存使用异常", e);
return false;
}
}
/**
* list 从尾部开始移除元素
*
* @param key 键
* @return 移除的元素
*/
public static Object lRightPop(String key) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForList().rightPop(key);
} catch (Exception e) {
return null;
}
}
/**
* list 根据指定索引修改值
*
* @param key 键
* @param index 索引
* @param value 值
* @return 是否成功
*/
public static boolean lUpdateIndex(String key, long index, Object value) {
try {
SpringUtil.getBean(RedisTemplate.class).opsForList().set(key, index, value);
return true;
} catch (Exception e) {
log.error("缓存使用异常", e);
return false;
}
}
/**
* list 从列表中移除特定值的元素<br>
*
* @param key 键
* @param count 指定要移除的元素数量。正数表示从列表头部移除,负数表示从尾部移除,0 表示移除所有匹配的元素。
* @param value 值
* @return 移除的个数
*/
public static Long lRemove(String key, long count, Object value) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForList().remove(key, count, value);
} catch (Exception e) {
log.error("缓存使用异常", e);
return 0L;
}
}
/**
* list 在头部添加元素
*
* @param key 键
* @param value 价值
* @return boolean
*/
public static boolean lLeftPush(String key, Object value) {
try {
Long result = SpringUtil.getBean(RedisTemplate.class).opsForList().leftPush(key, value);
return result != null && result.intValue() > 0;
} catch (Exception e) {
log.error("缓存使用异常", e);
return false;
}
}
/**
* list 在头部批量添加元素(集合)
*
* @param key 键
* @param value 价值
* @return boolean
*/
public static boolean lLeftPush(String key, List<Object> value) {
try {
Long result = SpringUtil.getBean(RedisTemplate.class).opsForList().leftPushAll(key, value);
return result != null && result.intValue() > 0;
} catch (Exception e) {
log.error("缓存使用异常", e);
return false;
}
}
/**
* list 在头部添加元素(数组)
*
* @param key 键
* @param values 价值观
* @return boolean
*/
public static boolean lLeftPush(String key, Object... values) {
try {
Long result = SpringUtil.getBean(RedisTemplate.class).opsForList().leftPushAll(key, values);
return result != null && result.intValue() > 0;
} catch (Exception e) {
log.error("缓存使用异常", e);
return false;
}
}
/**
* list 在头部添加元素(集合存在就添加)
*
* @param key 键
* @param value 价值
* @return boolean
*/
public static boolean lLeftSetIfPresent(String key, Object value) {
try {
Long result = SpringUtil.getBean(RedisTemplate.class).opsForList().leftPushIfPresent(key, value);
return result != null && result.intValue() > 0;
} catch (Exception e) {
log.error("缓存使用异常", e);
return false;
}
}
/**
* list 在头部删除元素
*
* @param key 键
* @return {@link Object}
*/
public static Object lLeftPop(String key) {
try {
return SpringUtil.getBean(RedisTemplate.class).opsForList().leftPop(key);
} catch (Exception e) {
return null;
}
}
/**
* list 在指定索引添加值<br>
*
* @param key 键
* @param index 索引
* @param value 值
*/
public static void lSet(String key, Long index, Object value) {
SpringUtil.getBean(RedisTemplate.class).opsForList().set(key, index, value);
}
}
在 Spring Boot 中,正确理解和配置序列化与反序列化机制对于构建健壮和高效的应用至关重要。Web 层的配置重点在于与外部系统(如前端应用)的数据交换,而 Redis 的配置则更多关注于内部数据的存储和访问效率。虽然两者在某些方面有共同之处,但它们各自的特定需求和用途要求我们进行细致和适当的配置调整。
通过本文的讨论,希望能帮助你更好地理解在 Spring Boot 应用中处理序列化和反序列化时的关键考虑因素。正确的配置将确保数据的正确流转,无论是在 Web 层的交互中,还是在 Redis 缓存的使用中。