本文从前端讲解数据流转过程
【前端如下】:首先输入手机号并点击发送验证码,将手机号数据进行提交到服务器
【服务器】如下:客户端 发送的请求和携带的数据【手机号】12345678910。
【第一步】首先会被拦截器拦截,这里配置了两个拦截器,根据拦截器拦截内容,第一个拦截器会进行释放,第二个拦截器由于拦截范围原因也会进行释放。

【第二步】数据【手机号】12345678910,会流转到验证码发送业务。
@Overridepublic Result sendCode(String phone, HttpSession session) {// 1. 验证手机号if (RegexUtils.isPhoneInvalid(phone)) {// 如果不符合要求直接返回return Result.fail("手机号不正确");}// 2.生成验证码String code = RandomUtil.randomNumbers(6);// 3.保存验证码到Redis中--验证码设置过期时间为60stemplate.opsForValue().set(LOGIN_CODE_KEY + phone, code, LOGIN_CODE_TTL, TimeUnit.MINUTES);// 4.发送验证码log.debug("验证码是:{}", code);return Result.ok();}
【第三步】用户点击登录按钮,数据【手机号+验证码】都会流转到登录业务
@Overridepublic Result login(LoginFormDTO loginForm, HttpSession session) {// 1. 验证手机号String phone = loginForm.getPhone();if (RegexUtils.isPhoneInvalid(phone)) {return Result.fail("手机号格式错误");}// 2. 从Redis中获取验证码String code = template.opsForValue().get(LOGIN_CODE_KEY + phone);if (code == null || !code.equals(loginForm.getCode())) {return Result.fail("验证码错误");}// 3.根据手机号查询用户信息User user = query().eq("phone", phone).one();// 4. 用户不存在则创建用户到数据库if (user == null) {user = CreateNewUser(phone);}// 5.保存用户到RedisString token = UUID.randomUUID(false).toString();UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);// 设置Long类型的数据转换为字符串类型的。Map userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),CopyOptions.create().setIgnoreNullValue(true).setFieldValueEditor((fieldName,fieldValue)->fieldValue.toString()));String tokenKey = LOGIN_USER_KEY + token;template.opsForHash().putAll(tokenKey,userMap);template.expire(tokenKey,LOGIN_USER_TTL,TimeUnit.MINUTES);// 6.返回Tokenreturn Result.ok(token);}private User CreateNewUser(String phone) {User user = new User();user.setPhone(phone);user.setNickName(USER_NICK_NAME_PREFIX + RandomUtil.randomString(6));save(user);return user;}
【第四步】登录状态校验
首先数据会被我们之前提到的拦截器进行拦截
第一个拦截器代码如下:
package com.hmdp.utils;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 org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.concurrent.TimeUnit;import static com.hmdp.utils.RedisConstants.LOGIN_USER_KEY;
import static com.hmdp.utils.RedisConstants.LOGIN_USER_TTL;public class RefleshInterceptor implements HandlerInterceptor {private StringRedisTemplate template;public RefleshInterceptor(StringRedisTemplate template) {this.template = template;}@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 1.获取tokenString token = request.getHeader("authorization");if (StrUtil.isBlank(token)) {return true;}String tokenKey = LOGIN_USER_KEY + token;Map
【第五步】
从第一个拦截器中出来以后,会进入第二个拦截器
至此所有登录相关校验执行关闭。
package com.hmdp.utils;import com.hmdp.dto.UserDTO;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 1. 查询ThreadLocalUserDTO user = UserHolder.getUser();if (user == null) {// 不存在拦截response.setStatus(401);return false;}return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {UserHolder.removeUser();}
}
【完整流程图如下】:首先进行短信验证码登录,注册--->校验登录状态。
