基于session实现登录
1.发送短信验证码

@Override
public Result sendCode(String phone, HttpSession session) {
//1.校验手机号是否合规
if (RegexUtils.isPhoneInvalid(phone)) {
//2.不合规直接返回 错误信息
return Result.fail("手机号错误");
}
//3.如果合规生成验证码
String code = RandomUtil.randomString(4);
//4.将验证码保存到session中
session.setAttribute("code",code);
//5.发送验证码
log.info("code: {}",code);
//返回ok
return Result.ok();
}
ServletContext:上下文对象,在服务器启动时被创建,关闭时被注销,被所有Servlet共享,可在web.xml中进行配置,存放一些初始化数据,拥有最长的生命周期。
HttpSession:会话对象,浏览器请求服务器时被创建,关闭浏览器窗口或页面不刷新过期时被销毁,拥有较长的生命周期。
ServletRequest:请求对象,浏览器每次发送请求时被创建,响应结束之后被销毁,用于存放来自页面的参数和浏览器信息,生命周期最短。
2.短信验证、登录、注册功能
@Override
public Result login(LoginFormDTO loginForm, HttpSession session) {
//1.校验手机号的格式
String phone = loginForm.getPhone();
if (RegexUtils.isPhoneInvalid(phone)) {
//2.不一致直接报错
return Result.fail("手机号错误");
}
//3.比较验证码
Object cacheCode = session.getAttribute("code");
String code = loginForm.getCode();
if(session==null || !cacheCode.toString().equals(code)){
//4.不一致直接报错
return Result.fail("错误信息");
}
//5.根据手机号查询用户
LambdaQueryWrapper<User> query = new LambdaQueryWrapper<>();
query.eq(User::getPhone,loginForm.getPhone());
User user = this.getOne(query);
if(user==null){
//6.不存在直接创建新用户保存到数据库中
user=createUserWithPhone(loginForm.getPhone());
}
//7.最终将用户信息保存到session中
session.setAttribute("user",user);
return Result.ok();
}
private User createUserWithPhone(String phone) {
User user = new User();
user.setPhone(phone);
user.setNickName(USER_NICK_NAME_PREFIX+RandomUtil.randomString(6));
this.save(user);
return user;
}
3.登录校验功能

创建拦截器
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//1.获取session
HttpSession session = request.getSession();
//2.从session中拿到用户信息
Object user = session.getAttribute("user");
if(user==null){
//3.如果不存在直接拦截 返回401状态
response.setStatus(401);
return false;
}
//4.存在 保存到ThreadLocal中实现共享
UserHolder.saveUser((User) user);
//5.放行
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//避免造成内存泄露
UserHolder.removeUser();
}
}
注册拦截器
//注册拦截器 及其相关配置
@Configuration
public class MvcConfig implements WebMvcConfigurer {
//添加拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor()).excludePathPatterns(
"/shop/**",
"/voucher/**",
"/shop-type/**",
"/upload/**",
"/blog/hot",
"/user/code",
"/user/login"
);
}
}
public class UserHolder {
private static final ThreadLocal<User> tl = new ThreadLocal<>();
public static void saveUser(User user){
tl.set(user);
}
public static User getUser(){
return tl.get();
}
public static void removeUser(){
tl.remove();
}
}
ThreadLocal叫做线程变量,意思是ThreadLocal中*填充的变量*属于*当前线程*,该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。


















