Redis---------实现短信登录业务

news2024/10/7 14:33:38

目录

基于Session的短信登录

 ①首先看他的业务逻辑

②进行代码逻辑处理

基于Redis的短信登录

 ①首先看他的业务逻辑

 ②进行代码逻辑处理

 Controller:

 Service接口:

  Service实例:

 Mapper:

  封装ThreadLocal线程的数据操作:

 自定义拦截器:

 拦截器配置文件:

 Redis常量配置文件:

 正则表达式文件:


基于Session的短信登录

 ①首先看他的业务逻辑

②进行代码逻辑处理

Controller层:

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    private IUserService userService;

    @Resource
    private IUserInfoService userInfoService;


    /**
     * 发送手机验证码
     */
    @PostMapping("code")
    public Result sendCode(@RequestParam("phone") String phone, HttpSession session) {

        return userService.sendCode(phone,session);
    }


    /**
     * 登录功能
     * @param loginForm 登录参数,包含手机号、验证码;或者手机号、密码
     */
    @PostMapping("/login")
    public Result login(@RequestBody LoginFormDTO loginForm, HttpSession session){

        return userService.login(loginForm,session);
    }


    //跳转到我的页面
    @GetMapping("/me")
    public Result me(){
        User user = UserHolder.getUser();
        return Result.ok(user);
    }

 Service层:

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    //发送验证码
    @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);

        //5,发送验证码给前端
        log.debug("发送验证码: "+code);

        return Result.ok();
    }

    //登陆
    @Override
    public Result login(LoginFormDTO loginForm, HttpSession session) {
        //1,校验手机号,看手机号是否合规
        String phone = loginForm.getPhone();
        if (RegexUtils.isPhoneInvalid(phone)) {
            //2,不符合则返回错误结果
            return Result.fail("手机号错误!");
        }

        //2,校验验证码
        Object Cachecode = session.getAttribute("code");//session里的验证码
        String code = loginForm.getCode();//前端提交过来的验证码

        if(Cachecode == null || !Cachecode.toString().equals(code)){
            //3,如果错误则返回
            return Result.fail("验证码错误!");
        }

        //4,正确的话就查询数据库中的数据
        User user = query().eq("phone", phone).one();

        //5,判断是否存在
        if(user == null){
            //6,如果没有查到就进行注册操作
            user= new User();
            user.setPhone(phone);
            user.setNickName( USER_NICK_NAME_PREFIX +RandomUtil.randomString(10));
            save(user);
        }

        //7,保存到Session中
        session.setAttribute("user",user);


        return Result.ok();
    }
}

 

基于Redis的短信登录

 ①首先看他的业务逻辑

 ②进行代码逻辑处理

 Controller:
import com.hmdp.dto.LoginFormDTO;
import com.hmdp.dto.Result;
import com.hmdp.entity.User;
import com.hmdp.entity.UserInfo;
import com.hmdp.service.IUserInfoService;
import com.hmdp.service.IUserService;
import com.hmdp.utils.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpSession;


@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    private IUserService userService;

    @Resource
    private IUserInfoService userInfoService;


    /**
     * 发送手机验证码,接受手机号参数以及session
     */
    @PostMapping("code")
    public Result sendCode(@RequestParam("phone") String phone, HttpSession session) {

        //把参数传到Service层去实现业务功能
        return userService.sendCode(phone,session);
    }

    /**
     * login登录功能
     * @param loginForm 登录参数,包含手机号、验证码;或者手机号、密码以及session
     */
    @PostMapping("/login")
    public Result login(@RequestBody LoginFormDTO loginForm, HttpSession session){

        把参数传到Service层去实现业务功能
        return userService.login(loginForm,session);
    }


    //进入我的页面发送的请求
    @GetMapping("/me")
    public Result me(){
        //在线程ThreadLocal把用户的数据拿出来并且返回到前端
        User user = UserHolder.getUser();
        System.out.println("user = " + user);
        //
        return Result.ok(user);
    }


}
 Service接口:
import com.baomidou.mybatisplus.extension.service.IService;
import com.hmdp.dto.LoginFormDTO;
import com.hmdp.dto.Result;
import com.hmdp.entity.User;

import javax.servlet.http.HttpSession;

public interface IUserService extends IService<User> {

    Result sendCode(String phone, HttpSession session);

    Result login(LoginFormDTO loginForm, HttpSession session);
}
  Service实例:
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.dto.LoginFormDTO;
import com.hmdp.dto.Result;
import com.hmdp.entity.User;
import com.hmdp.mapper.UserMapper;
import com.hmdp.service.IUserService;
import com.hmdp.utils.RegexUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpSession;
import java.util.concurrent.TimeUnit;
import static com.hmdp.utils.RedisConstants.*;
import static com.hmdp.utils.SystemConstants.USER_NICK_NAME_PREFIX;


@Service
//extends ServiceImpl<UserMapper, User>是mybatisplus中的IService接口,可以实现CRUD的快速操作
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    //redis-java客户端
    private StringRedisTemplate stringRedisTemplate;

    //发送验证码
    @Override
    public Result sendCode(String phone, HttpSession session) {
        //1,校验手机号,看手机号是否合规
        if (RegexUtils.isPhoneInvalid(phone)) {
            //2,不符合则返回错误结果
            return Result.fail("手机号错误!");
        }

        //3,符合就生成验证码
        String code = RandomUtil.randomNumbers(6);

        //4,保存验证码在Redis,设置有效期两分钟
        stringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY + phone, code , LOGIN_CODE_TTL , TimeUnit.MINUTES);

        //5,发送验证码给前端
        log.debug("发送验证码: "+code);

        return Result.ok();
    }

    //登录
    @Override
    public Result login(LoginFormDTO loginForm, HttpSession session) {
        //1,校验手机号,看手机号是否合规
        String phone = loginForm.getPhone();
        if (RegexUtils.isPhoneInvalid(phone)) {
            //2,不符合则返回错误结果
            return Result.fail("手机号错误!");
        }

        //2,校验验证码
        String Cachecode = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY + phone);//redis里的验证码
        String code = loginForm.getCode();//前端提交过来的验证码

        //redis里查不出数据,代表已经过期
        if(Cachecode == null || !Cachecode.equals(code)){
            //3,如果错误则返回
            return Result.fail("验证码错误!");
        }

        //4,正确的话就查询数据库中的数据
        User user = query().eq("phone", phone).one();

        //5,判断是否存在
        if(user == null){
            //6,如果没有查到就进行注册操作
            user= new User();
            user.setPhone(phone);
            user.setNickName( USER_NICK_NAME_PREFIX +RandomUtil.randomString(10));
            save(user);
        }

        //7,把用户数据保存到Redis中
        String token = IdUtil.randomUUID();//生成token
        String object_json = JSONUtil.parse(user).toString();//序列化
        stringRedisTemplate.opsForValue().set(LOGIN_USER_KEY+token,object_json,LOGIN_USER_TTL,TimeUnit.MINUTES);

        return Result.ok(token);
    }



}
 Mapper:
import com.hmdp.entity.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;


public interface UserMapper extends BaseMapper<User> {

}
  封装ThreadLocal线程的数据操作:
import com.hmdp.entity.User;

//线程里的数据的封装操作
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();
    }
}
 自定义拦截器:
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.hmdp.entity.User;
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.concurrent.TimeUnit;

import static com.hmdp.utils.RedisConstants.LOGIN_USER_KEY;

public class LoginInterceptor implements HandlerInterceptor {

    private StringRedisTemplate stringRedisTemplate;

    public LoginInterceptor(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }

    @Override
    //前置拦截器
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //校验登录状态
        //1,获取Token
        String token = request.getHeader("authorization");
        if (StrUtil.isBlank(token)) {
            response.setStatus(401);
            return false;
        }

        //2,获取Redis中的用户
        String s = stringRedisTemplate.opsForValue().get(LOGIN_USER_KEY+token);
        User user= JSONUtil.toBean(s, User.class);

        //3,判断用户是否存在
        if (user == null){
            //4,不存在直接拦截
            response.setStatus(401);
            return false;
        }

        //4,存在则保存信息到ThreadLocal
        UserHolder.saveUser(user);


        //5,刷新Token的有效期
        stringRedisTemplate.expire(LOGIN_USER_KEY+token,RedisConstants.LOGIN_USER_TTL, TimeUnit.MINUTES);
        return true;
    }


    @Override
    //后置拦截器
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        UserHolder.removeUser();
    }
}
 拦截器配置文件:
import com.hmdp.utils.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
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;

@Configuration
public class MVCCONFIG implements WebMvcConfigurer {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor(stringRedisTemplate))
                //“”里是添加要拦截的路径
                .addPathPatterns("/**")
                //“”里是设置不拦截的路径
                .excludePathPatterns("/user/login","/user/code","blog/hot","/shop/**","./shoptype/**","/upload/**","/voucher/**");

    }
}
 Redis常量配置文件:
public class RedisConstants {
    public static final String LOGIN_CODE_KEY = "login:code:";
    public static final Long LOGIN_CODE_TTL = 2L;
    public static final String LOGIN_USER_KEY = "login:token:";
    public static final Long LOGIN_USER_TTL = 30L;
}
 正则表达式文件:
import cn.hutool.core.util.StrUtil;


public class RegexUtils {
    /**
     * 是否是无效手机格式
     * @param phone 要校验的手机号
     * @return true:符合,false:不符合
     */
    public static boolean isPhoneInvalid(String phone){
        return mismatch(phone, RegexPatterns.PHONE_REGEX);
    }

    /**
     * 是否是无效邮箱格式
     * @param email 要校验的邮箱
     * @return true:符合,false:不符合
     */
    public static boolean isEmailInvalid(String email){
        return mismatch(email, RegexPatterns.EMAIL_REGEX);
    }

    /**
     * 是否是无效验证码格式
     * @param code 要校验的验证码
     * @return true:符合,false:不符合
     */
    public static boolean isCodeInvalid(String code){
        return mismatch(code, RegexPatterns.VERIFY_CODE_REGEX);
    }

}

在这里做一个总结:做这种业务主要是要捋清楚处理的步骤以及逻辑,像我们的发送验证码过程--->①前端发来数据请求参数和session②首先判断手机号是否符合正确的格式③如果不符合则返回错误,符合就可以生成验证码④验证码生成后将其保存到Redis中,并设置有效期⑤然后把验证码发送给前端。         前端收到验证码后填入并且点击登录按钮,就会发起一个带着参数的新的请求登录--->①后端收到请求首先判断手机号是否符合正确的格式②然后从Redis中把保存的验证码取出来与前端发过来的参数验证码进行比较③如果不相等或者Redis中无数据(即验证码已经过期)则返回错误④如果相等则去查询mysql数据库中是否有该数据⑤如果没有的话就要进行注册操作,把数据存到数据库中⑥最后把该数据存在Redis中并设置有限期。     点击登录后就会进入我们正式的”我的“页面。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1637706.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何快速搭建nginx虚拟主机

华子目录 实验1&#xff1a;基于IP地址的虚拟主机原理 实验2&#xff1a;基于端口号的虚拟主机原理 实验3&#xff1a;基于域名的虚拟主机原理 实验1&#xff1a;基于IP地址的虚拟主机 原理 如果一台服务器有多个IP地址&#xff0c;而且每个IP地址与服务器上部署的每个网站一一…

latex+vscode一直报错,配置文件json和环境变脸配置

1、json配置文件 {"latex-workshop.latex.tools": [{"name": "xelatex","command": "xelatex","args": ["-synctex1","-interactionnonstopmode","-file-line-error","%DOCF…

Large Language Models for Test-Free Fault Localization

基本信息 这是24年2月发表在ICSE 24会议&#xff08;CCF A&#xff09;的一篇文章&#xff0c;作者团队来自美国卡内基梅隆大学。 博客创建者 武松 作者 Aidan Z.H. Yang&#xff0c;Claire Le Goues&#xff0c;Ruben Martins&#xff0c;Vincent J. Hellendoorn 标签 …

C# 实现格式化文本导入到Excel

目录 需求 Excel 的文本文件导入功能 范例运行环境 配置Office DCOM 实现 组件库引入 OpenTextToExcelFile 代码 调用 小结 需求 在一些导入功能里&#xff0c;甲方经常会给我们一些格式化的文本&#xff0c;类似 CSV 那样的纯文本。比如有关质量监督的标准文件&…

ArrayList知识点详解

目录 1.简介 2.ArrayList的使用 &#xff08;1&#xff09;如何实例化ArrayList&#xff1f;&#xff08;如何创建&#xff1f;&#xff09; &#xff08;2&#xff09;如何构造使用&#xff1f; &#xff08;3&#xff09;为什么ArrayList的无参构造可以添加数据 &#…

【进收藏夹吃灰系列】算法学习指南

文章目录 [toc]分治算法 个人主页&#xff1a;丷从心 系列专栏&#xff1a;进收藏夹吃灰系列 分治算法 博客标题博客url【分治算法】【Python实现】Hanoi塔问题https://blog.csdn.net/from__2024_04_11/article/details/138093461?spm1001.2014.3001.5502

Flowable入门案例

资料地址1614912120/Flowable (github.com)https://github.com/1614912120/Flowable 步骤1&#xff1a;添加Flowable依赖 首先&#xff0c;您需要将Flowable引擎集成到您的项目中。您可以通过Maven、Gradle或手动下载jar包的方式来添加Flowable的依赖。 <?xml version&q…

CVPR 小样本土地覆盖制图 张洪艳教授团队获挑战赛冠军

提出了一个广义的基于少镜头分割的框架&#xff0c;以更新高分辨率土地覆盖制图中的新类&#xff0c;分为三个部分:(a)数据预处理:对基础训练集和新类的少镜头支持集进行分析和扩充;(b)混合分割结构:将多基学习器和改进的投影到正交原型(POP)网络相结合&#xff0c;增强基类识别…

公共 IP 地址与私有 IP 地址区别有哪些?

​  IP 地址是分配给互联网上每个设备的唯一数字 ID。 IP 地址可以在 Internet 上公开使用&#xff0c;也可以在局域网 (LAN)上私有使用。本文&#xff0c;我们主要探讨公共 IP 地址和私有 IP 地址之间的区别。 公共IP地址&#xff1a;公共IP地址是用于访问Internet的向外的I…

TouchGFX 总结

文章目录 使用中文字体多屏幕间交换数据UI to MCUMCU to UI API文档参考横竖屏切换 使用中文字体 添加一个textArea&#xff0c;默认的英文文本可见&#xff0c;输入中文字体后就看不见了&#xff0c;是因为这个默认的字体不支持中文&#xff0c;改一下字体就可以了&#xff1…

结构体反汇编解析

代码如下 #include<iostream> using namespace std; typedef struct Role {int HP;int MP; }*PRole; int main() {Role user;PRole puser;puser &user;puser->HP 1500;puser->MP 2000;user.HP 2500;user.MP 3000;return 0; }基础知识 如果是地址就是采用…

关于Centos 7/8 网络设置 与工具连接

网络三步曲的配置 1、首先更改虚拟机的网络配置 查看子网地址以及网关 如果有要求需要更改IP地址&#xff0c;规定第三位是指定数值&#xff0c;那么需要全部更改 例如&#xff0c;IP地址为192.168.200.30 其中200为重点&#xff0c;更改时为以下步骤 1、点击DHCP设置&#x…

红米1s 刷入魔趣 (Mokee)ROM(Android 7.1)

目录 背景准备工具硬件&#xff08;自己准备&#xff09;软件&#xff08;我会在文末提供链接&#xff09; 刷机步骤1. 重启电脑2. 安装驱动3. 刷入TWRP4. 清空数据5. 刷入魔趣6. 开机 结尾下载链接 本文由Jzwalliser原创&#xff0c;发布在CSDN平台上&#xff0c;遵循CC 4.0 B…

云计算技术概述_1.云计算相关概念

1.关于IBM“蓝云&#xff08;Blue Cloud&#xff09;”计划 IBM 推出的“蓝云&#xff08;Blue Cloud&#xff09;”计划为客户带来即可使用的云计算(Cloud Computing)。它包括一系列的云计算产品&#xff0c;使计算不仅仅局限在本地机器或远程Server Farms&#…

GPT3 终极指南(一)

原文&#xff1a;zh.annas-archive.org/md5/6de8906c86a2711a5a84c839bec7e073 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 前言 GPT-3&#xff0c;或者说是 Generative Pre-trained Transformer 3&#xff0c;是由 OpenAI 开发的基于 Transformer 的大型语言模型…

【R语言数据分析】数据类型与数据结构

R的数据类型有数值型num&#xff0c;字符型chr&#xff0c;逻辑型logi等等。 R最常处理的数据结构是&#xff1a;向量&#xff0c;数据框&#xff0c;矩阵&#xff0c;列表。 向量有数值型向量&#xff0c;字符型向量&#xff0c;逻辑型向量等&#xff0c;字符型向量就是反应…

书生·浦语 大模型(学习笔记-9)OpenCompass 大模型评测实战

目录 一、评测实现双赢 二、评测遇到的问题 三、如何评测大模型&#xff08;大概总结4大类方法&#xff09; 四、评测工具链及流水线 五、实战评测 GPU的环境安装 查看支持的数据集和模型 启动评测(会缺少protibuf库&#xff0c;提前安装&#xff09; 测评结果 一、评…

【linux学习指南】linux 环境搭建

文章目录 &#x1f4dd;前言&#x1f320; 云服务器的选择&#x1f320;阿里云&#x1f320;腾讯云&#x1f320;华为云 &#x1f320;使用 XShell 远程登陆到 Linux&#x1f309;下载 XShell &#x1f320;查看 Linux 主机 ip&#x1f309; XShell 下的复制粘贴&#x1f309; …

Linux下安装snaphu

1、官网下载安装包 2、解压&#xff0c;移动文件夹到/usr/local/下 3、在/usr/local/下创建man&#xff0c;在man下创建man1文件夹 4、进入到snaphu的src文件夹里&#xff0c;执行sudo make&#xff0c;如果报错 在这个 Makefile 中&#xff0c;-arch x86_64 是 macOS 特定的…

ai口语软件有合适的吗?分享4款!

在全球化日益深入的今天&#xff0c;英语作为国际通用语言&#xff0c;其重要性不言而喻。然而&#xff0c;传统的英语学习方式往往枯燥无味&#xff0c;难以持续。幸运的是&#xff0c;随着人工智能技术的快速发展&#xff0c;AI英语口语软件应运而生&#xff0c;为语言学习者…