spring boot3登录开发-3(2短信验证登录/注册逻辑实现)

 

⛰️个人主页:     蒾酒

🔥系列专栏:《spring boot实战》

🌊山高路远,行路漫漫,终有归途


目录

写在前面

上文衔接

内容简介

功能分析

短信验证登录实现

1.创建交互对象

用户短信登录/注册DTO

创建用户登录VO

2.创建自定义业务异常

创建验证码错误异常

创建用户被封禁异常

 创建用户注册失败异常

3.登录注册业务逻辑实现

4.测试接口

调用短信验证码发送接口

调用短信验证登录接口

写在最后


写在前面

本文介绍了springboot开发后端服务中,短信验证码登录功能的设计与实现,坚持看完相信对你有帮助。

同时欢迎订阅springboot系列专栏,持续分享spring boot的使用经验。

上文衔接

本文衔接上文,可以看一下:

spring boot3登录开发-2(2短信验证码接口实现)-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/qq_62262918/article/details/136888851?spm=1001.2014.3001.5501

用户表设计如下:

create table user
(
    id           bigint auto_increment comment '主键'
        primary key,
    user_name    varchar(32)                            null comment '用户昵称',
    password     varchar(256)                           null comment '密码',
    user_account varchar(64)                            null comment '账号',
    user_role    varchar(256) default 'user'            null comment '用户角色:user / admin',
    avatar       varchar(1024)                          null comment '头像',
    create_time  datetime     default (now())           null comment '创建时间',
    update_time  datetime     default CURRENT_TIMESTAMP null comment '更新时间',
    is_delete    tinyint(1)   default 0                 null comment '逻辑删除:1删除/0存在',
    gender       tinyint(1)                             null comment '性别',
    status       tinyint(1)   default 1                 not null comment '状态:1正常0禁用',
    phone        varchar(11)                            null comment '手机号'
)
    comment '用户表';

内容简介

上文我们已经实现了短信验证码的发送接口,本文我们来实现这个短信验证登录/注册逻辑。

功能分析

  • 手机号是新手机号则先注册,注册完执行登录
  • 已经注册过的手机号,直接执行登录

短信验证登录实现

1.创建交互对象

用户短信登录/注册DTO

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import lombok.Data;

/**
 * @author mijiupro
 */
@Data
public class UserSmsLoginDTO {

    @NotBlank( message = "手机号不能为空")
    @Pattern(regexp = "^1[3456789]\\d{9}$", message = "手机号格式不正确")
    private String phone;//手机号

    @NotBlank( message = "验证码不能为空")
    private String captcha;//验证码
}

创建用户登录VO

import lombok.Builder;
import lombok.Data;
 
import java.io.Serializable;
 
 
/**
 * @author mijiupro
 */
@Data
@Builder
public class UserLoginVO implements Serializable {
    private String token;//令牌
    private String userName;//用户名
    private String avatar;//头像
}

2.创建自定义业务异常

说白了就是登录代码可能会判断账号是否存在,密码是否正确,当账号不存在或密码错误需要返回对应提示信息,这种类似情况多了你的代码就会很多if-return,代码就会很难看;那么通过自定义异常去到异常处理的方法里面写对应返回提示以及其他逻辑,这样直接抛出对应异常AOP拦截到该异常走对应异常处理逻辑即可。(一句话概括就是:把处理特殊业务异常情况的代码逻辑抽取出来放到别的类里面写,可以使代码更加清晰和可维护)

创建验证码错误异常

import com.mijiu.commom.enumerate.ResultEnum;
import lombok.Getter;
 
/**
 * @author mijiupro
 */
@Getter
public class CaptchaErrorException extends RuntimeException {
    private final ResultEnum resultEnum;//返回提示信息枚举(code,message)
 
    public CaptchaErrorException(ResultEnum resultEnum) {
        this.resultEnum = resultEnum;
    }
}

创建用户被封禁异常

import com.mijiu.commom.enumerate.ResultEnum;
import lombok.Getter;
 
/**
 * @author mijiupro
 */
@Getter
public class AccountForbiddenException extends RuntimeException {
    private final ResultEnum resultEnum;
 
    public AccountForbiddenException(ResultEnum resultEnum) {
        this.resultEnum = resultEnum;
    }
}

 创建用户注册失败异常

import com.mijiu.commom.enumerate.ResultEnum;
import lombok.Getter;

/**
 * @author mijiupro
 */
@Getter
public class AccountRegisterFailException extends RuntimeException {
    private final ResultEnum resultEnum;//返回提示信息枚举(code,message)

    public AccountRegisterFailException(ResultEnum resultEnum) {
        this.resultEnum = resultEnum;
    }
}

3.登录注册业务逻辑实现

import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.mijiu.commom.enumerate.ResultEnum;
import com.mijiu.commom.exception.*;
import com.mijiu.commom.model.dto.UserLoginDTO;
import com.mijiu.commom.model.dto.UserSmsLoginDTO;
import com.mijiu.commom.model.vo.UserLoginVO;
import com.mijiu.commom.util.JwtUtils;
import com.mijiu.entity.User;
import com.mijiu.mapper.UserMapper;
import com.mijiu.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;


import java.util.Map;
import java.util.Objects;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author 蒾酒
 * @since 2024-02-03
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private final UserMapper userMapper;
    private final JwtUtils jwtUtils;
    private final StringRedisTemplate stringRedisTemplate;

    public UserServiceImpl(UserMapper userMapper, JwtUtils jwtUtils, StringRedisTemplate stringRedisTemplate) {
        this.userMapper = userMapper;
        this.jwtUtils = jwtUtils;
        this.stringRedisTemplate = stringRedisTemplate;
    }

 

    @Override
    public UserLoginVO SmsLogin(UserSmsLoginDTO userSmsLoginDTO) {
        // 校验验证码是否存在
        HashOperations<String, String, String> hashOps = stringRedisTemplate.opsForHash();
        String captcha = hashOps.get("login:sms:captcha:" + userSmsLoginDTO.getPhone(), "captcha");

        if (StringUtils.isEmpty(captcha)) {
            log.error("手机号 {} 的验证码不存在或已过期", userSmsLoginDTO.getPhone());
            throw new CaptchaErrorException(ResultEnum.USER_CAPTCHA_NOT_EXIST);
        }

        // 查询用户是否已注册
        User loginUser = new LambdaQueryChainWrapper<>(userMapper).eq(User::getPhone, userSmsLoginDTO.getPhone()).one();

        // 如果未注册则进行注册
        if (Objects.isNull(loginUser)) {
            loginUser = register(userSmsLoginDTO.getPhone());
        }

        // 校验验证码是否正确
        if (!userSmsLoginDTO.getCaptcha().equals(captcha)) {
            log.error("手机号 {} 的验证码错误", userSmsLoginDTO.getPhone());
            throw new CaptchaErrorException(ResultEnum.AUTH_CODE_ERROR);
        }
        //判断用户是否被禁用
        if (!loginUser.getStatus()) {
            throw new AccountForbiddenException(ResultEnum.USER_ACCOUNT_FORBIDDEN);
        }
        log.info("手机号 {} 用户登录成功", userSmsLoginDTO.getPhone());

        return UserLoginVO.builder()
                .token(jwtUtils.generateToken(Map.of("userId", loginUser.getId()), "user"))
                .userName(loginUser.getUserName())
                .build();
    }

    private User register(String phone) {
        User user = new User();
        user.setPhone(phone);
        user.setUserName(phone);
        user.setStatus(true);
        if (userMapper.insert(user) < 1) {
            log.error("手机号 {} 用户注册失败!", phone);
            throw new AccountRegisterFailException(ResultEnum.USER_REGISTER_FAIL);
        }
        log.info("手机号 {} 用户注册成功", phone);
        return user;
    }
}

4.测试接口

使用swagger3进行测试

Spring Boot3整合knife4j(swagger3)_springboot3 knife4j-CSDN博客文章浏览阅读2.3k次,点赞39次,收藏54次。Knife4j · 集Swagger2及OpenAPI3为一体的增强解决方案. | Knife4j (xiaominfo.com)作者的使用的spring boot 3.2.2为当前最新版,所以依赖导入最新的knife4j 4.4.0。3.1 增强模式 | Knife4j (xiaominfo.com)好一个spring boot项目且版本为3X,项目可正常启动。快速开始 | Knife4j (xiaominfo.com)接下来配置以下接口文档的作者等信息。@Tag注解:标记接口类别。_springboot3 knife4jhttps://blog.csdn.net/qq_62262918/article/details/135761392?spm=1001.2014.3001.5502

调用短信验证码发送接口

调用短信验证登录接口

第一次登录所以也就自动注册成功了。

写在最后

springboot实现短信验证登录注册到这里就结束了,本文介绍了一种通用的短信验证登录实现方式,代码逻辑清晰。任何问题评论区或私信讨论,欢迎指正。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux利用Jenkins部署SpringBoot项目保姆级教程

在当今快速发展的软件开发领域&#xff0c;持续集成和持续部署&#xff08;CI/CD&#xff09;已经成为提升开发效率、缩短产品上市时间的关键实践。Linux系统以其稳定性和开源友好性&#xff0c;成为众多开发者和企业的首选平台。而Spring Boot&#xff0c;作为一个轻量级的Jav…

【论文笔记】Text2QR

论文&#xff1a;Text2QR: Harmonizing Aesthetic Customization and Scanning Robustness for Text-Guided QR Code Generation Abstract 二维码通常包含很多信息但看起来并不美观。stable diffusion的出现让平衡扫描鲁棒性和美观变为可能。 为了保证美观二维码的稳定生成&a…

STM32FATFS(未完待续)

注意&#xff0c;本博客适合像我一样的小白&#xff0c;会的不多&#xff0c;但是想快速做些东西&#xff0c;不适合会写驱动的大佬。另外&#xff0c;示例代码中的注释有误&#xff08;从多个项目中移植过来的&#xff0c;未做更改&#xff09;&#xff0c;请不要被误导&#…

ICLR 2024 | 鸡生蛋蛋生鸡?再论生成数据能否帮助模型训练

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 新建了人工智能中文站https://ai.weoknow.com 每天给大家更新可用的国内可用chatGPT资源 发布在https://it.weoknow.com 更多资源欢迎关注 随着生成模型&#xff08;如 ChatGPT、扩散模型&#xff09;飞速发展&#x…

【详细讲解语言模型的原理、实战与评估】

&#x1f308;个人主页:程序员不想敲代码啊&#x1f308; &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家&#x1f3c6; &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提…

《2023网络安全行业薪资发展趋势报告》.pdf

《2023网络安全行业薪资发展趋势报告》.pdf 前段时间看到了一份网络安全的最新数据&#xff0c;反映了2023年截至目前的网络安全行业&#xff0c;以及网络安全人才的发展情况。 前段时间忙着赶项目一直没时间&#xff0c;今天终于有空和你唠嗑了。 很多网工小白对安全的向往…

基于DCT(离散余弦变换)的图像水印算法,Matlab实现

博主简介&#xff1a; 专注、专一于Matlab图像处理学习、交流&#xff0c;matlab图像代码代做/项目合作可以联系&#xff08;QQ:3249726188&#xff09; 个人主页&#xff1a;Matlab_ImagePro-CSDN博客 原则&#xff1a;代码均由本人编写完成&#xff0c;非中介&#xff0c;提供…

vue+elementUI搭建动态表头的表格

前提&#xff1a;以下代码是vue2项目结合elementUi完成的 数据结构 后端传来的数据是两个list&#xff0c;一个表头的list&#xff0c;一个表格内容的list // 表头 headTableAtts: [{ columnLabel: 姓名, columnName: name },{ columnLabel: 年龄, columnName: age },{ colu…

【Linux】防火墙iptables详解

目录 一、防护墙概述 二、防火墙 2.1名词 2.2使用规则 2.3表与链 2.3.1简介 2.3.2每个表说明 1&#xff09;filter表 2)nat表 2.4环境的配置 2.5iptables的命令参数 2.6 配置filter表规则 2.6.1备份与恢复 2.6.2案例1&#xff1a;禁止访问22端口 2.6.3案例2&…

GT收发器第六篇_GT channel内部时钟关系

文章目录 一、TX端时钟二、RX端时钟 一、TX端时钟 TX端可分为4个区域&#xff0c;分别为FPGA TX接口、PCS靠FPGA侧、PCS靠PMA侧、PMA&#xff0c;如下图。GTX/GTH发射器包括TXBUFFER和TX相位校准电路&#xff0c;以解决时钟域之间的相位差。TX相位校准电路用于TXBUFFER被旁路时…

element-ui badge 组件源码分享

今日简单分享 badge 组件的源码实现&#xff0c;主要从以下两个方面&#xff1a; 1、badge 组件页面结构 2、badge 组件属性 一、badge 组件页面结构 二、badge 组件属性 补充几个标签的用途&#xff1a; sub&#xff1a;下标、sup&#xff1a;上标、var 变量 代码如下&am…

AIGC之gradio系列学习教程(二)Components

简述: 让我们继续了解一下 Gradio 的一些主要功能。本指南旨在对构建演示时应注意的各种事项进行高级概述。 Components Gradio 包含 30 多个预构建组件(以及许多用户构建的自定义组件),只需一行代码即可在演示中用作输入或输出。这些组件对应于机器学习和数据科学中的常…

C++初学者:如何优雅地写程序

我喜欢C语言的功能强大&#xff0c;简洁&#xff0c;我也喜欢C#的语法简单&#xff0c;清晰&#xff0c;写起来又方便好用。 一、为什么不用C语言写程序。 C语言用来做题目&#xff0c;考试研究是很方便的&#xff0c;但是用来写程序做软件&#xff0c;你就会发现&#xff0c…

解决Centos7无法连接网络和访问网页连接不上问题

一、网络无法连接问题 网络无法连接的问题我查到了一个很良心的操作&#xff0c;不用重装&#xff0c;因为可能是你虚拟机设置上的问题。我先写我的解决方案&#xff0c;再附上其他几种解决方案。 问题一&#xff1a; 虚拟机的问题****加粗样式 解决&#xff1a; &#xff08;…

landsat8数据产品说明

1、下载数据用户手册 手册下载网址&#xff0c;搜索landsat science关键词&#xff0c;并点击到官网下载。 2、用户手册目录 3、landsat8数据产品说明 具体说明在手册的第四章&#xff0c;4.1.4数据产品章节&#xff0c;具体描述如下&#xff1a; 英文意思&#xff1a; L8 的…

Plesk环境中签发免费SSL证书的操作与成效

在过去的一段时间内&#xff0c;我专注于在Plesk控制面板环境中为多个网站成功签发免费SSL证书&#xff0c;确保了这些站点的安全传输和用户数据保护。以下是对这一工作的全面总结&#xff0c;包括突出的工作亮点、具体实施过程、取得的成绩以及下一阶段的工作规划。 一、工作亮…

【C++】新的类功能和可变参数模板

目录 一、新的类功能1.1 默认成员函数1.1.1 移动构造函数1.1.2 移动赋值运算符重载 1.2 关键字default1.3 关键字delete 二、可变参数模板2.1 可变参数的函数模板2.2 递归方式展开函数2.3 empalce 一、新的类功能 1.1 默认成员函数 在之前的学习过程中&#xff0c;我们已经知…

走进车厂 | 移远通信以前沿车载技术,照亮智能网联汽车产业创新发展之路

无钥匙自动解锁方便快捷、实时路况导航精准高效、语音指令轻松控制车辆、车载娱乐系统丰富多样……随着智能化、数字化浪潮的不断推进&#xff0c;现如今的汽车出行焕然一新。 正如我们所见&#xff0c;汽车产业正在经历前所未有的变革。物联网、车联网等前沿技术的发展和应用&…

反弹shell的方法和场景

Netcat反弹Shell 1 NC正向反弹shell Netcat简称NC,是一个简单、可靠的网络工具,被誉为网络界的瑞士军刀。通NC可以进行端口扫描、 反弹Shell、端口监听和文件传输等操作,常用参数如下&#xff1a; -c指定连接后要执行的shell命令-e指定连接后要执行的文件名-k配置 Socket一…

C语言指针 深入浅出讲解

指针在我的理解就是一个指向值的地址&#xff0c;地址是连续的&#xff0c;比如这个&#xff1a; 我写了一个数组&#xff0c;分别赋值4&#xff0c;5&#xff0c;6...11&#xff1b; 它们的地址分别如下&#xff1a; 可以看到地址增长是4&#xff0c;这是因为&#xff0c;地…