《SpringBoot从入门到放弃》之第(十)篇——整合Redis(SpringBoot 2.0 版本),写于2018年10月24号程序员节。

在 pom.xml 配置中添加 jar 依赖:

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>

		<dependency>
			<groupId>redis.clients</groupId>
			<artifactId>jedis</artifactId>
			<version>2.9.0</version>
		</dependency>

在 application.properties 配置文件里添加 Redis 配置:

# Redis 配置
# Redis 的IP地址,根据实际情况配置
spring.redis.host=192.168.126.130
# Redis 的端口号,默认 6379,如果没有特别要求,可以不配置。
spring.redis.port=6379
# 连接 Redis 的密码
spring.redis.password=123456
# 使用的库,默认 0
spring.redis.database=0
# 客户端连接超时时间,单位:毫秒,默认2000
spring.redis.timeout=10000
# 连接池中最大空闲数,默认是 8 ,如果没有特别要求,可以不配置。
spring.redis.jedis.pool.max-idle=8
# 连接池中最大连接数,默认是 8 ,如果没有特别要求,可以不配置。
spring.redis.jedis.pool.max-active=8
# 连接池中的最小空闲连接,默认是 0 ,如果没有特别要求,可以不配置。
spring.redis.jedis.pool.min-idle=0

其实,很多配置 Redis 都有默认的配置,我们可以追踪看看。按住 Ctrl + 鼠标左键,点中配置文件里的一些配置,就进入到 jar 包里:

​public class RedisProperties {
    private int database = 0;
    private String url;
    private String host = "localhost";
    private String password;
    private int port = 6379;

public static class Pool {
	private int maxIdle = 8;
	private int minIdle = 0;
	private int maxActive = 8;
	private Duration maxWait = Duration.ofMillis(-1L);

因此,如果一些配置跟默认的一致,就无需写到 application.properties 配置文件里了。

在写代码的时候发现,JedisConnectionFactory 从SpringBoot 2.0 版本以后,所有的 setXXX 方法都过时了,

查资料才知道:JedisConnectionFacotory 从 spring-boot-starter-data-redis 2.0开始已经不推荐直接显示设置连接的信息了,一方面为了使配置信息与建立连接工厂解耦,另一方面抽象出Standalone,Sentinel和RedisCluster三种模式的环境配置类和一个统一的 jedis 客户端连接配置类(用于配置连接池和SSL连接),使得可以更加灵活方便根据实际业务场景需要来配置连接信息。

O的K,那就用 2.0 的特性来学习吧。

新建 util 包,用来存放一些工具类的。后面接触分布式开发后,还会单独把工具类抽离出来,弄成一个 jar 包,用来作为公司的公共的工具类。

这里涉及 3 个新的 java 文件,分别是:

RedisConfig类:

package com.test.util;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

@Configuration
public class RedisConfig {

    @Value("${spring.redis.host}")
    private String host;//主机地址

    @Value("${spring.redis.port}")
    private Integer port;//端口号

    @Value("${spring.redis.password}")
    private String password;//连接密码

    @Value("${spring.redis.database}")
    private Integer database;//默认连接的库

    @Value("${spring.redis.timeout}")
    private Integer timeout;//超时时间

    @Value("${spring.redis.jedis.pool.max-idle}")
    private Integer maxIdle;//连接池中最大空闲数

    @Value("${spring.redis.jedis.pool.max-active}")
    private Integer maxActive;//连接池中最大连接数

    @Value("${spring.redis.jedis.pool.min-idle}")
    private Integer minIdle;//连接池中的最小空闲连接

    @Bean(name = "MyRedisTemplateUtil")//Bean的名称可以自定义
    public MyRedisTemplateUtil myRedisTemplate(){
        MyRedisTemplateUtil myRedisTemplate = new MyRedisTemplateUtil();
        myRedisTemplate.setRedisTemplate(redisTemplate());
        return myRedisTemplate;
    }

    /**
     * 创建工厂连接类对象,主要为模板 RedisTemplate 的 setConnectionFactory 方法服务。
     * @return
     */
    @Bean
    public RedisConnectionFactory redisConnectionFactory(){
        //Redis的基本配置
        RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
        configuration.setDatabase(database);
        configuration.setHostName(host);
        configuration.setPort(port);
        configuration.setPassword(RedisPassword.of(password));
        //配置连接池
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxIdle(maxIdle);
        poolConfig.setMinIdle(minIdle);
        poolConfig.setMaxTotal(maxActive);
        //使用工厂类创建连接对象
        JedisClientConfiguration.JedisPoolingClientConfigurationBuilder builder = (JedisClientConfiguration.JedisPoolingClientConfigurationBuilder)JedisClientConfiguration.builder();
        builder.poolConfig(poolConfig);
        JedisConnectionFactory factory = new JedisConnectionFactory(configuration,builder.build());
        factory.afterPropertiesSet();//在所有的属性被初始化后调用,但是会在init前调用
        RedisConnectionFactory connectionFactory = factory;
        return connectionFactory;
    }

    /**
     * 数据操作模板
     * @return
     */
    @Bean
    public RedisTemplate redisTemplate(){
        RedisTemplate template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory());//setConnectionFactory方法要求对象属于类:RedisConnectionFactory

        //采用JdkSerializationRedisSerializer的二进制数据序列化方式
        Jackson2JsonRedisSerializer jackson2Serializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2Serializer.setObjectMapper(mapper);

        //方式①:把 key 序列化成String类型,比较符合的习惯
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();//StringRedisSerializer是RedisSerializer的实现类
        template.setKeySerializer(redisSerializer);
        template.setHashKeySerializer(redisSerializer);

        //方式②:把 key 序列化成Json格式,key会变成类似:“myKey”的形式
        //template.setKeySerializer(jackson2Serializer);
        //template.setHashKeySerializer(jackson2Serializer);

        template.setValueSerializer(jackson2Serializer);
        template.setHashValueSerializer(jackson2Serializer);
        template.afterPropertiesSet();
        return template;
    }

}

需要注意的是:

①配置类需要添加 @Configuration 注解:import org.springframework.context.annotation.Configuration;

②使用 @Value("${spring.redis.host}") 语法获取已加载到 Spring 容器的配置信息

@Bean(name = "MyRedisTemplateUtil")//Bean的名称可以自定义,把 Bean 交给 Spring 容器来管理。

④在数据操作模板的方法里,有两种序列化的方式,按照对应的场景来使用,有人喜欢统一的Json格式,有人喜欢String格式。区别如下图:

MyRedisTemplateUtil 类,封装了操作 Redis 的一部分方法,更多的方法可以试着自己封装:

package com.test.util;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.List;

@Repository
public class MyRedisTemplateUtil{

    private RedisTemplate redisTemplate;

    public RedisTemplate getRedisTemplate() {
        return redisTemplate;
    }

    public void setRedisTemplate(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 判断 key 是否存在
     * @param key
     * @return
     */
    public boolean hasKey(String key){
        return getRedisTemplate().hasKey(key);
    }

    /**
     * 删除key
     * @param key
     * @return
     */
    public Boolean del(String key){
        return getRedisTemplate().delete(key);
    }

    /**
     * string类型:设置值
     * @param key
     * @param value
     * @return
     */
    public void set(String key, String value){
        getRedisTemplate().opsForValue().set(key,value);
    }

    /**
     * string类型:获取值
     * @param key
     * @return
     */
    public String get(String key){
        return (String)getRedisTemplate().opsForValue().get(key);
    }

    /**
     * list类型:获取列表里所有值,start=0,end=-1
     * @param key
     * @return
     */
    public List<String> range(String key){
        try{
            return (List) getRedisTemplate().opsForList().range(key,0L,-1L);
        }catch (Exception e){
            e.printStackTrace();
            return new ArrayList<>();
        }
    }

    /**
     * list类型:从右边(尾部)添加一个元素
     * @param key
     * @param value
     */
    public Boolean rightPush(String key,String value){
        try{
            getRedisTemplate().opsForList().rightPush(key,value);
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * list类型:从左边(头部)弹出一个元素
     * @param key
     * @return
     */
    public String leftPop(String key){
        try{
            return (String)getRedisTemplate().opsForList().leftPop(key);
        }catch (Exception e){
            e.printStackTrace();
            return "";
        }
    }
}

说明:Long类型的参数,请在数字后面加上大写的 L,而不是小写的 l,因为小写的 l 和数字 1 很像,容易搞错!

如果还有疑问,请查阅我的博客:Redis五种数据类型string、list、hash、set、zset

RedisController 测试的类:

package com.test.web;

import com.test.util.MyRedisTemplateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
public class RedisController {

    @Autowired
    @Qualifier("MyRedisTemplateUtil")//@Qualifier是标注@Bean=myRedisTemplateUtilUtil的类才是我们需要的
    private MyRedisTemplateUtil myRedisTemplateUtil;

    /**
     * 删除值
     * @param key
     * @return
     */
    @RequestMapping(value = "/del")
    public Map<String,Boolean> del(@RequestParam String key){
        boolean result = myRedisTemplateUtil.del(key);
        Map<String, Boolean> map = new HashMap<>();
        map.put("result", result);
        return map;
    }

    /**
     * 判断值是否存在
     * @param key
     * @return
     */
    @RequestMapping(value = "/hasKey")
    public Map<String,Boolean> hasKey(@RequestParam String key){
        Boolean result = myRedisTemplateUtil.hasKey(key);
        Map<String, Boolean> map = new HashMap<>();
        map.put("result", result);
        return map;
    }

    /**
     * string类型:设置值
     * @param key
     * @param value
     * @return
     */
    @RequestMapping(value = "/set")
    public Map<String,String> set(@RequestParam String key, @RequestParam String value){
        myRedisTemplateUtil.set(key,value);
        Map<String, String> map = new HashMap<>();
        map.put("result", "success");
        return map;
    }

    /**
     * string类型:获取值
     * @param key
     * @return
     */
    @RequestMapping(value = "/get")
    public Map<String,String> get(@RequestParam String key){
        String result = myRedisTemplateUtil.get(key);
        Map<String, String> map = new HashMap<>();
        map.put("result", result);
        return map;
    }

    /**
     * list类型:获取列表里所有的值
     * @param key
     * @return
     */
    @RequestMapping(value = "/range")
    public Map<String,List<String>> range(@RequestParam String key){
        List<String> result = myRedisTemplateUtil.range(key);
        Map<String, List<String>> map = new HashMap<>();
        map.put("result", result);
        return map;
    }

    /**
     * list类型:从右边(尾部)添加一个元素
     * @param key
     * @param value
     * @return
     */
    @RequestMapping(value = "rightPush")
    public Map<String,Boolean> rightPush(@RequestParam String key,@RequestParam String value){
        Boolean result = myRedisTemplateUtil.rightPush(key,value);
        Map<String, Boolean> map = new HashMap<>();
        map.put("result", result);
        return map;
    }

    /**
     * list类型:从左边(头部)弹出一个元素
     * @param key
     * @return
     */
    @RequestMapping(value = "leftPop")
    public Map<String,String> leftPop(@RequestParam String key){
        String result = myRedisTemplateUtil.leftPop(key);
        Map<String, String> map = new HashMap<>();
        map.put("result", result);
        return map;
    }
}

O的K,用 postman 来测试,测试之前,请开启 Linux 虚拟机,开启 Redis,确保能连通:

如有疑问,请阅读我的相关博客,Java连接Redis和Redis Desktop的使用

测试 string 类型:

①测试 set 方法设置值:http://localhost:9090/set?key=biandan&value=让天下没有难写的代码

②测试 get 方法获取值:http://localhost:9090/get?key=biandan

结果:{"result": "让天下没有难写的代码"}

③测试 hasKey 方法,判断某个 key 是否存在:http://localhost:9090/hasKey?key=biandan

结果:{"result":true}

④删除 key:http://localhost:9090/del?key=biandan

结果:{"result":true}

删除后,再次查询:http://localhost:9090/get?key=biandan

结果:{"result":null}

测试 list 类型:

①测试 rightPush 方法,从尾部依次添加元素,注意 key 要相同,才能测出效果:

http://localhost:9090/rightPush?key=alibaba&value=天猫双11

http://localhost:9090/rightPush?key=alibaba&value=马云说,人要有梦想。而他的梦想是:让天下没有难做的生意。

结果:{"result":true}

②测试 range 方法,查询 alibaba 的所有元素:http://localhost:9090/range?key=alibaba

结果:{"result":["天猫双11","马云说,人要有梦想。而他的梦想是:让天下没有难做的生意。"]}

③测试 leftPop 方法,从左边(头部)弹出一个元素:http://localhost:9090/leftPop?key=alibaba

结果:{"result":"天猫双11"}

④再次测试 range 方法:http://localhost:9090/range?key=alibaba

结果:{"result":["马云说,人要有梦想。而他的梦想是:让天下没有难做的生意。"]}

说明第一个元素 “天猫双11” 已经被移除了。

更多关于 RedisTemplate 的知识,可以查阅:如何使用RedisTemplate访问Redis数据结构

纸上得来终觉浅,绝知此事要躬行。敲代码越多,思考越多,进步越快,距离架构师越近。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值