在Spring Boot中集成Redis
依赖
<!-- Spring对Redis的集成支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 阿里JSON解析器 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
</dependency>
在application.yml中配置Redis服务地址
spring:
profiles:
active: druid
redis:
host: 127.0.0.1
port: 6379
password:
database: 0
timeout: 1800000
Redis 序列化器
package com.chinabuilder.framework.config;
/**
* FastJson2 实现的 Redis 序列化器
*
* 功能:将 Java 对象与 Redis 存储的二进制数据相互转换,使用 FastJson2 作为序列化工具。
* 特点:
* 1. 支持类名白名单过滤,防止反序列化攻击(安全特性)
* 2. 自动处理 null 值和空字节数组
* 3. 使用 UTF-8 编码确保跨平台兼容性
* 4. 序列化时写入类名(WriteClassName),便于反序列化时类型识别
*
* 泛型说明:
* @param <T> 需序列化的对象类型,需与反序列化目标类型一致
*
* 示例用法:
* RedisTemplate<String, User> template = new RedisTemplate<>();
* template.setValueSerializer(new FastJson2JsonRedisSerializer<>(User.class));
*/
public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
{
/**
* 默认字符集:UTF-8
* 确保序列化后的字节在不同系统间兼容
*/
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
/**
* 类名白名单过滤器
* 通过 {@link Constants.JSON_WHITELIST_STR} 配置允许反序列化的类全限定名
* 示例白名单内容:["com.example.Entity", "java.util.ArrayList"]
*/
static final Filter AUTO_TYPE_FILTER = JSONReader.autoTypeFilter(Constants.JSON_WHITELIST_STR);
/**
* 目标类型的 Class 对象
* 用于反序列化时确定具体类型
*/
private Class<T> clazz;
public FastJson2JsonRedisSerializer(Class<T> clazz)
{
// 调用父类的无参构造函数。
// 它是子类构造函数中的第一行代码(如果不显式写,编译器会自动插入,前提是父类有无参构造函数)。
// 目的是确保父类的初始化逻辑先于子类执行。
super();
this.clazz = clazz;
}
/**
* 序列化方法:将 Java 对象转换为字节数组
*
* @param t 待序列化的对象,允许为 null
* @return 序列化后的字节数组,null 对象返回空数组(非 null)
* @throws SerializationException 序列化失败时抛出
*
* 关键逻辑:
* 1. 空值检查:直接返回空数组,避免 NPE
* 2. 使用 FastJson2 的 {@link JSONWriter.Feature.WriteClassName} 特性,
* 在 JSON 中写入类名,确保反序列化能识别原始类型
* 3. 转换为 UTF-8 字节数组
*/
@Override
public byte[] serialize(T t) throws SerializationException
{
if (t == null)
{
return new byte[0];
}
return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName).getBytes(DEFAULT_CHARSET);
}
/**
* 反序列化方法:将字节数组还原为 Java 对象
*
* @param bytes 待反序列化的字节数组,允许为 null 或空数组
* @return 反序列化后的对象,输入为空时返回 null
* @throws SerializationException 反序列化失败时抛出(如白名单校验不通过)
*
* 关键逻辑:
* 1. 空值检查:直接返回 null
* 2. 将字节数组转为 UTF-8 字符串
* 3. 使用 {@link #AUTO_TYPE_FILTER} 白名单过滤,仅允许预定义的类被反序列化
* 4. 通过目标类型 clazz 确保反序列化结果类型安全
*
* 安全说明:
* - 白名单机制可防御 Fastjson 的 autoType 漏洞(如恶意类加载)
* - 若 bytes 包含非白名单类名,会抛出 {@link com.alibaba.fastjson2.JSONException}
*/
@Override
public T deserialize(byte[] bytes) throws SerializationException
{
if (bytes == null || bytes.length <= 0)
{
return null;
}
String str = new String(bytes, DEFAULT_CHARSET);
// 反序列化(启用白名单过滤)
return JSON.parseObject(str, clazz, AUTO_TYPE_FILTER);
}
}
初始化配置RedisConfig
package com.chinabuilder.framework.config;
/**
* Redis配置类
*
* 该类配置了Redis的核心功能
* RedisTemplate的序列化配置
*/
@Configuration
@EnableCaching // 启用Spring缓存注解支持
public class RedisConfig extends CachingConfigurerSupport
{
/**
* 配置RedisTemplate
*
* @param connectionFactory Redis连接工厂
* @return 配置好的RedisTemplate实例
*/
@Bean
@SuppressWarnings(value = { "unchecked", "rawtypes" })
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory)
{
// 创建RedisTemplate实例
RedisTemplate<Object, Object> template = new RedisTemplate<>();
// 设置连接工厂
template.setConnectionFactory(connectionFactory);
// 创建FastJson2序列化器,用于值(value)的序列化
FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);
// 设置键(key)的序列化器为StringRedisSerializer 确保所有键以字符串形式存储
// 避免二进制键导致 Redis 命令行工具无法直接查看
template.setKeySerializer(new StringRedisSerializer());
// 设置值(value)的序列化器为FastJson2JsonRedisSerializer
// 用于复杂对象的序列化
template.setValueSerializer(serializer);
// 设置Hash结构的key的序列化器
template.setHashKeySerializer(new StringRedisSerializer());
// 设置Hash结构的value的序列化器
template.setHashValueSerializer(serializer);
// 初始化模板属性
template.afterPropertiesSet();
return template;
}
}
缓存工具类
/**
* spring redis 工具类
*
**/
@SuppressWarnings(value = { "unchecked", "rawtypes" })
@Component
public class RedisCache {
@Autowired
public RedisTemplate redisTemplate;
/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
*/
public <T> void setCacheObject(final String key, final T value) {
redisTemplate.opsForValue().set(key, value);
}
/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
* @param timeout 时间
* @param timeUnit 时间颗粒度
*/
public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
}
/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @return true=设置成功;false=设置失败
*/
public boolean expire(final String key, final long timeout) {
return expire(key, timeout, TimeUnit.SECONDS);
}
/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @param unit 时间单位
* @return true=设置成功;false=设置失败
*/
public boolean expire(final String key, final long timeout, final TimeUnit unit) {
return redisTemplate.expire(key, timeout, unit);
}
/**
* 获取有效时间
*
* @param key Redis键
* @return 有效时间
*/
public long getExpire(final String key) {
return redisTemplate.getExpire(key);
}
/**
* 判断 key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public Boolean hasKey(String key) {
return redisTemplate.hasKey(key);
}
/**
* 获得缓存的基本对象。
*
* @param key 缓存键值
* @return 缓存键值对应的数据
*/
public <T> T getCacheObject(final String key) {
ValueOperations<String, T> operation = redisTemplate.opsForValue();
return operation.get(key);
}
/**
* 删除单个对象
*
* @param key
*/
public boolean deleteObject(final String key) {
return redisTemplate.delete(key);
}
/**
* 删除集合对象
*
* @param collection 多个对象
* @return
*/
public boolean deleteObject(final Collection collection) {
return redisTemplate.delete(collection) > 0;
}
}