SpringCache整合Redis并实现序列化和反序列化

文章介绍了如何在SpringBoot应用中引入Redis和缓存支持,包括添加相关依赖、配置自定义的JacksonObjectMapper以处理Java8日期类型,以及配置RedisTemplate和CacheManager进行缓存管理。此外,文章还展示了如何使用@Cacheable、@CacheEvict和@CachePut注解进行缓存操作,并提供了测试用例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引入依赖

 <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
 </dependency>
 <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-cache</artifactId>
 </dependency>
<!--处理Java8 日期类型-->
 <dependency>
      <groupId>com.fasterxml.jackson.datatype</groupId>
      <artifactId>jackson-datatype-jsr310</artifactId>
 </dependency>
  1. @Cacheable : 用于查询
  2. @CacheEvict : allEntries 这个注解的特有属性。如果触发该注解解,会清空该类型(value) 下的所有缓存。默认为false, 若要使用需要设为true。不能与key共存。
  3. @CachePut:用来接收方法的返回值,并将其添加到缓存。(不常用)

属性:

  • value:指明缓存的类型。
  • key:用于标记某次缓存,一般通过id标记,查询条件标记。删除缓存时,通过标记去删除。
  • conditon:是否缓存的判断条件,可以用来指明查询结果为null时不缓存。
  • unless:与condition相反。

注意:主类上添加 @EnableCaching 注解,开启缓存

配置类
用于处理返回前端的数据,序列化和反序列化的格式

public class JacksonObjectMapper extends ObjectMapper {
    @Serial
    private static final long serialVersionUID = 2220067913562288238L;

    public static final String DATE_TIME_FORMATTER= "yyyy-MM-dd HH:mm:ss";
    public static final String TIME_FORMATTER= "HH:mm:ss";
    public static final String DATE_FORMATTER= "yyyy-MM-dd";

    public JacksonObjectMapper() {
        this.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        this.setSerializationInclusion(JsonInclude.Include.ALWAYS);
        this.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT,true);
        this.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS,false);
        this.configure(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS,false);
        this.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES,false);
        this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
        this.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
        SimpleModule simpleModule = new SimpleModule()
                .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMATTER)))
                .addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DATE_FORMATTER)))
                .addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(TIME_FORMATTER)))
                //防止Long类型在前端精度缺失
                .addSerializer(Long.class, new ToStringSerializer())
                .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMATTER)))
                .addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DATE_FORMATTER)))
                .addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(TIME_FORMATTER)));
        this.registerModule(simpleModule);
    }
}

配置类
扩展转换器

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        converter.setObjectMapper(new JacksonObjectMapper());
        converters.add(0,converter);
    }
}

配置类
利用redis进行缓存时,对数据进行序列化,解决乱码。

@EnableCaching
@Configuration
public class RedisConfig {

    @Bean
    public GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer() {
        String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
        ObjectMapper objectMapper = new ObjectMapper();
        // 处理Date类型
        objectMapper.setDateFormat(new SimpleDateFormat(DATE_TIME_FORMAT));
        objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
        objectMapper.registerModule(new JavaTimeModule()
                // 处理LocalDateTime类型
                .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT)))
                .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT))));
        // 序列化java对象时,将类的信息写入redis
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
        return new GenericJackson2JsonRedisSerializer(objectMapper);
    }

    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);
        redisTemplate.setDefaultSerializer(genericJackson2JsonRedisSerializer());
        return redisTemplate;
    }

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofMinutes(30)) // 配置缓存时长
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(genericJackson2JsonRedisSerializer()));
        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
        return cacheManager;
    }
}

接口类

注意:key的书写格式,双引号内部的是变量,再加个单引号才能表示字符串
通过#,可以获得参数的信息。

@RestController
@RequestMapping("/wuxia")
public class UserController {
    @Resource
    private WuXiaService wuXiaService;

    /**
     * 缓存整个列表的数据
     * @return
     */
    @Cacheable(value = "wuxia",key = "'wuxiaList'")
    @GetMapping
    public Result list(){
        return Result.ok(wuXiaService.list());
    }

    /**
     * 缓存该id对应的数据到redis
     * @param id
     * @return
     */
    @Cacheable(value = "wuxia",key = "'wuxia'+'_'+#id")
    @GetMapping("/{id}")
    public Result getWuxiaById(@PathVariable("id") Integer id){
        return Result.ok(wuXiaService.getById(id));
    }

    /**
     * 有数据修改时,就会删除这个分组的所有缓存,防止list出现假数据
     * @param wuXia
     * @return
     */
    @CacheEvict(value = "wuxia",allEntries = true)
    @PutMapping
    public Result updateById(@RequestBody WuXia wuXia){
        wuXiaService.updateById(wuXia);
        return Result.ok("更新成功");
    }

    /**
     * 有数据删除时,就会删除这个分组的所有缓存,防止list出现假数据
     * @param id
     * @return
     */
    @CacheEvict(value = "wuxia",allEntries = true)
    @DeleteMapping("/{id}")
    public Result deleteById(@PathVariable("id") Integer id){
        wuXiaService.removeById(id);
        return Result.ok("删除成功");
    }
}

测试类

  1. 使用RestTemplate需要注册Bean。
  2. 对于RestTemplate的返回类型,最好使用Object类来接收,否则会出现类转换异常。
@SpringBootTest
public class CacheAppTest {

    @Resource
    private WuXiaService wuXiaService;

    @Test
    public void testSelect(){
        wuXiaService.list().forEach(System.out::println);

    }

    @Resource
    private RedisTemplate redisTemplate;

    @Test
    public void testRedis(){
        redisTemplate.opsForValue().set("age","23");
        System.out.println(redisTemplate.opsForValue().get("age"));
    }

    @Resource
    RestTemplate restTemplate;

    @Test
    public void testList(){
        Object object = restTemplate.getForObject("http://localhost:8080/wuxia", Object.class);
        System.out.println(object);
    }

    @Test
    public void testSelectById(){
        ResponseEntity<Object> forEntity = restTemplate.getForEntity("http://localhost:8080/wuxia/3", Object.class);
        System.out.println(forEntity.getBody());
    }

    @Test
    public void testUpdateById(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("id",1);
        map.put("name","lisi");
        map.put("age",14);
        map.put("inSchoolTime",LocalDate.now().plusDays(1));
        restTemplate.put("http://localhost:8080/wuxia",map);

    }

    @Test
    public void testDeleteById(){
        restTemplate.delete("http://localhost:8080/wuxia/2");
    }

}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值