猿问

具有复杂密钥的 SpringData Redis 存储库

CrudRepository我们尝试在项目中使用 Spring Data来为域对象提供持久性。
首先,我选择 REDIS 作为后端,因为在第一次实验中CrudRepository<ExperimentDomainObject, String>,它的运行似乎很容易。

当尝试将其放入我们的生产代码中时,事情变得更加复杂,因为这里我们的域对象不需要使用简单类型作为密钥,因此存储库是CrudRepository<TestObject, ObjectId>.

现在我得到了例外:

找不到能够从类型 [...ObjectId] 转换为类型 [byte[]] 的转换器

寻找这个异常,这个答案导致我对RedisTemplate配置进行了未经教育的实验。(对于我的实验,我使用的是 emdedded-redis)

我的想法是,提供一个RedisTemplate<Object, Object>而不是RedisTemplate<String, Object>允许使用Jackson2JsonRedisSerializerkeySerializer 来完成工作。

尽管如此,调用还是testRepository.save(testObject)失败。

请看我的代码:

为了简洁起见,我有公共字段并省略了导入。如果需要它们(使其成为 MVCE),我将很乐意提供它们。请给我留言。

依赖项:

dependencies {

    implementation 'org.springframework.boot:spring-boot-starter-data-redis'

    implementation 'org.springframework.boot:spring-boot-starter-web'

    compileOnly 'org.projectlombok:lombok'

    annotationProcessor 'org.projectlombok:lombok'

    implementation group: 'redis.clients', name: "jedis", version: '2.9.0'

    implementation group: 'it.ozimov', name: 'embedded-redis', version: '0.7.2'

}

Redis配置:


@Configuration

@EnableRedisRepositories

public class RedisConfiguration {

    @Bean

    JedisConnectionFactory jedisConnectionFactory() {

        return new JedisConnectionFactory();

    }

}

不是想要的答案:

当然,我可能会引入一些特殊的 ID,它是一种简单的数据类型,例如我使用 jacksons ObjectMapper 手动构建的 JSON-String,然后使用CrudRepository<TestObject, String>.

同时我也尝试过:

  • RedisTemplate<String, String>

  • RedisTemplate<String, Object>

  • 自动装配 aRedisTemplate并设置其默认序列化器

  • 注册一个Converter<ObjectId, byte[]>

    • 自动装配的ConverterRegistry

    • 一个自动接线GenericConversionService
      ,但显然他们是错误的


慕森卡
浏览 81回答 1
1回答

皈依舞

基本上,Redis 存储库使用RedisKeyValueTemplate底层将数据存储为键(Id)和值对。所以除非你直接使用它,否则你的配置RedisTemplate将不起作用。因此,您的一种方法是RedistTemplate直接使用,这样的东西对您有用。@Servicepublic class TestService {&nbsp; &nbsp; @Autowired&nbsp; &nbsp; private RedisTemplate redisTemplate;&nbsp; &nbsp; public void saveIt(TestObject testObject){&nbsp; &nbsp; &nbsp; &nbsp; ValueOperations<ObjectId, TestObject> values = redisTemplate.opsForValue();&nbsp; &nbsp; &nbsp; &nbsp; values.set(testObject.testId, testObject);&nbsp; &nbsp; }}因此,上面的代码将使用您的配置并使用 Jackson 作为键和值的映射器在 Redis 中生成字符串对。但是,如果您想通过以下方式使用 Redis 存储库,则需要为from 和 toCrudRepository创建读写转换器,并将它们注册为自定义 Redis 转换。ObjectIdStringbyte[]ObjectId因此,让我们为<->创建读写转换器String读者@Component@ReadingConverter@Slf4jpublic class RedisReadingStringConverter implements Converter<String, ObjectId> {&nbsp; &nbsp; private ObjectMapper objectMapper = new ObjectMapper();&nbsp; &nbsp; @Override&nbsp; &nbsp; public ObjectId convert(String source) {&nbsp; &nbsp; &nbsp; &nbsp; try {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return objectMapper.readValue(source, ObjectId.class);&nbsp; &nbsp; &nbsp; &nbsp; } catch (IOException e) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log.warn("Error while converting to ObjectId.", e);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new IllegalArgumentException("Can not convert to ObjectId");&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}作家@Component@WritingConverter@Slf4jpublic class RedisWritingStringConverter implements Converter<ObjectId, String> {&nbsp; &nbsp; private ObjectMapper objectMapper = new ObjectMapper();&nbsp; &nbsp; @Override&nbsp; &nbsp; public String convert(ObjectId source) {&nbsp; &nbsp; &nbsp; &nbsp; try {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return objectMapper.writeValueAsString(source);&nbsp; &nbsp; &nbsp; &nbsp; } catch (JsonProcessingException e) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log.warn("Error while converting ObjectId to String.", e);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new IllegalArgumentException("Can not convert ObjectId to String");&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}以及 ObjectId <-> byte[] 的读写转换器作家@Component@WritingConverterpublic class RedisWritingByteConverter implements Converter<ObjectId, byte[]> {&nbsp; &nbsp; Jackson2JsonRedisSerializer<ObjectId> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(ObjectId.class);&nbsp; &nbsp; @Override&nbsp; &nbsp; public byte[] convert(ObjectId source) {&nbsp; &nbsp; &nbsp; &nbsp; return jackson2JsonRedisSerializer.serialize(source);&nbsp; &nbsp; }}读者@Component@ReadingConverterpublic class RedisReadingByteConverter implements Converter<byte[], ObjectId> {&nbsp; &nbsp; &nbsp;Jackson2JsonRedisSerializer<ObjectId> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(ObjectId.class);&nbsp; &nbsp; @Override&nbsp; &nbsp; public ObjectId convert(byte[] source) {&nbsp; &nbsp; &nbsp; &nbsp; return jackson2JsonRedisSerializer.deserialize(source);&nbsp; &nbsp; }}最后添加 Redis 自定义对话。只需将代码放入RedisConfiguration@Beanpublic RedisCustomConversions redisCustomConversions(RedisReadingByteConverter readingConverter,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;RedisWritingByteConverter redisWritingConverter,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;RedisWritingStringConverter redisWritingByteConverter,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;RedisReadingStringConverter redisReadingByteConverter) {&nbsp; &nbsp; return new RedisCustomConversions(Arrays.asList(readingConverter, redisWritingConverter, redisWritingByteConverter, redisReadingByteConverter));}因此,现在在创建转换器并将其注册为自定义 Redis 转换器后,您RedisKeyValueTemplate可以使用它们,并且您的代码应该按预期工作。
随时随地看视频慕课网APP

相关分类

Java
我要回答