Spring Boot2.X 以JSON格式保存到Redis中所遇到的问题

在学习spring-boot 2.x 的过程中,学习使用 redis 时在将 Object类型存入 redis 出现 java.util.LinkedHashMap cannot be cast to com.xxx 遇到的问题 :

 在使用缓存注解时需要修改序列化方式。需要重写 cacheManager ,由于学习的spring-boot视频版本为 1.x 发现 spring-boot 1.x 与 2.x 的重写方式有很大差别!

spring-boot 1.x 版本源码如下:

    @Bean
    public RedisCacheManager cacheManager(RedisTemplate<Object, Object> redisTemplate) {
        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
        cacheManager.setUserPrefix(true);
        List<String> cacheNames = this.cacheProperties.getCacheNames();
        if (!cacheNames.isEmpty()) {
            cacheManager.setCacheNames(cacheNames);
        }
        return this.customizerInvoker.customize(cacheManager);
    }

spring-boot 2.x 版本源码如下:

    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory, ResourceLoader resourceLoader) {
        RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(this.determineConfiguration(resourceLoader.getClassLoader()));
        List<String> cacheNames = this.cacheProperties.getCacheNames();
        if (!cacheNames.isEmpty()) {
            builder.initialCacheNames(new LinkedHashSet(cacheNames));
        }

        return (RedisCacheManager)this.customizerInvoker.customize(builder.build());
    }

spring-boot 1.x 版本重写方式:

    @Bean
    public RedisCacheManager employeeCacheManager(RedisTemplate<Object, Object> redisTemplate) {
        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
        cacheManager.setUserPrefix(true);
       
        return cacheManager;
    }

通过测试发现,通过代码的方式保存对象到 redis 默认会使用 jdk 序列化的方式:

    @Test
    public void test02(){
        Employee empById = employeeMapper.getEmpById(1);
        //默认如果保存对象,使用jdk序列化机制,序列化后的数据保存到redis中
        //redisTemplate.opsForValue().set("emp01",empById);
        /**
         *  1.将数据以json的方式保存
         *      1).自己将对象转为JSON 使用JSON转换工具
         *      2).redisTemplate默认的序列化规则
         */
        empRedisTemplate.opsForValue().set("emp01",empById);
    }

需要重写 RedisTemplate  修改 RedisTemplate 默认的序列化方式:

    @Bean
    public RedisTemplate<Object, Employee> empRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, Employee> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        //设置默认的序列化方式
        template.setDefaultSerializer(new Jackson2JsonRedisSerializer(Object.class));
        return template;
    }

如果是通过注解 

@Cacheable 标注的方法执行之前先检查缓存中有没有这个数据,默认按照参数
*  的值作为key去查询缓存如果没有就运行该方法,并将结果放入缓存,以后再调用
*  可以直接使用缓存中的数据

的方式,则需要重写下述spring-boot 2.x 版本重写的方式。

spring-boot 2.x 版本重写方式:

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {

        //初始化json的序列化方式
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        RedisSerializationContext.SerializationPair<Object> pair = RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer);
        //设置 value 的序列化方式为 jackson2JsonRedisSerializer
        RedisCacheConfiguration defaultCacheConfig=RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair);

        //设置默认超过期时间是100秒
        defaultCacheConfig = defaultCacheConfig.entryTtl(Duration.ofSeconds(100));

        //初始化RedisCacheWriter
        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);
        //初始化RedisCacheManager
        RedisCacheManager cacheManager = new RedisCacheManager(redisCacheWriter, defaultCacheConfig);

        //设置白名单---非常重要********
        /*
        使用fastjson的时候:序列化时将class信息写入,反解析的时候,
        fastjson默认情况下会开启autoType的检查,相当于一个白名单检查,
        如果序列化信息中的类路径不在autoType中,
        反解析就会报com.alibaba.fastjson.JSONException: autoType is not support的异常
        可参考 https://blog.csdn.net/u012240455/article/details/80538540
         */
        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        return cacheManager;
    }

 

通过测试发现,如果我们使用注解的方式存入缓存,第一次不重写上述 spring-boot 2.x 版本 cacheManager 。

    @Cacheable(/*cacheNames = "emp"*//*,keyGenerator = "myKeyGenerator",condition = "#id > 1",unless = "#id==2"*/)
    public Employee getEmp(Integer id){
        System.out.println("查询"+id+"号员工");
        return employeeMapper.getEmpById(id);
    }

则默认使用的是jdk的序列化方式。存入redis中的对象如下图所示:

而后第二次我们重写了上述 spring-boot 2.x 版本 cacheManager 以后,我们再来通过注解来调用

    @Cacheable(/*cacheNames = "emp"*//*,keyGenerator = "myKeyGenerator",condition = "#id > 1",unless = "#id==2"*/)
    public Employee getEmp(Integer id){
        System.out.println("查询"+id+"号员工");
        return employeeMapper.getEmpById(id);
    }

@Cacheable 标注的方法的值如果被缓存后,下次会直接查询缓存。

由于我们重写了 cacheManager 以后,把默认的序列化方式改为了 JSON 格式的,缓存在反序列化时也使用 JSON 格式查询缓存,而之前使用 JDK 序列化的方式存入缓存,则会出现下列乱码现象:

 

刚接触 spring-boot,以上均为手打,如有错误望各位大佬多多指点。

参考资料:

https://blog.csdn.net/qq_33999844/article/details/82182427

https://blog.csdn.net/caojidasabi/article/details/83059642

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
org.springframework.data.redis.serializer.SerializationException是一个反序列化异常,表示在将JSON字符串转换为对象时出现了问题。具体地说,"Unrecognized field"意味着JSON字符串中包含了无法识别的字段。 这个异常通常发生在使用Spring框架的Redis序列化器时,它试图将JSON字符串反序列化为Java对象。在你提供的引用中,出现了两个例子,它们都是由于JSON字符串中的字段与Java对象的属性不匹配而引发了异常。 为了解决这个问题,你可以采取以下几个方法: 1. 使用@JsonIgnoreProperties(ignoreUnknown = true)注解 这个注解可以在类级别上使用,用于告诉Jackson JSON库在反序列化过程中忽略未知的JSON字段。在你的问题中,你可以在相关的Java类上加上这个注解以忽略无法识别的字段。 2. 使用@JsonIgnore注解 另一种解决方法是在相关的setter、getter或is方法上使用@JsonIgnore注解。这个注解可以用来忽略指定的属性,在反序列化时不会将其考虑在内。 综上所述,你可以根据具体情况选择其中一种方法来解决org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Unrecognized field异常。通过使用@JsonIgnoreProperties(ignoreUnknown = true)注解或在相关方法上使用@JsonIgnore注解,你可以告诉序列化器忽略无法识别的字段,从而避免这个异常的发生。 : org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Unrecognized field : org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Unrecognized field "accountNonLocked" : 解决办法:在类加上注解@JsonIgnoreProperties(ignoreUnknown = true)忽略实体中没有对应的json的key值,或者在set、get或is开头的方法上加上@JsonIgnore注解。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值