- 一. 问题背景
- 二. 版本说明
- 三. 解决方案
- 3.1 引入依赖
- 3.2 配置Redis
- 3.3 封装关于Redis的操作
- 3.3.1 定义接口
- 3.3.2 实现接口
- 3.4 测试前期准备
- 3.4.1 创建controller层
- 3.4.2 创建Service层
- 3.5 部署Redis
- 3.5.1 安装Redis
- 3.5.2 配置redis.conf
- 3.5.3 创建并启动Redis容器
- 3.6 测试
一. 问题背景
了解完了关于Redis的架构后,尝试动手写代码,SpringBoot整合Redis。Redis的客户端有Jedis以及Lettuce,SpringBoot2.x版本默认使用Lettuce了,可见Lettuce效果比较好。
参考自:
二. 版本说明
技术栈 | 版本 |
SpringBoot | 2.x以上版本 |
Redis | 6.0.10(以Docker方式运行) |
三. 解决方案
3.1 引入依赖
<!--redis依赖配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- lettuce pool 缓存连接池-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.9.0</version>
</dependency>
3.2 配置Redis
在yml文件中,spring节点下,配置Redis的信息:
redis:
host: xx.xx.xx.xx # Redis服务器地址
database: 0 # Redis数据库索引(默认为0)
port: 6379 # Redis服务器连接端口
password: 'xxx' # Redis服务器连接密码(默认为空)
lettuce:
pool:
max-active: 8 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 8 # 连接池中的最大空闲连接
min-idle: 0 # 连接池中的最小空闲连接
timeout: 3000ms # 连接超时时间(毫秒)
key:
prefix:
authCode: "portal:authCode:"
expire:
authCode: 20 # 验证码超期时间
注:上面代码中的
prefix authCode
以及expire authCode
的值随便填自定义RedisTemplate,否则中文的value存到redis里面会乱码,获取出来也会乱码:
package com.ganzalang.gmall.redis.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import lombok.extern.slf4j.Slf4j;
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.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;
/**
* @Author Androidla
* @Date 2021/2/14 13:40
* @Description
**/
@Configuration
@Slf4j
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
log.info("RedisConnectionFactory class: {}", redisConnectionFactory.getClass());
RedisSerializer<Object> serializer = redisSerializer();
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(serializer);
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(serializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
public RedisSerializer<Object> redisSerializer() {
// 创建JSON序列化器
Jackson2JsonRedisSerializer<Object> serializer =
new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 必须设置,否则无法将json转化为对象,会转化为Map类型
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(objectMapper);
return serializer;
}
}
3.3 封装关于Redis的操作
3.3.1 定义接口
package com.ganzalang.gmall.service;
/**
* redis操作Service,
* 对象和数组都以json形式进行存储
*/
public interface RedisService {
/**
* 存储数据
* @param key
* @param value
*/
void set(String key, String value);
/**
* 获取数据
* @param key
* @return
*/
String get(String key);
/**
* 设置超时时间
* @param key
* @param expire
* @return
*/
boolean expire(String key, long expire);
/**
* 删除数据
* @param key
*/
void remove(String key);
/**
* 自增操作
* @param key
* @param delta
* @return
*/
Long increment(String key, long delta);
}
3.3.2 实现接口
package com.ganzalang.gmall.service.impl;
import com.ganzalang.gmall.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
/**
* redis操作Service的实现类
*/
@Service
public class RedisServiceImpl implements RedisService {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override
public void set(String key, String value) {
stringRedisTemplate.opsForValue().set(key, value);
}
@Override
public String get(String key) {
return stringRedisTemplate.opsForValue().get(key);
}
@Override
public boolean expire(String key, long expire) {
return stringRedisTemplate.expire(key, expire, TimeUnit.SECONDS);
}
@Override
public void remove(String key) {
stringRedisTemplate.delete(key);
}
@Override
public Long increment(String key, long delta) {
return stringRedisTemplate.opsForValue().increment(key, delta);
}
}
3.4 测试前期准备
3.4.1 创建controller层
package com.ganzalang.gmall.controller;
import com.ganzalang.gmall.service.impl.TestServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 测试redis是否整合成功
*/
@RestController
@RequestMapping("/test")
public class TestController {
@Autowired
private TestServiceImpl testService;
@GetMapping("/redis")
public String testRedis() {
testService.testRedis();
return "success";
}
}
3.4.2 创建Service层
package com.ganzalang.gmall.service.impl;
import com.ganzalang.gmall.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class TestServiceImpl {
@Autowired
private RedisService redisService;
@Value("${spring.redis.key.prefix.authCode}")
private String REDIS_KEY_PREFIX_AUTH_CODE;
@Value("${spring.redis.key.expire.authCode}")
private Long AUTH_CODE_EXPIRE_SECONDS;
private static String username = "10010";
public void testRedis() {
log.info("testRedis start......");
log.info("REDIS_KEY_PREFIX_AUTH_CODE: {}", REDIS_KEY_PREFIX_AUTH_CODE);
log.info("AUTH_CODE_EXPIRE_SECONDS: {}", AUTH_CODE_EXPIRE_SECONDS);
// 设置缓存
redisService.set(getAuthKey(), "管理员权限");
// 设置过期时间
redisService.expire(getAuthKey(), AUTH_CODE_EXPIRE_SECONDS);
// 获取缓存
String auth = redisService.get(getAuthKey());
log.info("auth: {}", auth);
}
// 构造redis的key
private String getAuthKey() {
String key = REDIS_KEY_PREFIX_AUTH_CODE + username;
return key;
}
}
3.5 部署Redis
3.5.1 安装Redis
用Docker方式部署:
# 下载最新版的redis的docker镜像
docker pull redis
# 创建挂载数据的地方
mkdir /mydata/redis/data
3.5.2 配置redis.conf
必须以指定redis.conf方式启动redis容器,否则后面会有一堆报错。
去网上下载redis.conf文件,并放到
/mydata/redis/
下,并修改redis.conf的某些内容,修改如下:
1. 注释掉 bind 127.0.0.1
2. 将protected-mode yes改为no,否则无法远程登陆redis
3. 将daemonize yes 改为no,否则启动redis容器会一直失败
4. 强烈建议设置redis密码,在requirepass处设置自己的密码
3.5.3 创建并启动Redis容器
docker run -p xxxx:6379 --name redis \
-v /mydata/redis/redis.conf:/etc/redis/redis.conf \
-v /mydata/redis/data:/data \
-d redis redis-server /etc/redis/redis.conf \
--appendonly yes
解释:
-p xxxx:6379
:前者是宿主机的端口,后者是容器的端口。强烈建议修改宿主机的端口--name
:对创建出来的容器起别名-v
:挂载容器数据到宿主机,实现宿主机与容器数据互通-d
:后台运行--appendonly yes
:数据持久化
3.6 测试
启动程序,可以看到如下:
整合成功