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;}@Overridepublic 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实现短信验证登录注册到这里就结束了,本文介绍了一种通用的短信验证登录实现方式,代码逻辑清晰。任何问题评论区或私信讨论,欢迎指正。

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

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

相关文章

IOTX:未来市场爆发点的RWA协议?DePIN赛道被低估的龙头

从基本面来看&#xff0c;IoTeX的目标是创建一个连接的世界&#xff0c;在这个世界中&#xff0c;每个人都能控制自己的数据、设备和身份。通过区块链技术&#xff0c;IoTeX旨在解锁智能设备和数据的潜力&#xff0c;支持新一代的现实世界Dapp和数字资产的发展。IOTX始终致力于…

红黑树剖析

目录 一. 红黑树的概念 二. 红黑树的性质 三. 红黑树节点的定义 四. 红黑树的插入操作 4.1 uncle存在且颜色为红 4.2 uncle不存在或者uncle存在且为黑 五. 整体代码展示 一. 红黑树的概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每…

OpenCV 4.9基本绘图

返回&#xff1a;OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇&#xff1a;OpenCV使用通用内部函数对代码进行矢量化 下一篇&#xff1a;OpenCV系列文章目录&#xff08;持续更新中......&#xff09; ​目标 在本教程中&#xff0c;您将学习如何&am…

ResutBuilder 学习笔记二:增加新的输入数据类型

ResutBuilder 学习笔记二&#xff1a;增加新的输入数据类型 我们在前面的博客中创建了一个非常简单的结果构建器ConcatBuilder&#xff0c;用于连接多个字符串。 ConcatBuilder虽然非常简单&#xff0c;但已经展现出一些令人兴奋的特征&#xff0c;代码简洁&#xff0c;清晰&a…

广东小团队惊艳业绩揭秘:链动模式助力面膜销售破千万!

惊爆&#xff01;广东一个默默无闻的小团队竟然在短短一个月内&#xff0c;仅凭销售面膜就实现了超过千万的惊人业绩&#xff01;这背后究竟隐藏着怎样的秘密武器呢&#xff1f; 揭开链动模式的神秘面纱 链动模式&#xff0c;作为社交电商领域的一股新兴力量&#xff0c;正以其…

[Python学习篇] Python注释

注释 单行注释 # # 单行注释 多行注释 """ """ 多行注释1 多行注释2 """ 多行注释 多行注释1 多行注释2

【强化学习的数学原理-赵世钰】课程笔记(一)基本概念

目录 一. 内容概述1. 通过案例介绍强化学习中的基本概念2. 在马尔可夫决策过程&#xff08;MDP&#xff09;的框架下将概念正式描述出来 二. 通过案例介绍强化学习中的基本概念1. 网格世界&#xff08;A grid world example&#xff09;2. 状态&#xff08;State&#xff09;3.…

Spring AOP + 自定义注解 实现公共字段的填充

Spring AOP 自定义注解 实现公共字段的填充 代码冗,不利于后期维护. 定义操作这些字段的方法类型 实现步骤&#xff1a; 自定义注解AutoFill,用于表示操作这些公共字段的方法自定义切面类AutoFillAspect,统一拦截&#xff0c;通过反射获取方法入参&#xff0c;并填充公共字段…

mysql常见故障及mysql优化

目录 mysql单实例常见故障 mysql主从常见故障 mysql优化 硬件优化 查询优化 操作系统的优化 my.cnf内参数的优化 mysql单实例常见故障 ERROR 2002 (HY000): Cant connect to local MySQL server through scoket /data/mysql/mysql.sock问题分析 数据库未启动或者数据库…

【THM】Burp Suite:Other Modules(其他模块)-初级渗透测试

介绍 除了广泛认可的Repeater和Intruder房间之外,Burp Suite 还包含几个鲜为人知的模块。这些将成为这个房间探索的重点。 重点将放在解码器、比较器、排序器和组织器工具上。它们促进了编码文本的操作,支持数据集的比较,允许分析捕获的令牌内的随机性,并帮助您存储和注释…

9、鸿蒙学习-开发及引用静态共享包(API 9)

HAR&#xff08;Harmony Archive&#xff09;是静态共享包&#xff0c;可以包含代码、C库、资源和配置文件。通过HAR可以实现多个模块或多个工程共享ArkUI组件、资源等相关代码。HAR不同于HAP&#xff0c;不能独立安装运行在设备上&#xff0c;只能作为应用模块的依赖项被引用。…

MongoDB 6.1 及以上版本使用配置文件的方式启动报错 Unrecognized option: storage.journal.enabled

如果你使用的 MongoDB 的版本大于等于 6.1&#xff0c;并且在 MongoDB 的配置文件中编写了如下内容 storage:journal:# 启用或禁用持久性日志以确保数据文件保持有效和可恢复# true 启用&#xff1b;false 不启用# 64 位系统默认启用&#xff0c;启用后 MongoDB 可以在宕机后根…

Linux多进程通信(1)——无名管道及有名管道使用例程

管道是半双工通信&#xff0c;如果需要 双向通信&#xff0c;则需要建立两个管道&#xff0c; 无名管道&#xff1a;只能父子进程间通信&#xff0c;且是非永久性管道通信结构&#xff0c;当它访问的进程全部终止时&#xff0c;管道也随之被撤销 有名管道&#xff1a;进程间不需…

RK3568驱动指南|第十四篇 单总线-第162章DS18B20驱动读时序编写

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

秒验资深玩家熬夜整理的15个常见问题,拿走不谢!

1、双卡双待手机如何登录&#xff1f; 针对双卡双待手机只取当前流量卡号 2、用其他手机号如何登录&#xff1f; 使用传统验证方式登录&#xff0c;例如验证码登录 3、一键登录只支持4G吗&#xff1f; 电信支持4G,5G网络取号&#xff0c;移动, 联通支持5G,4G, 3G, 2G网络取号…

数值金额计算js封装包含加减乘除四个方法,能确保浮点数运算不丢失精度

项目场景&#xff1a; 商城类项目中大多需要金额计算&#xff0c;我们知道计算机编程语言里浮点数计算会存在精度丢失问题&#xff08;或称舍入误差&#xff09;&#xff0c;其根本原因是二进制和实现位数限制有些数无法有限表示 以下是十进制小数对应的二进制表示&#xff1…

python笔记(8)Tuple(元组)

目录 创建元组 元组取数 不支持修改和删除元素 元组运算符 元组内置函数 创建元组 Tuple 元组的元素不能修改&#xff0c;元组使用小括号&#xff08;&#xff09;&#xff0c;创建元组在括号里添加元素用逗号隔开即可。 创建空元组 tup1() 创建一个元素的元组&#xff…

Golang 开发实战day06 - Boolean Conditional

Golang 教程06 - Boolean & Conditional 1. Boolean & Conditional 1.1 什么是布尔类型&#xff1f; 想象一下&#xff0c;你正在玩一个古老的游戏&#xff0c;只有两个选项&#xff1a;是或否。在 Golang 中&#xff0c;这就是布尔类型&#xff0c;用 bool 关键字表…

【Linux实验室】DNS域名解析服务——超详细实验操作!

DNS域名解析 DNS域名解析服务——超详细实验操作&#xff01;&#xff01;&#xff01;序言DNS 基本概述分布式、层次数据库DNS 层次结构DNS 查询步骤DNS 查询类型DNS服务器类型DNS 缓存反向 DNS 查询如何检查 DNS 记录是否生效 Bind解析服务Bind简介bind的服务类型 DNS域名解析…

深入解析实时数仓Doris:Rollup上卷表与查询

码到三十五 &#xff1a; 个人主页 心中有诗画&#xff0c;指尖舞代码&#xff0c;目光览世界&#xff0c;步履越千山&#xff0c;人间尽值得 ! 目录 一、基本概念二、Aggregate 和 Unique 模型中的 ROLLUP三、Duplicate 模型中的 ROLLUP四、ROLLUP 调整前缀索引五、ROLLUP使…