54138qqqq
54138qqqq

Reputation: 127

How to Serialize Java Object into json and Reverse Json to Object when using springboot with Redis?

I am using SpringBoot with Redis And want to serial object UserDO into Json, store it in Redis, and get the json data, reverse it into UserDO Object. This is UserDO

public class UserDO {
String name;
int age;
String password;

// Getters and Setters are not here 

} This is how I set the Serializer:

@Configuration

public class RedisTemplateConfiguration {

@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {

    RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
    redisTemplate.setConnectionFactory(redisConnectionFactory);

    // 使用Jackson2JsonRedisSerialize 替换默认序列化
    Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

    // 设置key和value的序列化规则
    redisTemplate.setKeySerializer(new StringRedisSerializer());
    redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);

    // 设置hashKey和hashValue的序列化规则
    redisTemplate.setHashKeySerializer(new StringRedisSerializer());
    redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);

    // 设置支持事物
    //redisTemplate.setEnableTransactionSupport(true);

    redisTemplate.afterPropertiesSet();

    return redisTemplate;
}

}

It works when I use redisTemplate.opsForValue().set("user-service:user:2",userDO);

But when I Run uo = (UserDO)redisTemplate.opsForValue().get("user-service:user:2") I got a LinkedHashMap

@Test
void testSeriable(){
    User user = new User();
    user.setAge(18);
    user.setName("William");
    user.setPwd("testpwd");
    redisTemplate.opsForValue().set("user:2", user);

    System.out.println(redisTemplate.opsForValue().get("user:2").getClass());
    Map<String, String> res = ((LinkedHashMap<String, String>)redisTemplate.opsForValue().get("user:2"));
    System.out.println(res);
    /*
    class java.util.LinkedHashMap
    {name=William, age=18, pwd=testpwd}
     */

    redisTemplate.opsForList().leftPushAll("testkey", user, user, user);
    List<User> list = redisTemplate.opsForList().range("testkey", 0, -1);
    System.out.println(list);
    /*
    This works fine!
    [{name=William, age=18, pwd=testpwd}, {name=William, age=18, pwd=testpwd}, {name=William, age=18, pwd=testpwd}]
     */
}

So How can I get User directly from redisTemplate.opsForList().get() ?

Upvotes: 1

Views: 5271

Answers (2)

BSB
BSB

Reputation: 1705

I think you want your template typed to a specific type of key and model, something like:

@Bean
public RedisTemplate<String, Person> redisTemplate() {
  RedisTemplate<String, User> redisTemplate = new RedisTemplate<>();
  redisTemplate.setConnectionFactory(redisConnectionFactory());
  redisTemplate.setEnableTransactionSupport(true);
  
  Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

  ObjectMapper objectMapper = new ObjectMapper();
  objectMapper.setVisibility(PropertyAccessor.ALL,  JsonAutoDetect.Visibility.ANY);
  jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

  redisTemplate.setKeySerializer(new StringRedisSerializer());
  redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);

  redisTemplate.setHashKeySerializer(new StringRedisSerializer());
  redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);

  return redisTemplate;
}

You'll need a Primary Key for your DTO object so that SDR can use it to construct a key. It'll be the fully qualified class name by default + ":" + your PK.

Upvotes: 2

Suhas Kashyap
Suhas Kashyap

Reputation: 438

you can write a generic methods to serialize data and deserialize data using a particular class object

For this i am using

com.fasterxml.jackson.databind

you can add it in your pom.xml

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.0</version>
</dependency>

and in your Redis impl class you add these two methods

public final static String INVALID_SERIALIZATION_OR_DESERIALIZATION = "Invalid type passed for marshalling";

public String serializeData(T modelClass)
        throws SerializationOrDeserializationException {
    try {
        return objectMapper.writeValueAsString(modelClass);
    } catch (Exception e) {
        LOGGER.error("{}", e);
        throw new SerializationOrDeserializationException(INVALID_SERIALIZATION_OR_DESERIALIZATION);
    }
}

public T deserializeData(String value, Class<T> type) {
    try {
        if (value == null) {
            return null;
        }
        return objectMapper.readValue(value, type);
    } catch (Exception e) {
        LOGGER.error("{}", e);
        throw new SerializationOrDeserializationException(INVALID_SERIALIZATION_OR_DESERIALIZATION);
    }
}

And in you can create a custom exeception

public class SerializationOrDeserializationException extends RuntimeException {
    public SerializationOrDeserializationException(String message) {
        super(message);
    }
}

Then you can use serialize desrialize in following fashion

className.deserializeData('json_sring',User.class);
className.serializeData(userObject);

Upvotes: 1

Related Questions