麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 數(shù)據(jù)庫 > Redis > 正文

使用Redis獲取數(shù)據(jù)轉(zhuǎn)json,解決動(dòng)態(tài)泛型傳參的問題

2020-10-28 21:27:37
字體:
供稿:網(wǎng)友

場(chǎng)景:

項(xiàng)目有兩種角色需要不同的登錄權(quán)限,將redis做為用戶登錄信息緩存數(shù)據(jù)庫。碼一個(gè)方法,希望能夠根據(jù)傳入不用用戶實(shí)體類型來獲取相應(yīng)的數(shù)據(jù)。用戶實(shí)體為:SessionEntity<User1>、SessionEntity<User2>。json使用FastJson。

先闡述遇到的幾個(gè)問題:

1、redis獲取到的數(shù)據(jù)序列化后,轉(zhuǎn)json,經(jīng)常提示轉(zhuǎn)換異常(并不是每次,只是時(shí)常)。

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

解決:

1、redis獲取到的數(shù)據(jù)序列化后,轉(zhuǎn)json,經(jīng)常提示轉(zhuǎn)換異常:

先說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);   }  });

顯然第一種的方式比較簡(jiǎn)單。查看源碼,發(fā)現(xiàn)第一種方式底層調(diào)用的也是redisTemplate.execute方法,所以應(yīng)該算是一種封裝吧。我們一直采用的是第二種方式。(第一種方式試過,也一樣會(huì)出現(xiàn)json強(qiáng)轉(zhuǎn)異常)。這里出現(xiàn)過json異常,懷疑是跟泛型有關(guān)。這里手動(dòng)指定泛型反序列化類型。

修改后:

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>>(){});   }  });

完美~,確實(shí)解決了json強(qiáng)轉(zhuǎn)異常。

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

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>>(){});   }  });

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

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

上面說到就算加了泛型也依舊無法通過,嘗試了多種方式依舊如此。百度了一圈,都是說使用TypeReference這個(gè)來解決,但是并沒有提及動(dòng)態(tài)泛型的問題。偶然間看到文章說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庫的主要類。它提供一些功能將轉(zhuǎn)換成Java對(duì)象匹配JSON結(jié)構(gòu),反之亦然。它使用JsonParser和JsonGenerator的實(shí)例實(shí)現(xiàn)JSON實(shí)際的讀/寫。(復(fù)制來的)發(fā)現(xiàn)問題解決。

提供的抽象方法為:

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

調(diào)用方式為:

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

由于這里使用到的是jackson-databind-2.6.0的庫,這個(gè)版本種constructParametricType這個(gè)方法已經(jīng)快要過時(shí),更高版本使用

constructParametrizedType

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

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

補(bǔ)充知識(shí):Redis爬坑――Redis實(shí)現(xiàn)通用序列化器 & 解決Redis反序列化失敗

Redis默認(rèn)序列化是 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;}

這里因?yàn)槲覀兊捻?xiàng)目需要更改默認(rèn)序列策略為Jackson2JsonRedisSerializer讓它序列化為可視化的***json***語句

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

注釋代碼為修復(fù)反序列化bug的代碼

 @Bean public RedisTemplate<String, Object> objectRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {  RedisTemplate<String, Object> template = new RedisTemplate();  Jackson2JsonRedisSerializer<Object> jsonSerial = new 		 Jackson2JsonRedisSerializer(Object.class);//  //修復(fù)反序列化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; }

測(cè)試代碼為

@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);}

運(yùn)行結(jié)果為

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 

很明顯是對(duì)象強(qiáng)制轉(zhuǎn)換錯(cuò)誤

這是因?yàn)榉盒偷脑颍瑀edis在序列化時(shí)候把他當(dāng)成Object序列化的,所以這里反序列化為Object是可以的,但是因?yàn)檫@個(gè)Object沒有類型定義所以無法強(qiáng)轉(zhuǎn)。

解決辦法

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

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

通過 objectMapper.enableDefaultTyping() 方法設(shè)置

即使使用 Object.class 作為 jcom.fasterxml.jackson.databind.JavaType 也可以實(shí)現(xiàn)相應(yīng)類型的序列化和反序列化

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

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

運(yùn)行結(jié)果:

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

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

這里結(jié)果很明顯啦!!!

希望對(duì)大家有幫助!!!

以上這篇使用Redis獲取數(shù)據(jù)轉(zhuǎn)json,解決動(dòng)態(tài)泛型傳參的問題就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持武林網(wǎng)。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 欧产日产国产精品v | 免费一级肉体全黄毛片 | 毛片哪里看 | 91成人天堂久久成人 | 全黄性性激高免费视频 | 99精品国产一区二区三区 | 国产一级毛片国产 | 亚洲成人精品在线 | 欧美精品成人一区二区三区四区 | 色综合精品| 成年免费视频黄网站在线观看 | 色呦呦一区二区三区 | 欧美激情第一区 | www.99re14.com| 视频二区国产 | 九九热在线视频观看 | 欧日一级片 | av日韩一区二区三区 | 国产午夜免费福利 | 久久免费视频7 | 成人国产综合 | 亚洲欧美一区二区三区在线观看 | china对白普通话xxxx | 欧美成人免费小视频 | 亚洲午夜1000理论片aa | 蜜桃成品人免费视频 | 热99视频 | 国产精品久久久久av | xnxx 美女19| 91成人天堂久久成人 | 综合国产一区 | 亚洲啊v在线观看 | 日本在线播放一区二区三区 | 羞羞色在线观看 | 亚洲码无人客一区二区三区 | 日本最新免费二区三区 | 国产免费小视频在线观看 | www.91sese| 国产成人高清在线观看 | 精品久久久91 | 看免费一级毛片 |