Redis @type坑的解決
redis中@type導(dǎo)致取數(shù)據(jù)解析報(bào)錯(cuò)
java.lang.ClassCastException: com.alibaba.fastjson.JSONObject cannot be cast to
新建一個(gè)對(duì)象存入redis中,對(duì)象中會(huì)出現(xiàn)一個(gè)字段@type
LoginUser user = new LoginUser () ...... redisTemplate.opsForValue().set(key, user)
存入redis中數(shù)據(jù)如下
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>
取數(shù)據(jù)時(shí),redisTemplate.opsForValue().get(key);
如果LoginUser對(duì)象的包與存入時(shí)的包路徑不一致,會(huì)報(bào)錯(cuò)java.lang.ClassCastException: com.alibaba.fastjson.JSONObject cannot be cast to
redis緩存序列化導(dǎo)致存儲(chǔ)數(shù)據(jù)沒(méi)有@type
在使用redis注解將數(shù)據(jù)緩存的時(shí)候發(fā)現(xiàn)存儲(chǔ)進(jìn)去的數(shù)據(jù)是這樣的,沒(méi)有@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>
之前通過(guò)set方法放進(jìn)去的數(shù)據(jù)是這樣的
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>
原因:
是因?yàn)閟et方法的序列化方法和注解的序列化方法不同
解決辦法:
將序列化方法更換成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這個(gè)序列化
public static String getString(Object object) { return JSON.toJSONString(object, SerializerFeature.WriteClassName); }
如果加了SerializerFeature.WriteClassName存進(jìn)redis當(dāng)中的實(shí)體類就會(huì)帶@type路徑地址
“@type”:“com.xxx.xxx.entity.OpenNotice”
問(wèn)題解決方案:去掉@type 或者 兩邊@type路徑存放路徑一致 (包名和實(shí)體類修改為一致)
去掉@type使用 JSONObject.toJSONString(obj)來(lái)存value實(shí)體類
/** * 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數(shù)據(jù)
/** * 獲取hashGetAll * @param parentKey * @return */ public Map<String, String> hashGetAll(String parentKey) { try (Jedis jedis = pools.getResource()) { //這種寫法不需要手動(dòng)close(); return jedis.hgetAll(parentKey); }catch (Exception e) { return null; } }
測(cè)試Redis轉(zhuǎn)實(shí)體類`
@Test void getSoldierAttribute() { Map<String, String> openNoticeMap = redisPoolMgr.hashGetAll(StaticData.OpenNotice); //第一種根據(jù)key循環(huán) for (String key : openNoticeMap.keySet()) { OpenNotice openNotice = JSONObject.parseObject(openNoticeMap.get(key), OpenNotice.class); System.out.println("根據(jù)key循環(huán):" +openNotice.getContent()); System.out.println("根據(jù)key循環(huán):" + JSONObject.toJSONString(openNotice)); } //第二種根據(jù)value循環(huán) for (String values : openNoticeMap.values()) { OpenNotice openNotice = JSONObject.parseObject(values, OpenNotice.class); System.out.println("根據(jù)value循環(huán):"+openNotice.getContent()); System.out.println("根據(jù)value循環(huán):" + JSONObject.toJSONString(openNotice)); } }
到此這篇關(guān)于Redis @type坑的解決的文章就介紹到這了,更多相關(guān)Redis @type坑內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Redis實(shí)現(xiàn)庫(kù)存扣減的解決方案防止商品超賣
在日常開(kāi)發(fā)中有很多地方都有類似扣減庫(kù)存的操作,比如電商系統(tǒng)中的商品庫(kù)存,抽獎(jiǎng)系統(tǒng)中的獎(jiǎng)品庫(kù)存等,基于redis實(shí)現(xiàn)扣減庫(kù)存的具體實(shí)現(xiàn),初始化庫(kù)存回調(diào)函數(shù)(IStockCallback)扣減庫(kù)存服務(wù)(StockService),感興趣的朋友跟隨小編一起看看吧2022-06-06AOP?Redis自定義注解實(shí)現(xiàn)細(xì)粒度接口IP訪問(wèn)限制
這篇文章主要為大家介紹了AOP?Redis自定義注解實(shí)現(xiàn)細(xì)粒度接口IP訪問(wèn)限制,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10Spring+Redis+RabbitMQ開(kāi)發(fā)限流和秒殺項(xiàng)目功能
本項(xiàng)目將通過(guò)整合Springboot和Redis以及Lua腳本來(lái)實(shí)現(xiàn)限流和秒殺的效果,將通過(guò)RabbitMQ消息隊(duì)列來(lái)實(shí)現(xiàn)異步保存秒殺結(jié)果的效果,對(duì)Spring?Redis?RabbitMQ限流秒殺功能實(shí)現(xiàn)感興趣的朋友一起看看吧2022-02-02Redis遠(yuǎn)程字典服務(wù)器?hash類型示例詳解
這篇文章主要介紹了Redis遠(yuǎn)程字典服務(wù)器?hash類型示例詳解,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-08-08Ubuntu下Redis密碼設(shè)置問(wèn)題及其解決過(guò)程
這篇文章主要介紹了Ubuntu下Redis密碼設(shè)置問(wèn)題及其解決過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06Redis如何實(shí)現(xiàn)計(jì)數(shù)統(tǒng)計(jì)
這篇文章主要介紹了Redis如何實(shí)現(xiàn)計(jì)數(shù)統(tǒng)計(jì)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04