在SpringBoot项目中使用redis存储数据作为字典
本项目使用jdk1.8
一、添加依赖
<!-- spring boot redis缓存引入 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 缓存连接池-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- redis 存储 json序列化 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
二、配置yml
#spring:
redis:
host: 公网IP
port: 6379
database: 0
password: (redis密码) #默认为空
timeout: 3000ms #最大等待时间,超时则抛出异常,否则请求一直等待
lettuce:
pool:
max-active: 20 #最大连接数,负值表示没有限制,默认8
max-wait: -1 #最大阻塞等待时间,负值表示没限制,默认-1
max-idle: 8 #最大空闲连接,默认8
min-idle: 0 #最小空闲连接,默认0
三、写配置类
3.1 为什么写配置类
如果不写配置类,那么往redis存值,会存jdk序列化的数据,无法正常观看数据

3.2 配置类
java
package com.atguigu.srb.base.config;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
//首先解决key的序列化方式
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringRedisSerializer);
//解决value的序列化方式
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
//序列化时将类的数据类型存入json,以便反序列化的时候转换成正确的类型
ObjectMapper objectMapper = new ObjectMapper();
//objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
// 解决jackson2无法反序列化LocalDateTime的问题
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.registerModule(new JavaTimeModule());
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
return redisTemplate;
}
}
四、测试
4.1 存值
java
/**
* FileName: RedisTemplateTest
* Author: ccy
* Description:redis测试
* Date: 2025/4/21 22:23
*/
@SpringBootTest(classes = ServiceCoreApplication.class)
@RunWith(SpringRunner.class)
public class RedisTemplateTest {
@Resource
private RedisTemplate redisTemplate;
@Resource
private DictMapper dictMapper;
@Test
public void saveDict() {
Dict dict = dictMapper.selectById(1);
//向数据库中存储string类型的键值对,过期时间5分钟
redisTemplate.opsForValue().set("dict", dict, 5 , TimeUnit.MINUTES);
}
}
发现RedisTemplate默认使用了JDK的序列化方式存储了key和value

4.2 取值
java
package com.atguigu.srb;
/**
* FileName: RedisTemplateTest
* Author: ccy
* Description:redis测试
* Date: 2025/4/21 22:23
*/
@SpringBootTest(classes = ServiceCoreApplication.class)
@RunWith(SpringRunner.class)//
public class RedisTemplateTest {
@Resource
private RedisTemplate redisTemplate;
@Resource
private DictMapper dictMapper;
@Test
public void getDict() {
Dict dict = (Dict)redisTemplate.opsForValue().get("dict");
System.out.println(dict);
}
}

五、将数据字典存入Redis
本项目功能实际应用于尚融宝项目
java
// ---------Controller---------
/**
* 延迟加载
* @param parentId 前台传后台参数
* @return R
*/
@ApiOperation("根据上级id获取子节点数据列表")
@GetMapping("/listByParentId/{parentId}")
public R listByParentId(@ApiParam(value = "上级节点id", required = true)
@PathVariable Long parentId) {
List<Dict> dictList = dictService.listByParentId(parentId);
return R.ok().data("list", dictList);
}
// --------ServiceImpl-----------
@Override
public List<Dict> listByParentId(Long parentId) {
//用try-catch的原因是redis调用可能出错
try {
//首先查询redis中是否存在数据列表
List<Dict> dictList = (List<Dict>) redisTemplate.opsForValue().get("srb:core:dictList" + parentId);
//如果存在,则从redis中直接返回数据列表
if (dictList != null) {
log.info("从redis中获取数据列表");
return dictList;
}
} catch (Exception e) {
//ExceptionUtils.getStackTrace(e): 拿到e对象错误跟踪栈字符串
log.error("redis服务器异常:" + ExceptionUtils.getStackTrace(e));
}
// 如果不存在,则从数据库中查询,并把数据保存到redis中
log.info("从数据库中获取数据列表");
LambdaQueryWrapper<Dict> qW = Wrappers.lambdaQuery();
qW.eq(Dict::getParentId, parentId);
List<Dict> dictList = this.list(qW);
//填充hashChildren字段
dictList.forEach(dict -> {
//判断当前节点是否有子节点,找到当前的dict下级是否有子节点
boolean hasChildren = this.hasChildren(dict.getId());
dict.setHasChildren(hasChildren);
});
try {
//将数据存入redis
log.info("将数据存入redis");
redisTemplate.opsForValue().set("srb:core:dictList" + parentId, dictList, 5, TimeUnit.MINUTES);
} catch (Exception e) {
log.error("redis服务器异常:" + ExceptionUtils.getStackTrace(e));
}
//返回数据列表
return dictList;
}
