Appearance
Redis 学习笔记
Redis 安装及配置笔记
Redis下载
下载地址:Releases · microsoftarchive/redis · GitHub

Redis 配置
解压压缩包


将路径添加至环境变量

在当前路径下按shift + 鼠标右键,点击打开PowerShell后
输入命令 redis-server.exe redis.windows.conf

常用命令
shell
安装服务:redis-server --service-install
卸载服务:redis-server --service-uninstall
开启服务:redis-server --service-start
停止服务:redis-server --service-stop
服务端启动时重命名:redis-server --service-start --service-name Redis1Redis 连接
shell
redis-cli -h host -p port -a password
Redis 数据结构
String 类型
设置指定 key 的值SET key value
shell
set name gettler获取指定 key 的值 GET key
shell
get name
Hash 类型
List类型
Set 类型
Sorted 类型
Redis 通用命令
Redis 的 Java 客户端



请定义一个用户信息结构体,然后使用 fastjson 对用户信息对 象进行序列化和反序列化,再使用 jedis 对 Redis 缓存的用户信息进行存和取。
User类
javapackage com.gettler.base; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * @author Gettler * @date 2022/11/20 */ @Data @AllArgsConstructor @NoArgsConstructor public class User { private String name; private Integer age; }Jedis连接工厂
javapackage com.gettler.util; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; /** * @author Gettler * @date 2022/11/20 */ public class JedisConnectionFactory { private static final JedisPool JEDIS_POOL; static { JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMinIdle(0); jedisPoolConfig.setMaxIdle(8); jedisPoolConfig.setMaxTotal(8); jedisPoolConfig.setMaxWaitMillis(1000); JEDIS_POOL = new JedisPool(jedisPoolConfig, "localhost", 6379, 1000); } public static Jedis getJedis() { return JEDIS_POOL.getResource(); } }主类
javapackage com.gettler.base; import com.alibaba.fastjson.JSON; import com.gettler.util.JedisConnectionFactory; import redis.clients.jedis.Jedis; /** * @author Gettler * @date 2022/11/21 */ public class Homework1 { public static void main(String[] args) { Jedis jedis = JedisConnectionFactory.getJedis(); jedis.auth("73748156"); jedis.select(0); User user = new User("Gettler", 21); jedis.set("user:1", JSON.toJSONString(user)); User user2 = new User("lyl", 21); jedis.set("user:2", user2.toString()); System.out.println("user1 :" + jedis.get("user:1")); System.out.println("user2 :" + jedis.get("user:2")); jedis.close(); } }
项目实战
Redis 实现验证码登录
使用手机+验证码登录时生成验证码
使用正则表达式校验手机号,使用随机数工具生成六位数验证码,并将其存入redis中。
java
// 校验手机号
if(RegexUtils.isPhoneInvalid(phone)){
return Result.fail("手机号格式错误");
}
// 符合则生成验证码
String code=RandomUtil.randomNumbers(6);
// 保存验证码
stringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY+phone,code,LOGIN_CODE_TTL,TimeUnit.MINUTES);
// TODO 发送验证码
log.debug("发送验证码成功,验证码:"+code);
return Result.ok();校验验证码
在redis中获取以手机号为键的值,以此校验前端传回的验证码
将获取到的user对象转为Map对象,并以随机字符串token为键存入redis中,再将token传回前端。
java
String phone=loginForm.getPhone();
// 校验手机号
if(RegexUtils.isPhoneInvalid(phone)){
return Result.fail("手机号格式错误");
}
// 校验验证码
String code=loginForm.getCode();
String cacheCode=stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY+phone);
if(!code.equals(cacheCode)){
return Result.fail("验证码错误");
}
// 判断用户是否存在
User user=query().eq("phone",phone).one();
// 不存在,创建新用户
if(user==null){
user=createUserWithPhone(phone);
}
String token=UUID.randomUUID().toString();
// 将用户信息存到 Redis 里
UserDTO userDTO=BeanUtil.copyProperties(user,UserDTO.class);
String tokenKey=LOGIN_USER_KEY+token;
// stringRedisTemplate.opsForHash().putAll(tokenKey, BeanUtil.beanToMap(userDTO));
// 上方写法Long 转 String 会报错,需要用下方写法
stringRedisTemplate.opsForHash()
.putAll(tokenKey,BeanUtil.beanToMap(userDTO,new HashMap<>(),CopyOptions.create()
.setIgnoreNullValue(true)
.setFieldValueEditor((fieldName,fieldValue)->fieldValue.toString())));
stringRedisTemplate.expire(tokenKey,LOGIN_USER_TTL,TimeUnit.SECONDS);
return Result.ok(token);编写一个拦截器,在发送请求后,刷新token在redis中所对应键值对的有效期
java
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.hmdp.dto.UserDTO;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* @author Gettler
* @date 2023/1/24
*/
public class RefreshTokenInterceptor implements HandlerInterceptor {
private StringRedisTemplate stringRedisTemplate;
public RefreshTokenInterceptor(StringRedisTemplate stringRedisTemplate) {
this.stringRedisTemplate = stringRedisTemplate;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("authorization");
if (StrUtil.isBlank(token)) {
return true;
}
String key = RedisConstants.LOGIN_USER_KEY + token;
Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(key);
if (userMap.isEmpty()) {
return true;
}
UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);
UserHolder.saveUser(userDTO);
// 刷新token有效期
stringRedisTemplate.expire(key, RedisConstants.LOGIN_USER_TTL, TimeUnit.SECONDS);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
UserHolder.removeUser();
}
}还有在访问需要登录才能访问的路径时的登录拦截器,统一判断是否有权限访问
java
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author Gettler
* @date 2023/1/24
*/
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (UserHolder.getUser() == null) {
response.setStatus(401);
return false;
}
return true;
}
}编写配置文件将拦截器注册,并将StringRedisTemplate注入到容器中
java
import com.hmdp.utils.LoginInterceptor;
import com.hmdp.utils.RefreshTokenInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
/**
* @author Gettler
* @date 2023/1/25
*/
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Resource
StringRedisTemplate stringRedisTemplate;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 先添加先执行,也可以使用order方法指定优先级,数字越小优先级越高
registry.addInterceptor(new LoginInterceptor())
.excludePathPatterns("/shop/**", "/voucher/**", "/shop-type/**", "/blog/hot", "/upload/**",
"/user" + "/code", "/user/login").order(1);
registry.addInterceptor(new RefreshTokenInterceptor(stringRedisTemplate)).addPathPatterns("/**").order(0);
}
}