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

引入依赖

 <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进行缓存时,对数据进行序列化,解决乱码。

Configuration
public class RedisConfig extends CachingConfigurerSupport{

    @Bean
    @Primary
    public GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer(){
        ObjectMapper om = new ObjectMapper();
        // 解决查询缓存转换异常的问题
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 将类的信息随数据存入Redis,在反序列化时,恢复对象信息。
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        // 支持 jdk 1.8 日期   ---- start ---
        om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        om.registerModule(new Jdk8Module())
                .registerModule(new JavaTimeModule())
                .registerModule(new ParameterNamesModule());
        // --end --
        GenericJackson2JsonRedisSerializer  genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(om);
        return genericJackson2JsonRedisSerializer;
    }

    /**
     * 对redisTemplate 进行Json序列化
     * @param factory
     * @return
     */
    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory factory,GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer){
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
        return redisTemplate;
    }

    /**
     * 对redis缓存管理器进行配置
     * 主要作用于缓存得统一管理,搭配 @Cacheable注解使用
     * @return
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory,GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer){
        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");
    }

}

你可能感兴趣的:(redis,数据库,缓存)