springboot发送短信验证码,结合redis 实现限制,验证码有效期2分钟,有效期内禁止再次发送,一天内发送超3次限制

springboot结合redis发送短信验证码,实现限制发送操作

    • 前言(可忽略)
    • 实现思路
    • 正题
    • 效果图示例
      • 手机号不符合规则校验图
      • 成功发送验证码示例图
      • redis中缓存随机数字验证码,2分钟后失效删除redis缓存图
      • 验证码有效期内 返回禁止重复发送图
      • 验证码24小时内发送达到3次,限制再次发送验证码图
      • idea代码控制台输出日志信息图
      • 接口压测1万次全部success图
    • 使用到的maven依赖
    • redis 缓存Key 统一静态管理类
    • 返回错误信息枚举定义
    • redis缓存util工具类封装
    • service验证码发送接口定义和实现代码
      • 接口定义
      • 接口实现类
    • controller业务接口请求代码
    • 接口请求测试
      • 请求
      • 响应
    • 结尾

前言(可忽略)

好久没有更新过csdn博客了,从2023年到发布这篇文章之前,感觉有1年没有写代码的状态,大多还是和 工作/日常 有关 影响,有点退步了。 现在找回了写代码的那种状态,找回状态后发现还是要多学习,要始终保持着热爱 虚心钻研之心.

工作之余想到了一些功能点,空闲时间自己实现了下,做个记录。 有时间还是得要多写点业务代码,不然一直在退步.
----好了 不多说了,进入文章正题---</b>

实现思路

调用发送短信接口,输入手机号发送短信。

发送请求后,判断手机号码格式是否正确,格式不正确,返回格式错误信息。

格式正确,进行发送短信,发送成功时,redis中缓存该手机号验证码2分钟 同时缓存24小时发送次数默认1。

如验证码2分钟未失效,再次使用相同手机号码发短信时,返回验证码在有效期内请勿重复发送。

2分钟验证码失效后,会自动删除该验证码缓存。可再次对该手机号发送验证码,再次发送成功后,该号码24小时发送次数缓存值+1,此时短信发送成功第二次。

24小时内重复发送短信测试,直到达到3次后。 发送验证码返回24小时发送验证码3次,发送失败,请于1天后重试。

正题

使用springboot框架结合redis发送验证码, 实现限制功能,验证码有效期2分钟,有效期内禁止再次发送,一天内发送超3次限制.

代码中定义短信云平台模板,进行模拟发送真实验证码,可接入阿里云等各种第三方云短信模板,结合各种场景进行验证码后续的业务操作。

在这里插入图片描述

// 模拟阿里云发送短信业务, 模板示例值.  可自行对接
String sendMsg = "【提先森的小站】测试阿里云服务短信发送,此次操作验证码为 {} ,该验证码有效期2分钟,请尽快输入验证.";

使用良好优雅的代码规范实现限制发送验证码功能, 加入统一枚举返回错误类型,统一redis缓存key值管理~


以下开始正文 附上效果图示例和完整代码,希望对看到有需要的朋友有所帮助。
如有帮到您,还希望点赞支持一下yo~


效果图示例

手机号不符合规则校验图

在这里插入图片描述

成功发送验证码示例图

在这里插入图片描述

redis中缓存随机数字验证码,2分钟后失效删除redis缓存图

在这里插入图片描述

验证码有效期内 返回禁止重复发送图

在这里插入图片描述

验证码24小时内发送达到3次,限制再次发送验证码图

在这里插入图片描述

idea代码控制台输出日志信息图

在这里插入图片描述

接口压测1万次全部success图

在这里插入图片描述


在这里插入图片描述

使用到的maven依赖

        <!--redis--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!--hutool 工具使用参考文档:https://hutool.cn/ --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.20</version></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.10</version></dependency>  

redis 缓存Key 统一静态管理类

/*** @author zxt* @version 1.0.0* @date 2023年06月20日 11:29:16* @describe redis 缓存Key 统一管理*/
public class RedisKeyConstant {// 发送验证码keypublic static final String USER_REGISTER_KEY = "user:register:send_code:{}";// 手机号24小时内发送验证码次数keypublic static final String USER_REGISTER_COUNT_KEY = "user:register:day_send_count:{}";public static final String USER_INFORMATION_KEY = "user:information:{}";public static final Integer USER_INFORMATION_EXPIRED = 3;public static final String USER_LOGIN_INFORMATION_KEY = "login:info:{}";public static final Integer USER_LOGIN_INFORMATION_EXPIRED = 2;public static final String APPLET_TELECOM_TOKEN_KEY = "user:token:{}";public static final Integer APPLET_TELECOM_TOKEN_EXPIRED = 1;}

返回错误信息枚举定义

/*** @author zxt* @apiNote* @date 2024/4/16 10:23*/
public enum ServiceErrorEnum {SUCCESS(0, "OK!"),SERVER_ERROR(500, "Internal Server Error"),PARAM_FAIL(-1, "Param Fail"),REGISTER_RECAPTCHA_INPUT_ERROR(10000, "注册失败, 验证码输入错误..."),REGISTER_RECAPTCHA_EXPIRE(10001, "注册失败, 手机号验证码信息不存在..."),REGISTER_RECAPTCHA_ISVALID(10002, "验证码在有效期内, 2分钟内请勿重复发送... "),REGISTER_CODE_COUNT_ERROR(10003, "24小时内已发送验证码3次,发送已限制 请于1天后重试..."),REGISTER_PHONENUMBER_ERROR(10004, "请检查手机号码是否符合规范..."),REGISTER_PHONENUMBER_ISREGISTER(10006, "短信发送失败,该手机号已注册..."),REGISTER_PHONENUMBER_EXIST(10007, "该手机号已注册,注册失败..."),LOGIN_PASSWORD_ERROR(10008, "用户名或密码输入错误,登录失败..."),LOGIN_NOREGISTER_ERROR(10009, "手机号未注册,登录失败..."),;/*** code*/private int code;/*** message*/private String message;public int getCode() {return code;}public void setCode(int code) {this.code = code;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}ServiceErrorEnum(int code, String message) {this.code = code;this.message = message;}
}

redis缓存util工具类封装

/*** spring redis 工具类** @author zxt**/
@SuppressWarnings(value = { "unchecked", "rawtypes" })
@Component
@Slf4j
public class RedisCache
{@Resourcepublic RedisTemplate redisTemplate;private static final Long SUCCESS = 1L;private static final Integer DEFAULT_EXPIRE_TIME = 30 * 60;/*** 缓存基本的对象,Integer、String、实体类等** @param key 缓存的键值* @param value 缓存的值*/public <T> void setCacheObject(final String key, final T value){redisTemplate.opsForValue().set(key, value);}/*** 缓存基本的对象,Integer、String、实体类等** @param key 缓存的键值* @param value 缓存的值* @param timeout 时间* @param timeUnit 时间颗粒度*/public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit){redisTemplate.opsForValue().set(key, value, timeout, timeUnit);}/*** 获得缓存的基本对象。** @param key 缓存键值* @return 缓存键值对应的数据*/public <T> T getCacheObject(final String key){ValueOperations<String, T> operation = redisTemplate.opsForValue();return operation.get(key);}/*** 判断 key是否存在** @param key 键* @return true 存在 false不存在*/public Boolean hasKey(String key){return redisTemplate.hasKey(key);}/*** 删除单个对象** @param key*/public boolean deleteObject(final String key){return redisTemplate.delete(key);}}

service验证码发送接口定义和实现代码

接口定义

package com.tiz.third.sevice;import com.baomidou.mybatisplus.extension.service.IService;
import com.tiz.third.pojo.User;import java.util.Map;/*** @author zxt* @date 2024-05-24 17:57* @describe 注册登录接口业务*/
public interface ModelService{/*** 发送验证码* @param phoneNumber* @return*/public String sendVerificationCode(String phoneNumber);/*** 注册* @param user* @return*///.....更多接口实现已略
}

接口实现类

/*** @author zxt* @date 2024-05-24 18:01* @describe*/
@Slf4j
@Service
public class ModelServiceImpl implements ModelService {@Resourceprivate RedisCache redisCache;@Overridepublic String sendVerificationCode(String phoneNumber) {// 模拟阿里云发送短信业务, 模板示例值。 可自行对接String sendMsg = "【提先森的小站】测试阿里云服务短信发送,此次操作验证码为 {} ,该验证码有效期2分钟,请尽快输入验证.";synchronized (this) {boolean phoneIsValid = Validator.isMobile(phoneNumber);if (!phoneIsValid) {log.error("请确认发送验证码手机号格式是否正确");return ServiceErrorEnum.REGISTER_PHONENUMBER_ERROR.getMessage();}//手机验证码keyString msgKey = StringUtils.format(RedisKeyConstant.USER_REGISTER_KEY, phoneNumber);//手机验证码valueString msgValue = StringUtils.format(sendMsg, RandomUtil.randomNumbers(4));//判断手机验证码key是否存在Boolean registerExists = redisCache.hasKey(msgKey);if (registerExists) {log.error("验证码在有效期内,2分钟内请勿重复发送!");return ServiceErrorEnum.REGISTER_RECAPTCHA_ISVALID.getMessage();}//手机验证码1天内获取次数String countKey = StringUtils.format(RedisKeyConstant.USER_REGISTER_COUNT_KEY, phoneNumber);//判断验证码1天发送次数key是否存在Boolean cacheDayCount = redisCache.hasKey(countKey);if (cacheDayCount) {Integer count = redisCache.getCacheObject(countKey);//发送次数值控制Integer newCacheCount = count + 1;if (newCacheCount > 3) {log.error("手机号:{} 注册验证码24小时内已发送3次,发送验证码失败,请于24小时后重试!", phoneNumber);return ServiceErrorEnum.REGISTER_CODE_COUNT_ERROR.getMessage();}log.error("手机号:{} 注册验证码发送成功, 24小时内已发送{}次", phoneNumber, newCacheCount);//缓存手机验证码1天发送次数值+1redisCache.setCacheObject(countKey, newCacheCount);} else {//缓存手机验证码1天发送次数值 默认1redisCache.setCacheObject(countKey, 1, 1, TimeUnit.DAYS);log.error("手机号:{} 注册验证码发送成功, 24小时内已发送{}次", phoneNumber, 1);}//缓存手机验证码2分钟 key+valueredisCache.setCacheObject(msgKey, msgValue, 2, TimeUnit.MINUTES);return "send success";}}
}

controller业务接口请求代码

/*** @author zxt* @date 2024-05-24 18:03* @describe*/
@RequestMapping("/model")
@RestController
@Slf4j
public class ModelController {@Resourceprivate ModelService modelService;/*** 发送手机验证码* @param phoneNumber* @return*/@GetMapping("/send/{phoneNumber}" )public AjaxResult sendVerificationCode(@NotBlank(message = "手机号码不能为空") @PathVariable  String phoneNumber) {// 可自己代码定义返回值类型,业务逻辑返回string 此处自己处理返回相对应返回类型return AjaxResult.success(modelService.sendVerificationCode(phoneNumber));}
}

接口请求测试

请求

get请求
localhost:xx/model/send/{手机号}

响应

{"msg": "24小时内已发送验证码3次,发送已限制 请于1天后重试...","code": 200,"data": null,"currentTimeStamp": 1716779182241
}

在这里插入图片描述

结尾

该功能 可用于 > 注册、登录 等各种需要发送手机验证码场景,可防盗刷验证码限流,去redis中拿取手机号对应缓存,判断验证码是否正确,去执行一系列的业务操作。

如对您有帮助,点个赞支持一下,感谢支持~

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

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

相关文章

【Leetcode 206】 反转链表——此递归相当妙啊

题目 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2&#xff1a; 输入&#xff1a;head [1,2] 输出&#xff1a;[2,1]示例 3&#xff1a; …

【机器学习300问】105、计算机视觉(CV)领域有哪些子任务?

计算机视觉作为人工智能的重要分支&#xff0c;发展至今已经在诸多领域取得显著的成果。在众多的计算机视觉任务中&#xff0c;图像分类、目标检测与定位、语义分割和实例分割是四个基本而关键的子任务&#xff0c;它们在不同的应用场景下扮演着重要角色。这四个子任务虽然各具…

深入理解JVM:内存结构、垃圾收集与性能调优

目录 JDK、JRE、JVM关系? 启动程序如何查看加载了哪些类&#xff0c;以及加载顺序? class字节码文件10个主要组成部分? JVM结构 画一下JVM内存结构图 程序计数器 Java虚拟机栈 本地方法栈 Java堆 方法区 运行时常量池? 什么时候抛出StackOverflowError? 例如&…

海医大三院使用先进血管外科微创技术成功救治危重主动脉夹层患者

近日,上海东方肝胆外科医院血管外科周建教授团队采用主动脉弓分支型一体化移植物联合体外开窗技术,成功救治复杂危重主动脉夹层患者,为上海嘉定首例,彰显了上海东方肝胆外科医院血管外科的优势与特色。 患者谢先生,72岁,两周前突发剧烈胸背部撕裂样疼痛,休息后症状未能得到缓解…

量化交易:如何在QMT中运行Python策略并在VSCode中高效调试?

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; 为何选择QMT和VSCode进行量化策略开发&#xff1f; 在量化交易的世界里&#xff0c;选择正确的工具与拥有优秀的策略同等重要。调用用Visual Studio Code&#xff08;简称VSCode&#xff09;或pycharm&#xff0c;方…

JAVA 大鱼吃小鱼小游戏

java实现大鱼吃小鱼&#xff0c;支持身份证防沉迷、账号密码、选择难度 放沉迷 登录 选择难度 游戏界面

【移除链表元素】python

目录 题目&#xff1a; 方法&#xff1a; 知识&#xff1a; 代码&#xff1a; 题目&#xff1a; 方法&#xff1a; 在头节点前增加一个虚拟头节点 知识&#xff1a; 链表中的每一个节点只包含当前值val和指向下一个next 代码&#xff1a; class Solution:def removeEle…

uniapp或微信小程序一些问题解决

1.按钮边框如何去除&#xff1f; 参考博主&#xff1a;微信小程序按钮去不掉边框_微信小程序button去掉边框-CSDN博客文章浏览阅读1k次。最近在学uni-app&#xff0c;顺便自己写个小程序。左上角放了个button&#xff0c;可边框怎么也去不掉…原来微信小程序的按钮要去掉边框要…

汽车IVI中控开发入门及进阶(二十一):DAB和FM 收音机

前言: 在过去的十年里,数字收音机对车载娱乐产生了重大影响。现在,几乎每辆新车都标配了这项技术,这也是我们60%以上的人收听收音机的方式。甚至有传言称,在不久的将来,将永久关闭调频发射机,使许多车载收音机过时。但一些相对年轻的汽车在工厂里仍然没有安装DAB,而且…

六西格玛培训:企业逆袭的秘密武器!——张驰咨询

为了提升企业的运营效率、产品质量和客户满意度&#xff0c;六西格玛培训成为了一个不可或缺的环节。以下是企业成功实施六西格玛培训的关键步骤&#xff1a; 一、清晰设定培训目标 首先&#xff0c;企业应明确六西格玛培训的具体目标&#xff0c;如提升产品质量、降低成本、…

java Web开发中采用Servlet登录验证,中文用户名始终提示“用户名密码错误”以及输出中文乱码问题

采用Servlet登录验证&#xff0c;中文乱码问题解决 在Java Web开发中&#xff0c;往往采用Servlet完成前后端直接的控制和处理&#xff0c;例如&#xff1a;用户登录验证功能。 在采用如下Servle源码t完成用户名登录验证时&#xff0c;只要用户名涉及中文&#xff0c;对于正确…

SpringBoot 之基础(一)

文章目录 SpringBoot 基础基本概念创建 SpringBoot 项目编码编写启动类写 Controller运行 / 测试properties 和 yml关闭 Spring banner日志spring-boot 默认的日志格式 解决 start.spring.io 不能访问不使用 spring boot 的 parent pom SpringBoot 基础 Spring Boot 是由 Pivo…

梳理清楚的echarts地图下钻和标点信息组件

效果图 说明 默认数据没有就是全国地图&#xff0c; $bus.off("onresize")是地图容器变化刷新地图适配的&#xff0c;可以你们自己写 getEchartsFontSize是适配字体大小的&#xff0c;getEchartsFontSize(0.12) 12 mapScatter是base64图片就是图上那个标点的底图 Ge…

2024年5月最新高德poi数据采集科普

曾几何时&#xff0c;个人注册高德开发者即可拥有每日一万次免费配额调用&#xff0c;现如今&#xff0c;个人每日只能调用100次&#xff0c;即使额外购买了配额300元/10万次&#xff0c;也会因为短时间大量采集被封号。要想稳定采集&#xff0c;恐怕只有购买商业授权5万/年&am…

kafka的安装与简单使用

下载地址&#xff1a;Apache Kafka 1. 上传并解压安装包 tar -zxvf kafka_2.13-3.6.2.tgz 修改文件名&#xff1a;mv kafka_2.13-3.6.2 kafka 2. 配置环境变量 sudo vim /etc/profile #配置kafka环境变量 export KAFKA_HOME/export/server/kafka export PATH$PATH:$KAFKA…

【Vue】v-if / v-show条件渲染指令

条件判断指令&#xff0c;用来辅助开发者按需控制 DOM 的显示与隐藏。条件渲染指令有如下两个&#xff0c;分别是&#xff1a; v-show 作用&#xff1a; 控制元素显示隐藏&#xff08;简单的显示隐藏&#xff09; 语法&#xff1a; v-show "表达式" 表达式值为 tru…

如何评价GPT-4o?

GPT-4o&#xff1a;开启全新理解与生成语言的篇章 在近年来的AI发展中&#xff0c;GPT模型赫然矗立&#xff0c;在自然语言处理任务中刷新了人们的认知&#xff0c;一路从GPT-1演进到如今的GPT-4o。 从GPT-1到GPT-4&#xff0c;我们可以看到模型的层数和参数量在持续增长&…

解密网络流量监控:优化IT运维的利器

引言&#xff1a; 在当今数字化时代&#xff0c;网络流量监控是维护网络稳定与业务连续性的关键。作为一名资深网络工程师&#xff0c;我将分享一些关于网络流量监控的重要知识&#xff0c;并探讨如何在IT运维中运用这一工具优化网络性能&#xff0c;确保业务的顺畅进行。 1. 网…

基于Patroni+etcd+流复制搭建PostgreSQL高可用——筑梦之路

Patroni方案简介 Patroni是一个基于zk、etcd、consul等的pg ha模板&#xff0c;可以使用python来创建和定制高可用性解决方案。Patroni使用分布式key-value数据库作为数据存储&#xff0c;主节点故障时进行主节点重新选举。通过PG内置的流复制&#xff0c;支持同步和异步复制。…

k210数字识别 笔记2 (串口通信)

这个模型识别的还可以&#xff0c;离近点 识别率高达0.9 资源&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1D4ubJGMptqop1x_Nf8KqfQ?pwd1234 提取码&#xff1a;1234 一&#xff1a;报错解决 报错的意思应该是模型文件错误 原程序可以在sd卡运行&#xff0c;但…