SpringBoot by Kotlin?任重道远!

不知道有没有安卓开发的小伙伴跟我一样,平时喜欢维护一下自己的小项目,有余力的情况下自己把后端也写了。在安卓开发中越用越顺手的我这次的后端开发就开始使用了Kotlin,与Springboot搭配网上那是说的神乎其技。我也信以为真,因为我也非常喜欢Kotlin,于是边着手了旧项目的重构+迁移。

一切都很顺利,毕竟IDEA可以一键转换Kotlin,加上自己对Kotlin的掌握程度,转换不成问题,直到Redis时,有这么一句:

    @Autowired
    private lateinit var redisTemplate: RedisTemplate<String, Any>

运行时这句代码报了错,内容如下:

Description:

Field redisTemplate in com.gitlab.nykbapi.util.RedisUtil required a bean of type 'org.springframework.data.redis.core.RedisTemplate' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'org.springframework.data.redis.core.RedisTemplate' in your configuration.

意思大致就是说redisTemplate找不到bean,我心想不对呀,这个项目在Java时是正常跑的,怎么来到Kotlin就出问题了,于是我上网寻找问题答案,看到了这么一个建议(原文连接):

好家伙,简单!急性子的我看到解决办法立马就去试了,能跑,没问题,关闭浏览器!后文直接被我忽略...

程序能跑,问题解决了吗,真的解决了吗?

在我兴高采烈的写了一堆代码后,发现了一个问题:

没错,存储redis时自动给我的每个字段前都加上了一段\xac\xed\x00\x05t\x00\的字符,眼尖的我发现了“HEX”的标签,我心想哦~没事,切换成16进制了而已,于是我将它切成了text:

WTF?乱码无疑了,又开始了上网“Redis乱码”、“Redis自动加上乱码前缀”、“Redis序列化”....乱七八糟的,直到一句话映入我眼帘:

你确定你的Bean有被找到?

好家伙,这才想起我的注解改成了@Resource ,心中一万个草泥马...

将注解改回@Autowired后,又要面对先前的问题:

Field redisTemplate in com.gitlab.nykbapi.util.RedisUtil required a bean of type 'org.springframework.data.redis.core.RedisTemplate' that could not be found.

我一拍脑门,才想起忘记将我的RedisConfig拷贝过来了,真糊涂啊!

一顿CV操作(注意:RedisConfig由于我急于验证,所以并未转换成Kotlin):

package cc.han0.nykbcommon.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * @author Han0
 * @date 2022/8/15 17:01
 */
@Configuration
public class RedisConfig {
    @Bean
    public static RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        //设置key的序列化器
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());

        //创建对象映射器
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        //设置value的序列化对
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        //设置value的序列化器
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();

        return redisTemplate;

    }

    @Bean
    public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
        //创建对象映射器
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
                ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);

        //设置value的序列化对
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
        //设置key序列化器
        redisCacheConfiguration.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
        //设置value序列化器
//        redisCacheConfiguration.serializeValuesWith(jackson2JsonRedisSerializer);
        return RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(redisCacheConfiguration).build();
    }

}

大功告成,运行!

成功运行!

再走一遍接口:

WTF?阿真,你来真的?

想了想不应该呀,之前确实是没问题的,代码都没变,唯一变的就是Redis版本变高了,于是又开始降了一堆级,还是不行

直到我看到了这么一篇文章:

springboot的RedisTemplate泛型自动注入问题_redistemplate 泛型-CSDN博客

简单说就是注入会受泛型影响,突然想起RedisConfig是Java写的,泛型写的是<String, Object>,而这边RedisUtils写的是<String, Any>,emmmmm...

真的引起我的浑身不适!因为这个语言问题,害我排查了一晚!(归根结底其实是我太菜...)

键来!

package com.gitlab.nykbapi.config

import com.fasterxml.jackson.annotation.JsonAutoDetect
import com.fasterxml.jackson.annotation.JsonTypeInfo
import com.fasterxml.jackson.annotation.PropertyAccessor
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.data.redis.cache.RedisCacheConfiguration
import org.springframework.data.redis.cache.RedisCacheManager
import org.springframework.data.redis.connection.RedisConnectionFactory
import org.springframework.data.redis.core.RedisTemplate
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer
import org.springframework.data.redis.serializer.RedisSerializationContext
import org.springframework.data.redis.serializer.StringRedisSerializer

/**
 * @author Han0
 * @date 2022/8/15 17:01
 */
@Configuration
class RedisConfig {
    @Bean
    fun redisTemplate(redisConnectionFactory: RedisConnectionFactory): RedisTemplate<String, Any> {
        val redisTemplate = RedisTemplate<String, Any>()
        redisTemplate.setConnectionFactory(redisConnectionFactory)

        //设置key的序列化器
        redisTemplate.keySerializer = StringRedisSerializer()
        redisTemplate.hashKeySerializer = StringRedisSerializer()

        //创建对象映射器
        val objectMapper = ObjectMapper()
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY)
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL)
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

        //设置value的序列化对
        val jackson2JsonRedisSerializer = Jackson2JsonRedisSerializer(
            Any::class.java
        )
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper)

        //设置value的序列化器
        redisTemplate.valueSerializer = jackson2JsonRedisSerializer
        redisTemplate.hashValueSerializer = jackson2JsonRedisSerializer
        redisTemplate.afterPropertiesSet()
        return redisTemplate
    }

    @Bean
    fun redisCacheManager(redisConnectionFactory: RedisConnectionFactory?): RedisCacheManager {
        //创建对象映射器
        val objectMapper = ObjectMapper()
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY)
        objectMapper.activateDefaultTyping(
            LaissezFaireSubTypeValidator.instance,
            ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY
        )

        val redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
        //设置key序列化器
        redisCacheConfiguration.serializeKeysWith(
            RedisSerializationContext.SerializationPair.fromSerializer(
                StringRedisSerializer()
            )
        )
        return RedisCacheManager.builder(redisConnectionFactory!!).cacheDefaults(redisCacheConfiguration).build()
    }
}

 再跑,再运行:

ohhhhhhhhhhhhhhhh

Kotlin + Springboot,神吗?未必...不好用吗?也未必。

只能说SpringBoot by Kotlin,任重道远!

  • 41
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值