将springboot与Redis一起使用时如何将Java对象序列化为json并将Json反向序列化为对象?

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

我正在使用 SpringBoot 和 Redis 并且想将对象 UserDO 序列化为 Json,将其存储在 Redis 中,并获取 json 数据,将其反转为 UserDO 对象。 这是 UserDO

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

// Getters and Setters are not here 

} 这就是我设置序列化程序的方式:

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

}

当我使用 redisTemplate.opsForValue().set("user-service:user:2",userDO);

时有效

但是当我运行uo = (UserDO)redisTemplate.opsForValue().get("user-service:user:2") 我有一个 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}]
     */
}

那么如何直接从 redisTemplate.opsForList().get() 获取用户?

您可以使用特定的 class 对象编写通用方法来序列化数据和反序列化数据

为此我正在使用

com.fasterxml.jackson.databind

您可以将其添加到您的 pom.xml

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

并在您的 Redis impl class 中添加这两个方法

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

并且您可以在其中创建自定义异常

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

然后您可以按照以下方式使用序列化反序列化

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

我认为您希望您的模板输入特定类型的密钥和模型,例如:

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

您的 DTO 对象需要一个主键,以便 SDR 可以使用它来构造一个键。默认情况下,它将是完全限定的 class 名称 +“:”+ 您的 PK。