Redis在SpringBoot中的使用
在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: 公网IPport: 6379database: 0password: (redis密码) #默认为空timeout: 3000ms #最大等待时间,超时则抛出异常,否则请求一直等待lettuce:pool:max-active: 20 #最大连接数,负值表示没有限制,默认8max-wait: -1 #最大阻塞等待时间,负值表示没限制,默认-1max-idle: 8 #最大空闲连接,默认8min-idle: 0 #最小空闲连接,默认0
三、写配置类
3.1 为什么写配置类
如果不写配置类,那么往redis存值,会存jdk序列化的数据,无法正常观看数据
3.2 配置类
package com.atguigu.srb.base.config;@Configuration
public class RedisConfig {@Beanpublic 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 存值
/*** FileName: RedisTemplateTest* Author: ccy* Description:redis测试* Date: 2025/4/21 22:23*/
@SpringBootTest(classes = ServiceCoreApplication.class)
@RunWith(SpringRunner.class)
public class RedisTemplateTest {@Resourceprivate RedisTemplate redisTemplate;@Resourceprivate DictMapper dictMapper;@Testpublic void saveDict() {Dict dict = dictMapper.selectById(1);//向数据库中存储string类型的键值对,过期时间5分钟redisTemplate.opsForValue().set("dict", dict, 5 , TimeUnit.MINUTES);}}
发现RedisTemplate默认使用了JDK的序列化方式存储了key和value
4.2 取值
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 {@Resourceprivate RedisTemplate redisTemplate;@Resourceprivate DictMapper dictMapper;@Testpublic void getDict() {Dict dict = (Dict)redisTemplate.opsForValue().get("dict");System.out.println(dict);}}
五、将数据字典存入Redis
本项目功能实际应用于尚融宝项目
// ---------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-----------@Overridepublic 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 {//将数据存入redislog.info("将数据存入redis");redisTemplate.opsForValue().set("srb:core:dictList" + parentId, dictList, 5, TimeUnit.MINUTES);} catch (Exception e) {log.error("redis服务器异常:" + ExceptionUtils.getStackTrace(e));}//返回数据列表return dictList;}