RedisTemplate自定义配置及序列化问题

  • Post author:
  • Post category:其他




1 简介

本文讲解RedisTemplate自定义配置及序列化问题。



2 整合过程



2.1 自动配置类

把相关依赖引入到项目中后,Springboot就自动帮我们生成了Template类,分别是

RedisTemplate



StringRedisTemplate

。看一下自动配置类能看出这两个类都已经创建到Spring容器里了。

public class RedisAutoConfiguration {
    public RedisAutoConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean( name = {"redisTemplate"} )
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

实际上

StringRedisTemplate



RedisTemplate

的子类,对于String类型,更推荐使用前者,它的类型只能是String的,会有类型检查上的安全;而RedisTemplate可以操作任何类型。



2.2 实现数据访问层

本文通过

RedisTemplate对Redis

进行操作,所以我们需要将它注入进来。代码如下:

package com.pkslow.springbootredistemplate.dal;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class UserDAL {
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    public void setValue(Object key, Object value) {
        redisTemplate.opsForValue().set(key, value);
    }

    public Object getValue(Object key) {
        return redisTemplate.opsForValue().get(key);
    }
}

RedisTemplate提供了丰富的方法,具体可以参考官方文档,本次用到的及类似的方法有:

    opsForHash(): 返回对于Hash的操作类;
    opsForList(): 返回对于列表List的操作类;
    opsForSet(): 返回对于Set的操作类;
    opsForValue(): 返回对于字符串String的操作类;
    opsForZSet(): 返回对于ZSet的操作类。



2.3 实现Controller

我们需要把功能通过Web的方式暴露出去,实现以下Contrller:

package com.pkslow.springbootredistemplate.controller;

import com.pkslow.springbootredistemplate.dal.UserDAL;
import com.pkslow.springbootredistemplate.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/userTemplate")
public class UserTemplateController {

    @Autowired
    private final UserDAL userDAL;

    public UserTemplateController(UserDAL userDAL) {
        this.userDAL = userDAL;
    }

    @GetMapping("/{userId}")
    public User getByUserId(@PathVariable String userId) {
        return (User)userDAL.getValue(userId);
    }

    @PostMapping("/{userId}")
    public User addNewUser(@PathVariable String userId,
                           @RequestBody User user) {
        user.setUserId(userId);
        userDAL.setValue(userId, user);
        return user;
    }

}

能写能读,功能实现,完美!Perfect!收工!



3 序列化问题

程序功能正常运行一段时间后,运维杀来了:

“这是什么东西?我怎么看得懂?我要怎么查看数据?”


在这里插入图片描述



3.1 定位问题

不得不重新打开项目代码,Debug一下看看哪出了问题。既然用Postman测试能正常显示,而数据库显示不对,说明是写入数据库时做了转换。查看

RedisTemplate

就行了,毕竟活是他干的(先疯狂甩锅)。

在这里插入图片描述

Deubg

看它的序列化类用的是默认的

JdkSerializationRedisSerializer

,所以序列化后的数据我们看不懂。



3.2 问题修复

甩锅完后,还是要修复问题的,毕竟代码是自己写的。关键就是替换掉

RedisTemplate

所使用的序列化类就行了,这有两个方案可选:

(1)自定义一个新的

RedisTemplate

以覆盖旧的,在定义的时候指定序列化类。大致代码如下:

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
  Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
  ObjectMapper om = new ObjectMapper();
  om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
  om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
  jackson2JsonRedisSerializer.setObjectMapper(om);

  RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
  template.setConnectionFactory(redisConnectionFactory);
  template.setKeySerializer(jackson2JsonRedisSerializer);
  template.setValueSerializer(jackson2JsonRedisSerializer);
  template.setHashKeySerializer(jackson2JsonRedisSerializer);
  template.setHashValueSerializer(jackson2JsonRedisSerializer);
  template.afterPropertiesSet();
  return template;
}

甚至还可以自定义

RedisConnectionFactory

,如下:

@Bean
JedisConnectionFactory jedisConnectionFactory() {
    JedisConnectionFactory jedisConFactory = new JedisConnectionFactory();
    jedisConFactory.setHostName("localhost");
    jedisConFactory.setPort(6379);
    return jedisConFactory;
}

(2)使用原有的

RedisTemplate

,在使用前替换掉序列化类

引用的类的代码如下,init方法作为初始化方法:

public class UserDAL {
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    public void init() {
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));

    }

    public void setValue(Object key, Object value) {
        redisTemplate.opsForValue().set(key, value);
    }

    public Object getValue(Object key) {
        return redisTemplate.opsForValue().get(key);
    }
}

然后在创建UserDAL时,代码如下:

@Bean(initMethod = "init")
public UserDAL userDAL() {
  return new UserDAL();
}

重新提交代码、重新测试、重新发布,结果可以了:

在这里插入图片描述
### 3.3 Redis配置类模板

@Configuration
public class RedisConfig {

    /**
     * 自定义RedisTemplate
     * redisTemplate 序列化使用的jdkSerializeable,存储二进制字节码, 所以自定义序列化类
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {

        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();

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

        //  hash类型
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());

        //注入连接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
    }

}



4 总结

本文内容为博客园转载,只为学习技术,

转载地址



版权声明:本文为Good_omen原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。