• 通过redis在控制台模拟手机验证码功能(java)


    一、题目要求:

    手机验证码功能
    需求:
    1、输入手机号,点击发送后随机生成6位数字码,2分钟内有效。
    2、输入验证码:点击验证,返回成功或者失败。
    3、每个手机号每天只能获取3次验证码。

    二、代码和分析(分析和数据存储结构的设计在代码注释中):

    1. import redis.clients.jedis.Jedis;
    2. import java.util.Scanner;
    3. import java.util.regex.Pattern;
    4. /**
    5. * @author:tengsen
    6. * @create: 2022-10-03 06:21
    7. * @Description: 模拟手机验证码
    8. * 手机验证码功能
    9. * 要求:
    10. * 1、输入手机号,点击发送后随机生成6位数字码,2分钟内有效
    11. * 2、输入验证码:点击验证,返回成功或者失败
    12. * 3、每个手机号每天只能获取3次验证码
    13. *
    14. * 数据结构设计:
    15. * (1)普通键值对set: key:"phone"+具体电话号码+"p", value: 当天该号码已经发送的次数, 过期时间为1天(24*60*60)
    16. * (2)普通键值对set: key:"code"+具体电话号码+"c", value: 具体验证码, 过期时间为2min(2*60)
    17. * (3) hash: key "hash"+具体电话号码+"h", field: 具体验证码, value:已经请求验证的次数(最多尝试验证3次)
    18. * (4) 注意: 验证成功、发送新的验证码或验码已经过期时,都要时要根据key来删除(2)和(3)
    19. *
    20. **/
    21. public class verifyCode {
    22. public static void main(String[] args) {
    23. //连接redis
    24. Jedis jedis = new Jedis("127.0.0.1",6380);
    25. // 注意!注意!注意!
    26. // 此处为密码登录,若无密码可注释掉
    27. // 注释还是不注释或者具体密码是多少可根据实际情况调整
    28. // 我这里使用的密码是123
    29. jedis.auth("123");
    30. //测试redis是否连接成功
    31. String ping = jedis.ping();
    32. System.out.println(ping);
    33. //输入手机号
    34. Scanner scanner = new Scanner(System.in);
    35. System.out.print("请输入手机号:");
    36. String phone;
    37. while (true){
    38. phone = scanner.nextLine();
    39. if(isValidPhone(phone)){
    40. break;
    41. }
    42. System.out.println("手机号格式输入错误,正确的格式要求为:");
    43. System.out.println("第一位数字是1,第二位数字只能是3或4或5或6或7或8或9,剩下的九位数字可以是0-9之间任意一位数字,共11位");
    44. System.out.print("请重新输入手机号:");
    45. }
    46. boolean login = false;
    47. boolean exit = false;
    48. //token作为用户想不想获取验证码的一个标志符
    49. String token = "";
    50. System.out.print("是否获取验证码:(y/n):");
    51. while (true){
    52. token = scanner.nextLine();
    53. if (isValidToken(token)){
    54. break;
    55. }
    56. System.out.print("输入非法,请重新输入是否获取验证码(y/n):");
    57. }
    58. if(token.equals("y")){
    59. //发送验证码
    60. boolean flag = sendVerifyCode(phone,jedis);
    61. if(flag){
    62. String codeKey = "code"+phone+"c";
    63. String realCode = jedis.get(codeKey);
    64. System.out.println("!提示:收到的验证码为:"+realCode);
    65. }
    66. System.out.print("登录校验请输入(v),重新发送验证码请输入(r),退出登录请输入(e):");
    67. while (true){
    68. String select = scanner.nextLine();
    69. System.out.println();
    70. if(select.equals("v")){
    71. //校验验证码
    72. System.out.print("请输入验证码:");
    73. while (true){
    74. String code = scanner.nextLine();
    75. Integer i = verifyCode(phone,code,jedis);
    76. if(i.equals(1)){
    77. login = true;
    78. break;
    79. }else if(i.equals(0)){
    80. //验证失败已达3次或者验证码过期
    81. break;
    82. }
    83. System.out.print("重新输入验证码请输入(continue),任意输入终止本轮验证:");
    84. String select2 = scanner.nextLine();
    85. if(!select2.equals("continue")){
    86. System.out.println("本轮验证终止");
    87. break;
    88. }
    89. System.out.print("请重新输入验证码:");
    90. }
    91. }else if(select.equals("r")){
    92. //重新发送验证码
    93. boolean flag2 = sendVerifyCode(phone,jedis);
    94. String codeKey = "code"+phone+"c";
    95. String realCode = jedis.get(codeKey);
    96. if (flag2){
    97. System.out.println("!提示:收到的验证码为:"+realCode);
    98. }else{
    99. System.out.println("!提示:已存在的验证码为:"+realCode);
    100. }
    101. }else if(select.equals("e")){
    102. //退出登录
    103. exit = true;
    104. }else {
    105. System.out.println("输入非法,只能输入v或r或e,请重新输入您的选择");
    106. }
    107. if (exit){
    108. System.out.println("成功退出");
    109. break;
    110. }
    111. if (login){
    112. break;
    113. }
    114. System.out.println();
    115. System.out.print("登录校验请输入(v),重新发送验证码请输入(r),退出请输入(e):");
    116. }
    117. if (login){
    118. System.out.println("登录成功");
    119. }else {
    120. System.out.println("登录失败");
    121. }
    122. }else {
    123. System.out.println("您选择了n,已经退出程序,如需再次使用手机验证码功能,请重新启动程序");
    124. }
    125. }
    126. //校验手机号格式的函数
    127. public static boolean isValidPhone(String phone){
    128. if((phone!=null)&&(!phone.isEmpty())){
    129. return Pattern.matches("^1[3-9]\\d{9}$",phone);
    130. }
    131. return false;
    132. }
    133. //校验token(y/n)输入是否合法的函数
    134. public static boolean isValidToken(String token){
    135. if((token!=null)&&(!token.isEmpty())){
    136. return token.equals("y")||token.equals("n");
    137. }
    138. return false;
    139. }
    140. //发送验证码
    141. public static boolean sendVerifyCode(String phone,Jedis jedis){
    142. String phoneKey = "phone"+phone+"p";
    143. String codeKey = "code"+phone+"c";
    144. String hashKey = "hash"+phone+"h";
    145. String phoneValue = jedis.get(phoneKey);
    146. if(phoneValue == null){
    147. jedis.setex(phoneKey,24*60*60,"1");
    148. }else {
    149. //规定发出一个验证码60秒后,才能发送新的验证码,原定一个一个验证码存活120秒,所以ttl要减60
    150. Long ttl = jedis.ttl(codeKey);
    151. ttl-=60;
    152. if(ttl>=0){
    153. System.out.println("验证码已存在,"+(ttl)+"秒后可重新尝试");
    154. return false;
    155. }else{
    156. if(Integer.parseInt(phoneValue)<3){
    157. jedis.incr(phoneKey);
    158. }else {
    159. System.out.println("今天该手机号验证码发送次数已经超过3次,今天已经不能再发送验证码");
    160. return false;
    161. }
    162. }
    163. }
    164. //生成验证码
    165. String code = generateCode();
    166. jedis.setex(codeKey,2*60,code);
    167. jedis.hset(hashKey,code,"0");
    168. System.out.println("验证码发送成功");
    169. return true;
    170. }
    171. //校验验证码
    172. public static Integer verifyCode(String phone,String code,Jedis jedis){
    173. String codeKey = "code"+phone+"c";
    174. String hashKey = "hash"+phone+"h";
    175. //判断此时的验证码是否已经过期
    176. Integer ttl = Math.toIntExact(jedis.ttl(codeKey));
    177. if(ttl.equals(-2)){
    178. System.out.println("验证码已经过期,请重新发送新的验证码");
    179. //根据codeKey删除code,根据hashKey删除该code已经验证的次数
    180. deleteCode(codeKey,hashKey,jedis);
    181. return 0;
    182. }
    183. String codeValue = jedis.get(codeKey);
    184. String hashValue = jedis.hget(hashKey,codeValue);
    185. int times = Integer.parseInt(hashValue);
    186. if(times<3){
    187. if(code.equals(codeValue)){
    188. System.out.println("验证成功");
    189. //根据codeKey删除code,根据hashKey删除该code已经验证的次数
    190. deleteCode(codeKey,hashKey,jedis);
    191. return 1;
    192. }else{
    193. Long aLong = jedis.hincrBy(hashKey, codeValue, 1);
    194. System.out.println("验证码错误,请重新输入,你还可以尝试"+(3-aLong)+"次");
    195. return 2;
    196. }
    197. }else {
    198. System.out.println("你已经验证过三次,达到上限,请重新发送验证码");
    199. //根据codeKey删除code,根据hashKey删除该code已经验证的次数
    200. deleteCode(codeKey,hashKey,jedis);
    201. return 0;
    202. }
    203. }
    204. //生成6位随机验证码的函数
    205. public static String generateCode(){
    206. String code = "";
    207. for (int i = 0; i < 6; i++) {
    208. code += (int)(Math.random()*10);
    209. }
    210. return code;
    211. }
    212. //根据codeKey删除code,根据hashKey删除该code已经验证的次数
    213. public static void deleteCode(String codeKey,String hashCode,Jedis jedis){
    214. jedis.del(codeKey);
    215. jedis.del(hashCode);
    216. }
    217. }

     

     三、运行测试结果:

    1、验证成功的案例:

     2、手机号格式输入错误的案例:

     3、输错手机验证码的案例:

     4、欲重复获取验证码的失败案例,冷却事件1分钟:

     

     5、一天内获取验证码次数超过三次,当天受限:

     

     6、非法输入案例:

     

    四、跑验证码代码开发前的准备:

    1、对redis进行配置:

    下载redis压缩包并解压,将redis要使用的端口配置好(我这里使用的端口是6380),并配置好登录需要redis对应密码(即配置requirepass属性,我这里配置的密码是123)。

    (1) 编辑redis的配置文件,后缀为.conf

     (2)使用ctrl+F快捷键查找port,需要设置为自己想要redis占用的端口:

     (3)查找requirepass,将登录该redis的密码设置好:

     

     

    2、启动redis:

    我这里使用的是下面的指令(redis服务端启动命令+要使用的配置文件):

    redis-server.exe redis.windows-6380.conf

     

     3、在java项目中导入需要用到的redis对应jar包:

    (1)相关工具百度网盘分享:

    这个jar包相当于辅助组件,因为java本身是没有redis的,所以需要引入该工具。

     链接:https://pan.baidu.com/s/1FBwvbRv3ickkrB58VNklWA?pwd=9999 
    提取码:9999 
    --来自百度网盘超级会员V5的分享

     对于以上两个工具,也可以去redis官网下载其他版本。

    (2)下载好jedis-2.9.0.jar后,需要将该jar包引入项目中,这里以idea为实操工具

    1>在项目src目录下新建lib文件夹。

    2>在文件(File)中找到项目结构(Project Structure...),点击打开:

     3>在项目结构中找到库(Libraries),点击+号:

     4>继续点击:

     5>找到lib文件夹,选中后点击确定:

     6>然后选中Jar Directory,点击确定:

    7>继续选择确定:

     8>继续选择确定:

     9>将该jar包复制进lib文件夹中:

    10>查看目录,效果如红圈内所示:

     

     到这一步,java项目的redis文件导入已经完成。

  • 相关阅读:
    共生与共享:线程与进程的关系
    python学习——python的内建函数总结
    洗地机还能这样玩?添可芙万空间站,创新永无止境
    网络安全防御体系建设-防守实例
    vim的Dirvish中文文档
    MR混合现实情景实训教学系统在商务外语课堂的应用
    JUC(4):Java “锁“事一览
    轻量封装WebGPU渲染系统示例<18>- 材质多pass实现GPU Compute计算(源码)
    R语言使用dplyr包的transmute函数计算dataframe数据中的指定数据列的移动窗口均值
    MySQL学习笔记
  • 原文地址:https://blog.csdn.net/zhan_qian/article/details/127338118