亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 數據庫 > Redis > 正文

使用Redis獲取數據轉json,解決動態泛型傳參的問題

2020-10-28 21:27:37
字體:
來源:轉載
供稿:網友

場景:

項目有兩種角色需要不同的登錄權限,將redis做為用戶登錄信息緩存數據庫。碼一個方法,希望能夠根據傳入不用用戶實體類型來獲取相應的數據。用戶實體為:SessionEntity<User1>、SessionEntity<User2>。json使用FastJson。

先闡述遇到的幾個問題:

1、redis獲取到的數據序列化后,轉json,經常提示轉換異常(并不是每次,只是時常)。

2、不想每種用戶都書寫一個redis操作方法(顯得tai low)。

解決:

1、redis獲取到的數據序列化后,轉json,經常提示轉換異常:

先說redis有兩種獲取方式。

1)

redisTemplate.opsForValue().get(key);

2)

SessionEntity result = redisTemplate.execute(new RedisCallback<SessionEntity>() {   public SessionEntity doInRedis(RedisConnection connection)     throws DataAccessException {    RedisSerializer<String> serializer = getRedisSerializer();    byte[] key = serializer.serialize(s);    byte[] value = connection.get(key);    if (value == null) {     return null;    }    String json = serializer.deserialize(value);    return JSONObject.parseObject(json,SessionEntity.class);   }  });

顯然第一種的方式比較簡單。查看源碼,發現第一種方式底層調用的也是redisTemplate.execute方法,所以應該算是一種封裝吧。我們一直采用的是第二種方式。(第一種方式試過,也一樣會出現json強轉異常)。這里出現過json異常,懷疑是跟泛型有關。這里手動指定泛型反序列化類型。

修改后:

SessionEntity result = redisTemplate.execute(new RedisCallback<SessionEntity>() {   public SessionEntity doInRedis(RedisConnection connection)     throws DataAccessException {    RedisSerializer<String> serializer = getRedisSerializer();    byte[] key = serializer.serialize(s);    byte[] value = connection.get(key);    if (value == null) {     return null;    }    String json = serializer.deserialize(value);    return JSONObject.parseObject(json, new TypeReference<SessionEntity<User>>(){});   }  });

完美~,確實解決了json強轉異常。

那么問題來了,這里的TypeReference需要手動指定明確的的實體類型,嘗試添加泛型:

SessionEntity<T> result = redisTemplate.execute(new RedisCallback<SessionEntity<T>>() {   public SessionEntity<T> doInRedis(RedisConnection connection)     throws DataAccessException {    RedisSerializer<String> serializer = getRedisSerializer();    byte[] key = serializer.serialize(s);    byte[] value = connection.get(key);    if (value == null) {     return null;    }    String json = serializer.deserialize(value);    return JSONObject.parseObject(json, new TypeReference<SessionEntity<T>>(){});   }  });

看樣子是沒什么問題,而且泛型也被識別到了。 但是依舊無法通過。

2、不想每種用戶都書寫一個redis操作方法:

上面說到就算加了泛型也依舊無法通過,嘗試了多種方式依舊如此。百度了一圈,都是說使用TypeReference這個來解決,但是并沒有提及動態泛型的問題。偶然間看到文章說Fastjson不支持,所以嘗試替換成jackson。

替換后的代碼:

SessionEntity<T> result = redisTemplate.execute(new RedisCallback<SessionEntity<T>>() {   public SessionEntity<T> doInRedis(RedisConnection connection)     throws DataAccessException {    RedisSerializer<String> serializer = getRedisSerializer();    byte[] key = serializer.serialize(s);    byte[] value = connection.get(key);    if (value == null) {     return null;    }    String json = serializer.deserialize(value);    ObjectMapper om = new ObjectMapper();    JavaType javatype = om.getTypeFactory().constructParametricType(SessionEntity.class, clazz);    try {     return om.readValue(json, javatype);    } catch (IOException e) {     e.printStackTrace();    }    return null;//    return JSONObject.parseObject(json, new TypeReference<SessionEntity<T>>(){});   }  });

這里使用到了jackson的ObjectMapper。ObjectMapper類是Jackson庫的主要類。它提供一些功能將轉換成Java對象匹配JSON結構,反之亦然。它使用JsonParser和JsonGenerator的實例實現JSON實際的讀/寫。(復制來的)發現問題解決。

提供的抽象方法為:

public <T> SessionEntity<T> get(final String s, Class<T> clazz);

調用方式為:

sessionEntityDao.get(key, User1.class); 跟 sessionEntityDao.get(key, User2.class);

由于這里使用到的是jackson-databind-2.6.0的庫,這個版本種constructParametricType這個方法已經快要過時,更高版本使用

constructParametrizedType

替換。這里我還沒嘗試過,等有空再玩。

這里問題已經解決,純粹做個筆記以供自己以后方便查閱。這里只提供自己項目中遇到的解決方式之一,相信應該還有其他方式可以解決。如果有說明錯誤的地方,請指出并見諒。

補充知識:Redis爬坑――Redis實現通用序列化器 & 解決Redis反序列化失敗

Redis默認序列化是 JdkSerializationRedisSerializer,由此可見

public void afterPropertiesSet() { super.afterPropertiesSet(); boolean defaultUsed = false; if (this.defaultSerializer == null) {  this.defaultSerializer = new JdkSerializationRedisSerializer(this.classLoader != null ? this.classLoader : this.getClass().getClassLoader()); } if (this.enableDefaultSerializer) {  if (this.keySerializer == null) {   this.keySerializer = this.defaultSerializer;   defaultUsed = true;  }  if (this.valueSerializer == null) {   this.valueSerializer = this.defaultSerializer;   defaultUsed = true;  }  if (this.hashKeySerializer == null) {   this.hashKeySerializer = this.defaultSerializer;   defaultUsed = true;  }  if (this.hashValueSerializer == null) {   this.hashValueSerializer = this.defaultSerializer;   defaultUsed = true;  } } if (this.enableDefaultSerializer && defaultUsed) {  Assert.notNull(this.defaultSerializer, "default serializer null and not all serializers initialized"); } if (this.scriptExecutor == null) {  this.scriptExecutor = new DefaultScriptExecutor(this); } this.initialized = true;}

這里因為我們的項目需要更改默認序列策略為Jackson2JsonRedisSerializer讓它序列化為可視化的***json***語句

我們首先定義自己的RedisTemplate,這里我們不要為了每一個類定義一個序列化器,我們定義一個統一的序列化器所以這里泛型是 <String,Object>,key我們使用StringRedisSerializer,value使用Jackson2JsonRedisSerializer

注釋代碼為修復反序列化bug的代碼

 @Bean public RedisTemplate<String, Object> objectRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {  RedisTemplate<String, Object> template = new RedisTemplate();  Jackson2JsonRedisSerializer<Object> jsonSerial = new 		 Jackson2JsonRedisSerializer(Object.class);//  //修復反序列化bug//  ObjectMapper om = new ObjectMapper();//  om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);//  om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);//  jsonSerial.setObjectMapper(om);  template.setDefaultSerializer(jsonSerial);  template.setKeySerializer(RedisSerializer.string());  template.setConnectionFactory(redisConnectionFactory);  template.afterPropertiesSet();  return template; }

測試代碼為

@Testpublic void redisSaveObject(){ UserDO ob = new UserDO(); ob.setName("name"); ob.setCity("city"); objectRedisTemplate.opsForValue().set("ob1",ob); Object ob2 = objectRedisTemplate.opsForValue().get("ob1"); UserDO ob1 = (UserDO)ob2; System.out.println(ob1);}

運行結果為

java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.hcy.core.model.UserDOat com.hcy.core.redistest.RedisTest.redisSaveObject(RedisTest.java:42)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)at 

很明顯是對象強制轉換錯誤

這是因為泛型的原因,redis在序列化時候把他當成Object序列化的,所以這里反序列化為Object是可以的,但是因為這個Object沒有類型定義所以無法強轉。

解決辦法

在RedisTemplate中對序列化器Jackson2JsonRedisSerializer進行修改添加如下代碼,上文注釋了

  //修復反序列化bug  ObjectMapper om = new ObjectMapper();  om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);  om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);  jsonSerial.setObjectMapper(om);

通過 objectMapper.enableDefaultTyping() 方法設置

即使使用 Object.class 作為 jcom.fasterxml.jackson.databind.JavaType 也可以實現相應類型的序列化和反序列化

好處:只定義一個序列化器就可以了(通用)

這里我們也做個測試,分別用不修改ObjectMapper的和修改了ObjectMapper的看看生成的value有啥子不一樣

運行結果:

ob1: [“com.hcy.core.model.UserDO”,{“userid”:null,“openid”:null,“name”:“name”,“city”:“city”}]

ob2: {“userid”:null,“openid”:null,“name”:“name”,“city”:“city”}

這里結果很明顯啦!??!

希望對大家有幫助?。?!

以上這篇使用Redis獲取數據轉json,解決動態泛型傳參的問題就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩成人在线电影网| 亚洲精品久久久久久下一站| 欧美一级黑人aaaaaaa做受| 欧美激情一区二区久久久| 日韩精品在线影院| 国产免费一区二区三区在线观看| 国产视频亚洲精品| 中文字幕亚洲精品| 91精品国产高清久久久久久久久| 日韩在线观看高清| 亚洲一区二区在线| 欧美日韩电影在线观看| 国产午夜精品免费一区二区三区| 91影视免费在线观看| 日韩av在线天堂网| 国产激情视频一区| 国产精品三级网站| 国产69久久精品成人| 国产精品免费视频久久久| 欧美视频免费在线观看| 91手机视频在线观看| 午夜精品久久久久久99热软件| 日本韩国在线不卡| 国产一区二区三区三区在线观看| 国产成人av在线| 国产精品视频地址| 亚洲视频精品在线| 中文字幕欧美日韩在线| 国产97免费视| 97在线观看免费| 91精品啪aⅴ在线观看国产| 日韩欧美在线观看视频| 色婷婷综合成人| 色播久久人人爽人人爽人人片视av| 欧美大片在线影院| 欧美综合第一页| 日韩欧美在线视频免费观看| www日韩欧美| 亚洲91精品在线观看| 久久精品视频亚洲| 91在线观看免费高清完整版在线观看| 国产人妖伪娘一区91| 国产97色在线|日韩| 国产成人在线一区二区| 亚洲男人7777| 欧美日韩中文在线| 精品亚洲永久免费精品| 欧美日韩国产精品专区| 精品久久久久久久大神国产| 欧美片一区二区三区| 亚洲欧美制服另类日韩| 日韩欧美在线网址| 国产亚洲欧洲高清| 国产精品综合不卡av| 国产精品69久久| 久久精品视频免费播放| 51精品国产黑色丝袜高跟鞋| 国产91精品久久久久久久| 亚洲国产精品久久久久久| 久久久人成影片一区二区三区| 中文字幕国产精品| 成人观看高清在线观看免费| 国产精品日韩久久久久| 亚洲直播在线一区| 欧美一区三区三区高中清蜜桃| 久久久久日韩精品久久久男男| 亚洲电影免费在线观看| 午夜美女久久久久爽久久| 国产美女久久精品| 欧美激情手机在线视频| 亚洲xxx大片| 国产精品女人久久久久久| 日韩黄色在线免费观看| 日韩美女中文字幕| 在线播放国产一区二区三区| 成人精品在线视频| 欧美午夜无遮挡| 丝袜美腿精品国产二区| 成人黄色av免费在线观看| 国产精品爽爽爽爽爽爽在线观看| 日韩精品中文字幕久久臀| 日本乱人伦a精品| 91久久在线观看| 亚洲理论在线a中文字幕| 日日噜噜噜夜夜爽亚洲精品| 欧美电影在线观看网站| 色综合久久久久久中文网| 色悠悠久久久久| 国产91网红主播在线观看| 国产精品一区久久久| 国产日韩av在线播放| 久久久av网站| 91久久国产婷婷一区二区| 欧美成人激情视频免费观看| 欧美精品亚州精品| 欧美日韩国产在线看| 欧美丰满少妇xxxxx做受| 欧美床上激情在线观看| 国产美女精品视频| 久久精品亚洲热| 亚洲男人av在线| 97超视频免费观看| 深夜福利亚洲导航| 性金发美女69hd大尺寸| 高清欧美一区二区三区| 日韩精品在线看| 国产丝袜一区视频在线观看| 啪一啪鲁一鲁2019在线视频| 亚洲福利视频网站| 91wwwcom在线观看| 国产91在线播放九色快色| 亚洲精品美女在线观看播放| 久久精品国产精品| 日韩中文字幕久久| 国产精品成人va在线观看| 亚洲欧美中文字幕在线一区| 欧美裸体男粗大视频在线观看| 国产精品天天狠天天看| 国产精品久久久久久久久久久久| 久久久国产影院| 久热精品视频在线免费观看| 中文字幕一精品亚洲无线一区| 日本sm极度另类视频| 中文字幕av一区二区| 韩国一区二区电影| 亚州国产精品久久久| 亚洲免费视频观看| 欧美性猛交xxxx黑人| 深夜福利一区二区| 色妞一区二区三区| 一级做a爰片久久毛片美女图片| …久久精品99久久香蕉国产| 7777免费精品视频| 欧美久久精品一级黑人c片| 国产精品网红直播| 久久理论片午夜琪琪电影网| 国产91对白在线播放| 亚洲黄色www网站| 欧美激情一区二区三区久久久| 国产国语videosex另类| www.欧美精品| 亚洲另类xxxx| 国产偷亚洲偷欧美偷精品| 国产伦精品免费视频| 亚洲久久久久久久久久| 国产97色在线|日韩| 性欧美长视频免费观看不卡| 久久久久久久久久久久av| 91精品国产91久久久久福利| 自拍亚洲一区欧美另类| 少妇av一区二区三区| 欧美大片在线免费观看| 亚洲精品99久久久久中文字幕| 欧美激情二区三区| 日本三级韩国三级久久| 一夜七次郎国产精品亚洲| 欧美精品久久久久| 日本国产精品视频| 在线看欧美日韩| 国产精品手机播放| 日本一欧美一欧美一亚洲视频| 欧美精品精品精品精品免费| 久久综合88中文色鬼| 日韩中文字幕在线免费观看|