亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

 更新時(shí)間:2020年07月16日 10:53:58   作者:有一只柴犬  
這篇文章主要介紹了使用Redis獲取數(shù)據(jù)轉(zhuǎn)json,解決動(dòng)態(tài)泛型傳參的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧

場(chǎng)景:

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

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

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

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

解決:

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

先說(shuō)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)該算是一種封裝吧。我們一直采用的是第二種方式。(第一種方式試過(guò),也一樣會(huì)出現(xiàn)json強(qiáng)轉(zhuǎn)異常)。這里出現(xiàn)過(guò)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)異常。

那么問(wèn)題來(lái)了,這里的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>>(){});
   }
  });

看樣子是沒(méi)什么問(wèn)題,而且泛型也被識(shí)別到了。 但是依舊無(wú)法通過(guò)。

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

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

constructParametrizedType

替換。這里我還沒(méi)嘗試過(guò),等有空再玩。

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

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

Redis默認(rèn)序列化是 JdkSerializationRedisSerializer,由此可見(jiàn)

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***語(yǔ)句

我們首先定義自己的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è)試代碼為

@Test
public 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.UserDO
at 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)榉盒偷脑?,redis在序列化時(shí)候把他當(dāng)成Object序列化的,所以這里反序列化為Object是可以的,但是因?yàn)檫@個(gè)Object沒(méi)有類型定義所以無(wú)法強(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);

通過(guò) 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)泛型傳參的問(wèn)題就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Reactor?WebFlux集成Redis處理緩存操作

    Reactor?WebFlux集成Redis處理緩存操作

    這篇文章主要為大家介紹了Reactor?WebFlux集成Redis處理緩存操作示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • Redis集群下過(guò)期key監(jiān)聽(tīng)的實(shí)現(xiàn)代碼

    Redis集群下過(guò)期key監(jiān)聽(tīng)的實(shí)現(xiàn)代碼

    這篇文章主要介紹了Redis集群下過(guò)期key監(jiān)聽(tīng)的實(shí)現(xiàn)代碼,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-09-09
  • 從源碼解讀redis持久化

    從源碼解讀redis持久化

    redis的持久化也就是數(shù)據(jù)落地,對(duì)于任何一個(gè)數(shù)據(jù)系統(tǒng)都要考慮是不是需要數(shù)據(jù)落地。在系統(tǒng)崩潰或是機(jī)房掉電等的情況下,將有用的數(shù)據(jù)記錄在非易失性存儲(chǔ)器上面,防止數(shù)據(jù)丟失,以及用來(lái)系統(tǒng)重啟時(shí)的數(shù)據(jù)恢復(fù)。
    2018-08-08
  • redis啟動(dòng)和退出命令行簡(jiǎn)單操作步驟

    redis啟動(dòng)和退出命令行簡(jiǎn)單操作步驟

    Redis是一種鍵值存儲(chǔ)數(shù)據(jù)庫(kù),用戶可以使用它來(lái)存儲(chǔ)和檢索大量的鍵值數(shù)據(jù),下面這篇文章主要給大家介紹了關(guān)于redis啟動(dòng)和退出命令行的相關(guān)資料,需要的朋友可以參考下
    2024-03-03
  • redis專屬鏈表ziplist的使用

    redis專屬鏈表ziplist的使用

    本文主要介紹了redis專屬鏈表ziplist的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • Redis高并發(fā)超賣問(wèn)題解決方案圖文詳解

    Redis高并發(fā)超賣問(wèn)題解決方案圖文詳解

    Redis是一種基于內(nèi)存的數(shù)據(jù)存儲(chǔ)系統(tǒng),被廣泛用于解決高并發(fā)問(wèn)題,下面這篇文章主要給大家介紹了關(guān)于Redis高并發(fā)超賣問(wèn)題解決方案的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-02-02
  • Redis系列之底層數(shù)據(jù)結(jié)構(gòu)SDS詳解

    Redis系列之底層數(shù)據(jù)結(jié)構(gòu)SDS詳解

    SDS(簡(jiǎn)單動(dòng)態(tài)字符串)是Redis使用的核心數(shù)據(jù)結(jié)構(gòu),用于替代C語(yǔ)言的字符串,以解決長(zhǎng)度獲取慢、內(nèi)存溢出等問(wèn)題,SDS通過(guò)預(yù)分配與惰性釋放策略優(yōu)化內(nèi)存使用,增強(qiáng)安全性,且能存儲(chǔ)文本與二進(jìn)制數(shù)據(jù),可查看源碼src/sds.h和src/sds.c了解更多
    2024-11-11
  • Redisson實(shí)現(xiàn)分布式鎖、鎖續(xù)約的案例

    Redisson實(shí)現(xiàn)分布式鎖、鎖續(xù)約的案例

    這篇文章主要介紹了Redisson如何實(shí)現(xiàn)分布式鎖、鎖續(xù)約,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-03-03
  • Redis中的Lettuce使用詳解

    Redis中的Lettuce使用詳解

    Lettuce 是一個(gè)高級(jí)的、線程安全的 Redis 客戶端,用于與 Redis 數(shù)據(jù)庫(kù)交互,Lettuce 是一個(gè)功能強(qiáng)大、使用方便的 Redis 客戶端,適用于各種規(guī)模的 Java 項(xiàng)目,下面給大家介紹Redis中的Lettuce使用詳解,感興趣的朋友一起看看吧
    2025-05-05
  • Redis中Hash類型的使用

    Redis中Hash類型的使用

    本文主要介紹了Redis中Hash類型的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06

最新評(píng)論