技术架构
后端
Spring相关:
- Springboot 2.x
数据存储层:
- Mysql:数据库
- MyBatis Plus:数据访问框架
Redis相关:
- spring-data-redis:操作redis
- Lettuce:操作Redis的高级客户端
- Apache Commons Pool:用于实现Redis连接池
- Redisson:基于Redis的分布式数据网格
工具库:
- HuTool:工具库合集
- Lombok:注解式代码生成工具
前端
- 原生HTML,CSS,JS
- Vue 2
- Element UI组件库
- axios请求库
学习重点
涵盖面非常广,非常适合学习redis
短信登录
导入黑马点评项目
运行后端
百度网盘:https://pan.baidu.com/s/1189u6u4icQYHg_9_7ovWmA?pwd=eh11#list/path=%2F
运行hmdp.sql文件(给的)导入数据库
下载了源码用idea打开
- 修改application.yml配置文件,把mysql的相关配置改成自己的
启动项目:
可以打开http://localhost:8081/shop-type/list看一下访问成功没
运行前端
在项目目录下打开终端,输入:start nginx.exe运行nginx
打开http://localhost:8080即可看到页面
tips: nginx.conf路径不要包含中文,不然会报错,闪退
浏览器按f12进入开发者模式, 进入手机模式
基于Session实现登录
发送验证码
登录逻辑:
找到UserController负责关于user的请求
找到发送验证码的Mapper
找到userService实现类实现短信验证码请求
//1.校验手机号
if (RegexUtils.isPhoneInvalid(phone)) {
//2.不符合
return Result.fail("手机号格式错误!");
}
//3.符合,生成验证码
String code = RandomUtil.randomNumbers(6);
//4.保存验证码到session
session.setAttribute("code", code);
//5.发送验证码
log.debug("发送短信验证码成功");
return Result.ok();
非常简单,但注意2个方面:
- 正则校验手机号用的是项目自带的Regexutils
- 生成验证码用的是HuTools的RandomUtil
登录逻辑
- 用户提交手机号和验证码
- if 手机号错误 return Result.fail(“手机号格式错误!”)
- if 验证码错误 return Result.fail(“验证码错误!”)
- 根据手机号查询用户
- 用户不存在(== null), 在数据库中创建新用户
- 用户存在
- 保存用户到session中
- return Result.ok()
登录验证
创建拦截器LoginInterceptor
别忘了拦截器是implements HandlerInterceptor
只需要Override preHandle跟afterCompletion就行了
拦截器逻辑:
- 获取session
- 获取用户,从session中
- 用户不存在(== null)拦截(返回false)
- 用户存在,保存到ThreadLocal中(使用自定义工具类UserHolder)
- 放行(返回true)
新建MvcConfig别忘记加上@Configuration
重写addInterceptors方法, 用注册器添加LoginInterceptor, 可以指定哪些路径不走拦截器, 通过excludePathPatterns方法
Redis替代session
session共享问题
多态tomcat并不共享session存储空间,当请求切换到不同tomcat服务时导致数据丢失问题
采用redis
要保证每一个不同的手机号做验证时保存的key是不一样的。可以用json也可以用hash
修改逻辑:(因为修改的逻辑用文字不太好说所以用图片了)
大致上:
- 把sessionId为凭证的方式改为了Token
- 校验验证码的时候以手机号为key从redis中读取
修改1:LoginInterceptor拦截器
拦截器逻辑修改为:
- 获取请求头中的token(判断空(StrUtil.isBlank))
- 从redis中根据token获取用户(判断空)
- 将获得的hash数据转换成UserDTO(使用BeanUtil.fillBeanWithMap)(判断空)
- 用户存在,保存到ThreadLocal中
- 刷新token有效期
- 放行
修改2:Login实现类
- 校验手机号
- 判断空(RegexUtils.isPhoneInvalid)
- 从redis中获取验证码并校验
- 成功,根据手机号查询用户
- 不存在,在数据库中创建用户
- 用户存在
- 保存用户到redis中
- 创建随机token作为登录令牌(UUID.randomUUID)
- 将取到的hash数据转化为UserDTO(BeanUtil.copyProperties)
- 存储
- 设置有效期
- 返回结果不要忘记Result.ok(token) 返回token!!!!!!
登录拦截器的优化
在LoginInterceptor之前再添加一个拦截器RefreshTokenInterceptor来管理token刷新
逻辑如下: