Redis @type坑的解决

 更新时间:2024年06月03日 11:11:55   作者:strggle_bin  
新建一个对象存入redis中,对象中会出现一个字段@type,本文主要介绍了Redis @type坑的解决,具有一定的参考价值,感兴趣的可以了解一下

redis中@type导致取数据解析报错

java.lang.ClassCastException: com.alibaba.fastjson.JSONObject cannot be cast to
新建一个对象存入redis中,对象中会出现一个字段@type

LoginUser user = new LoginUser ()
......
redisTemplate.opsForValue().set(key, user)

存入redis中数据如下

127.0.0.1:6379> get login_tokens:5be4de32-6eb5-44a5-b212-56d93e3fc067
"{\"@type\":\"com.common.core.domain.model.LoginUser\",\"deptId\":103L,\"expireTime\":1710463649132,\"token\":\"xxxx\",\"user\":{\"admin\":true,\"createBy\":\"admin\",\"dept\":{\"deptId\":103L,\"deptName\":\"xxx",\"orderNum\":1,\"params\":{\"@type\":\"java.util.HashMap\"},\"parentId\":101L,\"status\":\"0\"},\"deptId\":103L,\"loginDate\":\"2024-03-14 14:35:56\",\"loginIp\":\"127.0.0.1\",\"nickName\":\"xxx\",\"params\":{\"@type\":\"java.util.HashMap\"},\"phonenumber\":\"15888888888\",\"sex\":\"1\",\"status\":\"0\",\"userId\":1L,\"userName\":\"admin\"},\"userId\":1L,\"username\":\"admin\"}"
127.0.0.1:6379>

取数据时,redisTemplate.opsForValue().get(key);
如果LoginUser对象的包与存入时的包路径不一致,会报错java.lang.ClassCastException: com.alibaba.fastjson.JSONObject cannot be cast to

redis缓存序列化导致存储数据没有@type

在使用redis注解将数据缓存的时候发现存储进去的数据是这样的,没有@type

127.0.0.1:6379> get login_tokens:5be4de32-6eb5-44a5-b212-56d93e3fc067
"{\"deptId\":103L,\"expireTime\":1710463649132,\"token\":\"xxxx\",\"user\":{\"admin\":true,\"createBy\":\"admin\",\"dept\":{\"deptId\":103L,\"deptName\":\"xxx",\"orderNum\":1,\"parentId\":101L,\"status\":\"0\"},\"deptId\":103L,\"loginDate\":\"2024-03-14 14:35:56\",\"loginIp\":\"127.0.0.1\",\"nickName\":\"xxx\",\"phonenumber\":\"15888888888\",\"sex\":\"1\",\"status\":\"0\",\"userId\":1L,\"userName\":\"admin\"},\"userId\":1L,\"username\":\"admin\"}"
127.0.0.1:6379>

之前通过set方法放进去的数据是这样的

127.0.0.1:6379> get login_tokens:5be4de32-6eb5-44a5-b212-56d93e3fc067
"{\"@type\":\"com.common.core.domain.model.LoginUser\",\"deptId\":103L,\"expireTime\":1710463649132,\"token\":\"xxxx\",\"user\":{\"admin\":true,\"createBy\":\"admin\",\"dept\":{\"deptId\":103L,\"deptName\":\"xxx",\"orderNum\":1,\"params\":{\"@type\":\"java.util.HashMap\"},\"parentId\":101L,\"status\":\"0\"},\"deptId\":103L,\"loginDate\":\"2024-03-14 14:35:56\",\"loginIp\":\"127.0.0.1\",\"nickName\":\"xxx\",\"params\":{\"@type\":\"java.util.HashMap\"},\"phonenumber\":\"15888888888\",\"sex\":\"1\",\"status\":\"0\",\"userId\":1L,\"userName\":\"admin\"},\"userId\":1L,\"username\":\"admin\"}"
127.0.0.1:6379>

原因:
是因为set方法的序列化方法和注解的序列化方法不同

在这里插入图片描述

解决办法:
将序列化方法更换成set方法所使用的序列化方法

下面是序列化方法

public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> {
    @SuppressWarnings("unused")
    private ObjectMapper objectMapper = new ObjectMapper();

    public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;

    private Class<T> clazz;

    static {
        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
    }

    public FastJson2JsonRedisSerializer(Class<T> clazz) {
        super();
        this.clazz = clazz;
    }

    @Override
    public byte[] serialize(T t) throws SerializationException {
        if (t == null) {
            return new byte[0];
        }
        return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
    }

    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
        if (bytes == null || bytes.length <= 0) {
            return null;
        }
        String str = new String(bytes, DEFAULT_CHARSET);
        return JSON.parseObject(str, clazz);
    }

    public void setObjectMapper(ObjectMapper objectMapper) {
        Assert.notNull(objectMapper, "'objectMapper' must not be null");
        this.objectMapper = objectMapper;
    }

    protected JavaType getJavaType(Class<?> clazz) {
        return TypeFactory.defaultInstance().constructType(clazz);
    }
}

SerializerFeature.WriteClassName这个序列化

public static String getString(Object object) {
   return JSON.toJSONString(object, SerializerFeature.WriteClassName);
}

如果加了SerializerFeature.WriteClassName存进redis当中的实体类就会带@type路径地址
“@type”:“com.xxx.xxx.entity.OpenNotice”

问题解决方案:去掉@type 或者 两边@type路径存放路径一致 (包名和实体类修改为一致)

去掉@type使用 JSONObject.toJSONString(obj)来存value实体类

    /**
     * hashMap存值方式
     *
     * @param parentKey
     * @param fieldKey
     * @param obj
     */
    public static void hashSet(String parentKey, String fieldKey, Object obj) {
        try {
            jedis.hset(parentKey, fieldKey, JSONObject.toJSONString(obj));
            //jedis.hset(parentKey, fieldKey, JSONParser.getString(obj)); //"@type":"com.xyz.miniLegion.entity.OpenNotice"
        } finally {
            jedis.close();
        }
    }

获取hashAll数据

   /**
     * 获取hashGetAll
     * @param parentKey
     * @return
     */
    public Map<String, String> hashGetAll(String parentKey) {
        try (Jedis jedis = pools.getResource()) { //这种写法不需要手动close();
            return jedis.hgetAll(parentKey);
        }catch (Exception e) {      
            return null;
        }
    }

测试Redis转实体类`

   @Test
    void getSoldierAttribute() {
        Map<String, String> openNoticeMap = redisPoolMgr.hashGetAll(StaticData.OpenNotice);
        //第一种根据key循环
        for (String key : openNoticeMap.keySet()) {
            OpenNotice openNotice = JSONObject.parseObject(openNoticeMap.get(key), OpenNotice.class);
            System.out.println("根据key循环:" +openNotice.getContent());
            System.out.println("根据key循环:" + JSONObject.toJSONString(openNotice));
        }
 
        //第二种根据value循环
        for (String values : openNoticeMap.values()) {
            OpenNotice openNotice = JSONObject.parseObject(values, OpenNotice.class);
            System.out.println("根据value循环:"+openNotice.getContent());
            System.out.println("根据value循环:" + JSONObject.toJSONString(openNotice));
        }
    }

在这里插入图片描述

 到此这篇关于Redis @type坑的解决的文章就介绍到这了,更多相关Redis @type坑内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • redis启动失败原因分析及解决过程

    redis启动失败原因分析及解决过程

    文章描述了在Windows系统上启动Redis服务器时遇到的启动失败问题,并通过重启Redis服务器解决了问题,在解决问题的过程中,作者还展示了如何使用redis-cli.exe和shutdown命令来管理和关闭Redis服务器
    2026-03-03
  • Redis全文搜索教程之创建索引并关联源数据的教程

    Redis全文搜索教程之创建索引并关联源数据的教程

    RediSearch提供了一种简单快速的方法对 hash 或者 json 类型数据的任何字段建立二级索引,然后就可以对被索引的 hash 或者 json 类型数据字段进行搜索和聚合操作,这篇文章主要介绍了Redis全文搜索教程之创建索引并关联源数据,需要的朋友可以参考下
    2023-12-12
  • 基于Redis实现双加密Token的示例代码

    基于Redis实现双加密Token的示例代码

    在现代分布式系统中,Token管理是身份验证和授权的核心部分,本文将深入分析一个基于Redis的Token管理实现,探讨其设计思路、关键代码逻辑以及实现细节,通过对源码的逐层剖析,帮助读者更好地理解Token管理的实现原理,需要的朋友可以参考下
    2025-01-01
  • Linux服务器Redis6.x安装、配置全过程

    Linux服务器Redis6.x安装、配置全过程

    Redis是一个高性能的键值对数据库,支持多种数据类型和持久化方式,它在缓存、分布式系统、聊天室、任务队列等领域有广泛应用,本文详细介绍了Redis的安装、配置、高级类型和持久化机制
    2026-03-03
  • Redis 中使用 list,streams,pub/sub 几种方式实现消息队列的问题

    Redis 中使用 list,streams,pub/sub 几种方式实现消息队列的问题

    这篇文章主要介绍了Redis 中使用 list,streams,pub/sub 几种方式实现消息队列,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-03-03
  • mac安装redis全过程

    mac安装redis全过程

    文章内容主要介绍了如何从官网下载指定版本的Redis,以及如何在自定义目录下安装和启动Redis,还提到了如何修改Redis的密码和配置文件,以及使用RedisInsight进行可视化管理,最后,总结了一些常用的Redis命令
    2025-01-01
  • 使用Redis存储SpringBoot项目中Session的详细步骤

    使用Redis存储SpringBoot项目中Session的详细步骤

    在开发Spring Boot项目时,我们通常会遇到如何高效管理Session的问题,默认情况下,Spring Boot会将Session存储在内存中,今天,我们将学习如何将Session存储从内存切换到Redis,并验证配置是否成功,需要的朋友可以参考下
    2024-06-06
  • Redis Desktop Manager(Redis可视化工具)安装及使用图文教程

    Redis Desktop Manager(Redis可视化工具)安装及使用图文教程

    这篇文章主要介绍了Redis Desktop Manager(Redis可视化工具)安装及使用图文教程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-04-04
  • Redis主从复制的实现示例

    Redis主从复制的实现示例

    Redis主从复制实现多机备份,本文就来介绍一下Redis主从复制的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-11-11
  • Redis主从复制详解

    Redis主从复制详解

    今天小编就为大家分享一篇关于Redis主从复制详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-01-01

最新评论