目录
[2 熟悉Redis的常用5种数据结构](#2 熟悉Redis的常用5种数据结构)
[实战篇 - 01.Redis 企业实战课程介绍](#实战篇 - 01.Redis 企业实战课程介绍)
[实战篇 - 02. 短信登录 - 导入黑马点评项目](#实战篇 - 02. 短信登录 - 导入黑马点评项目)
[实战篇 - 03. 短信登录 - 基于 session 实现短信登录的流程](#实战篇 - 03. 短信登录 - 基于 session 实现短信登录的流程)
[实战篇 - 04. 短信登录 - 实现发送短信验证码功能](#实战篇 - 04. 短信登录 - 实现发送短信验证码功能)
[实战篇 - 05. 短信登录 - 实现短信验证码登录和注册功能](#实战篇 - 05. 短信登录 - 实现短信验证码登录和注册功能)
[实战篇 - 06. 短信登录 - 实现登录校验拦截器](#实战篇 - 06. 短信登录 - 实现登录校验拦截器)
问题:preHandle,postHandle,afterCompletion是什么?
问题:为什么使用redis存储令牌后就不需要后置拦截器移除用户了?
[实战篇 - 07. 短信登录 - 隐藏用户敏感信息](#实战篇 - 07. 短信登录 - 隐藏用户敏感信息)
[实战篇 - 08. 短信登录 - session 共享的问题分析](#实战篇 - 08. 短信登录 - session 共享的问题分析)
[实战篇 - 09. 短信登录 - Redis 代替 session 的业务流程](#实战篇 - 09. 短信登录 - Redis 代替 session 的业务流程)
[实战篇 - 10. 短信登录 - 基于 Redis 实现短信登录](#实战篇 - 10. 短信登录 - 基于 Redis 实现短信登录)
问题:redis中存储的token有效期是基于用户最后访问时间经过30min取消,不是首次登录30min后取消,该怎么动态刷新token的过期时间?
[实战篇 - 11. 短信登录 - 解决状态登录刷新的问题](#实战篇 - 11. 短信登录 - 解决状态登录刷新的问题)
问题:stringRedisTemplate.opsForHash().entries(key)和.get(key)的区别?
[entries 是获取整个哈希表的所有键值对,返回是 Map 集合。](#entries 是获取整个哈希表的所有键值对,返回是 Map 集合。)
[get 是获取哈希表中指定 key 的字段值,返回是单个值。](#get 是获取哈希表中指定 key 的字段值,返回是单个值。)
一复习
1知道NoSQL与SQL的差别

2 熟悉Redis的常用5种数据结构







3熟悉Redis的常用命令


4熟练使用Jedis或SpringDataRedis






二实战篇
实战篇 - 01.Redis 企业实战课程介绍


实战篇 - 02. 短信登录 - 导入黑马点评项目

问题:已经有优惠券表了为什么还需要优惠券订单表?


实战篇 - 03. 短信登录 - 基于 session 实现短信登录的流程
问题:发送短信验证码(登录/注册/校验)流程?
实战篇 - 04. 短信登录 - 实现发送短信验证码功能

问题:将验证码保存到session和redis有什么区别?
- Session 存内存,Redis 独立缓存
- Session 不支持集群,Redis 支持分布式
- Session 过期不灵活,Redis 可精确设置过期
- Session 重启丢失,Redis 更稳定
- 生产环境验证码统一用 Redis
java@Override public Result sendCode(String phone, HttpSession session) { // 1.校验手机号 if (RegexUtils.isPhoneInvalid(phone)) { // 2.如果不符合,返回错误信息 return Result.fail("手机号格式错误!"); } // 3.符合,生成验证码 String code = RandomUtil.randomNumbers(6); // 4.保存验证码到 session(session.setAttribute("code", code);) stringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY + phone, code, LOGIN_CODE_TTL, TimeUnit.MINUTES); // 5.发送验证码 log.debug("发送短信验证码成功,验证码:{}", code); // 返回ok return Result.ok(); }
问题Lmybatis-plus怎么使用?
接口层extends IService<实体类>
实现层extends ServiceImpl<mapper类,实体类> implements 接口
到时候就可以直接使用query(),update()这些了
问题:为什么下图的同意协议按钮点不动?
实战篇 - 05. 短信登录 - 实现短信验证码登录和注册功能
java@Override public Result login(LoginFormDTO loginForm, HttpSession session) { // 1.校验手机号 String phone = loginForm.getPhone(); if (RegexUtils.isPhoneInvalid(phone)) { // 2.如果不符合,返回错误信息 return Result.fail("手机号格式错误!"); } // 3.从redis获取验证码并校验 String cacheCode = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY + phone); String code = loginForm.getCode(); if (cacheCode == null || !cacheCode.equals(code)) { // 不一致,报错 return Result.fail("验证码错误"); } // 4.一致,根据手机号查询用户 select * from tb_user where phone = ? User user = query().eq("phone", phone).one(); // 5.判断用户是否存在 if (user == null) { // 6.不存在,创建新用户并保存 user = createUserWithPhone(phone); } // 7.保存用户信息到 redis中 // 7.1.随机生成token,作为登录令牌 String token = UUID.randomUUID().toString(true); // 7.2.将User对象转为HashMap存储 UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class); Map<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(), CopyOptions.create() .setIgnoreNullValue(true) .setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString())); // 7.3.存储 String tokenKey = LOGIN_USER_KEY + token; stringRedisTemplate.opsForHash().putAll(tokenKey, userMap); // 7.4.设置token有效期 stringRedisTemplate.expire(tokenKey, LOGIN_USER_TTL, TimeUnit.MINUTES); // 8.返回token return Result.ok(token); }
实战篇 - 06. 短信登录 - 实现登录校验拦截器

问题:preHandle,postHandle,afterCompletion是什么?
前置拦截器,后置拦截器
- preHandle:Controller 之前 → 拦截、登录判断
- postHandle:Controller 之后 → 修改响应
- afterCompletion:页面渲染完 → 清理资源
问题:为什么使用redis存储令牌后就不需要后置拦截器移除用户了?
因为用户信息存在 Redis 里,而不是存在 ThreadLocal 里了! 你现在这个拦截器根本没往 ThreadLocal 存用户 ,自然就不用删!
实战篇 - 07. 短信登录 - 隐藏用户敏感信息
实战篇 - 08. 短信登录 - session 共享的问题分析

实战篇 - 09. 短信登录 - Redis 代替 session 的业务流程



实战篇 - 10. 短信登录 - 基于 Redis 实现短信登录
问题:解释下面代码?
javaMap<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(), CopyOptions.create() .setIgnoreNullValue(true) .setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));
javaMap<String, Object> userMap = BeanUtil.beanToMap( userDTO, // 要转换的源对象 new HashMap<>(), // 转换后要放进的目标 Map CopyOptions.create() // 转换规则 .setIgnoreNullValue(true) // 忽略值为 null 的字段 .setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()) // 把所有字段的值 转成 String );
问题:@Autowired和@Resource有什么区别?
- @Autowired :按类型注入(Spring 核心注解)
- @Resource :按名称注入(JSR-250 标准注解,默认按名称,找不到才按类型)
问题:redis中存储的token有效期是基于用户最后访问时间经过30min取消,不是首次登录30min后取消,该怎么动态刷新token的过期时间?
每次用户访问接口时,都重新把 Redis 里的 token 过期时间设置为 30 分钟 → 这就叫 "滑动过期" 只要用户一直在操作,token 就永远不过期;30 分钟不操作,自动失效。
🧠 原理(超级好懂)
- 首次登录:设置过期 30 分钟
- 用户每发一次请求 :重置过期时间为 30 分钟
- 30 分钟不访问:token 自动过期
这就是你要的:基于最后一次访问时间过期。
我们可以在拦截器的位置加一次刷新redis的token过期时间(再加一层拦截器拦截所有,只刷新token过期时间,其他事情不干)
实战篇 - 11. 短信登录 - 解决状态登录刷新的问题
问题:为什么要优化成两个拦截器?
因为一个拦截器的时候只拦截需要登录的路径,那不需要登录的路径不拦截就没办法动态刷新token的有效期了

问题:stringRedisTemplate.opsForHash().entries(key)和.get(key)的区别?
entries 是获取整个哈希表的所有键值对,返回是 Map 集合。
get 是获取哈希表中指定 key 的字段值,返回是单个值。
末尾页:
本文介绍了Redis在企业项目中的实战应用,重点讲解了短信登录功能的实现过程。首先对比了Session和Redis存储验证码的优劣,指出Redis在分布式、稳定性和过期设置方面的优势。然后详细说明了基于Redis的短信验证码登录流程,包括验证码生成、存储、校验以及用户信息保存到Redis等关键步骤。文章还探讨了登录拦截器的实现原理,解释了为何使用Redis后无需后置拦截器处理用户信息。最后针对常见问题如MyBatis-Plus使用、注解区别、Redis数据结构操作等进行了说明,并提出了动态刷新token有效期的解决方案。








