Redis @type坑的解決
redis中@type導致取數(shù)據(jù)解析報錯
java.lang.ClassCastException: com.alibaba.fastjson.JSONObject cannot be cast to
新建一個對象存入redis中,對象中會出現(xiàn)一個字段@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ù)時,redisTemplate.opsForValue().get(key);
如果LoginUser對象的包與存入時的包路徑不一致,會報錯java.lang.ClassCastException: com.alibaba.fastjson.JSONObject cannot be cast to
redis緩存序列化導致存儲數(shù)據(jù)沒有@type
在使用redis注解將數(shù)據(jù)緩存的時候發(fā)現(xiàn)存儲進去的數(shù)據(jù)是這樣的,沒有@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方法放進去的數(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>
原因:
是因為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數(shù)據(jù)
/** * 獲取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轉(zhuǎn)實體類`
@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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
AOP?Redis自定義注解實現(xiàn)細粒度接口IP訪問限制
這篇文章主要為大家介紹了AOP?Redis自定義注解實現(xiàn)細粒度接口IP訪問限制,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-10-10Spring+Redis+RabbitMQ開發(fā)限流和秒殺項目功能
本項目將通過整合Springboot和Redis以及Lua腳本來實現(xiàn)限流和秒殺的效果,將通過RabbitMQ消息隊列來實現(xiàn)異步保存秒殺結(jié)果的效果,對Spring?Redis?RabbitMQ限流秒殺功能實現(xiàn)感興趣的朋友一起看看吧2022-02-02Redis如何實現(xiàn)計數(shù)統(tǒng)計
這篇文章主要介紹了Redis如何實現(xiàn)計數(shù)統(tǒng)計方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-04-04