在 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数据结构
纸上得来终觉浅,绝知此事要躬行。敲代码越多,思考越多,进步越快,距离架构师越近。