小记

Java实现短信验证码–设置发送间隔时间,以及有效时间(Java+Redis)
这篇文章,实现了Java发送手机短信验证码发送的间隔时间,以及手机验证码的有效时间和手机验证码格式的合法性验证,可以防止恶意刷接口

关于Java项目怎么连接redis,请看这一篇文章 https://www.cnblogs.com/nanstar/p/13367747.html

代码部分

  • 001
  • 002
  • 003
  • 004
  • 005
  • 006
  • 007
  • 008
  • 009
  • 010
  • 011
  • 012
  • 013
  • 014
  • 015
  • 016
  • 017
  • 018
  • 019
  • 020
  • 021
  • 022
  • 023
  • 024
  • 025
  • 026
  • 027
  • 028
  • 029
  • 030
  • 031
  • 032
  • 033
  • 034
  • 035
  • 036
  • 037
  • 038
  • 039
  • 040
  • 041
  • 042
  • 043
  • 044
  • 045
  • 046
  • 047
  • 048
  • 049
  • 050
  • 051
  • 052
  • 053
  • 054
  • 055
  • 056
  • 057
  • 058
  • 059
  • 060
  • 061
  • 062
  • 063
  • 064
  • 065
  • 066
  • 067
  • 068
  • 069
  • 070
  • 071
  • 072
  • 073
  • 074
  • 075
  • 076
  • 077
  • 078
  • 079
  • 080
  • 081
  • 082
  • 083
  • 084
  • 085
  • 086
  • 087
  • 088
  • 089
  • 090
  • 091
  • 092
  • 093
  • 094
  • 095
  • 096
  • 097
  • 098
  • 099
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
package com.zxjs.controller.app; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; import org.apache.commons.lang.RandomStringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import redis.clients.jedis.Jedis; import java.util.HashSet; import java.util.Set; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * 发送短信验证码 */ @Api(value="发送短信验证码",description = "发送短信验证码,默认发送短信的间隔是一分钟",tags = {"发送短信验证码"}) @RestController @RequestMapping("appISendSms") public class SendSMS { private final static Logger logger = LoggerFactory.getLogger(SendSMS.class); /** * 链接redis数据库,使用验证码的时候,只需要在其他的地方用redis查询这个手机号的验证码就可以了 */ static Jedis jedis = new Jedis("localhost"); /** * 生成随机的六位验证码 */ static String sale = ""; /** * @param args */ public static void main(String[] args) throws InterruptedException{ //手机号测试部分 sendSmsInfo("13683654784"); } /** * 发送验证消息 * 传入手机号,接收到的是用户的手机号码 * @return */ @ApiOperation(value="发送验证消息",notes = "发送验证消息,默认同一个手机号码发送短信间隔是一分钟,加入手机号码格式验证,可使用时长是五分钟,可以有效防止恶意刷接口") @ApiImplicitParam(paramType = "query",name="phone",value = "0",required = true) @GetMapping("getReCode") @ResponseBody public static String sendSmsInfo(String phone){ //进入发送逻辑的时候生成随机验证码,六位数字 sale = RandomStringUtils.randomNumeric(6); //思路,每个手机号进来的时候,放到redis里面一个值,(手机号,验证码+开始时间) // 当这个用户再次来查询的时候,查看时间是否到达一分钟,到达的话可以发送验证码 try { //验证码有效时间,放到redis缓存里面(手机号,验证码+开始时间),根据开始时间来判断,达到了时间删掉缓存里面的手机号 String regex = "^((13[0-9])|(14[5,7,9])|(15([0-3]|[5-9]))|(17[0,1,3,5,6,7,8])|(18[0-9])|(19[8|9])|(16[6]))\\d{8}$"; Pattern p = Pattern.compile(regex); Matcher m = p.matcher(phone); boolean isMatch = m.matches(); if (! isMatch) { return "手机号码格式不正确,请核对后重新输入!"; } else { /*检测redis是否开启,未开启的话,返回信息*/ if(jedis.ping() == "PONG"){ return "Redis Is Not Run!"; } //当前时间秒数 Long timemili = System.currentTimeMillis() / 1000; // System.out.println("当前的秒数" + timemili); // System.out.println(jedis.dbSize()); // System.out.println(jedis.keys("*")); /*在这里写一个定时的for循环,用来取redis的手机号码信息,然后查询手机号码开始的时间,若是大于等于五分钟 * 就给删除这个键值*/ //创建多线程定时任务,延迟1s启动,每隔1s执行一次,是前一个任务开始时就开始计算时间间隔,但是会等上一个任务结束在开始下一个 ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10); scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { /*执行程序的位置*/ //首先取出所有的手机号 键信息,放到新的集合里 Set setPhone = new HashSet(); setPhone = jedis.keys("*"); for (Object setInfo : setPhone) { //判断这个键的值是不是超过五分钟,是的话就删除掉这个键 System.out.println("计算结果"+ (System.currentTimeMillis() / 1000 - Long.parseLong(jedis.get(setInfo.toString()).substring(6))) ); if(System.currentTimeMillis() / 1000 - Long.parseLong(jedis.get(setInfo.toString()).substring(6)) > 300){ jedis.del(setInfo.toString()); } // System.out.println(setInfo); } } }, 1, 2, TimeUnit.SECONDS); /** * 设置键值的时候先查询是否存在这个键值对,存在的话查看时长,不存在的话直接发送短信 */ boolean str = jedis.exists(phone); if (! str) { //发送短息 String recode = SmsInfo(phone); jedis.set(phone, (sale + timemili)); return recode; } else { String strT = jedis.get(phone); //查看请求间隔,默认是一分钟,小于一分钟继续等待,超过一分钟发送短信 if (timemili - Long.parseLong(strT.substring(6)) < 60) { // System.out.println("请一分钟后再次重试" + new Date()); return "请等待一分钟后再次重试!"; } else { //发送短息 String recode = SmsInfo(phone); jedis.set(phone, (sale + timemili)); return recode; } } } }catch(Exception e){ logger.error(e.getMessage()); } return "false"; } /** * 发送短息 * @return */ public static String SmsInfo(String phone){ 这里设置短信验证码的接口和账户密码部分(自己购买的接口在这里) String url ="http://www.ztsms.cn/sendNSms.do"; String username ="";//内容 String password ="";//密码 String mobile = phone; //号码 String content ="您本次操作的的验证码是:"+sale+",验证码五分钟内有效,请不要把验证码发送给别人!";//内容 String productid =""; //产品id String xh ="";//设置为空 String tkey = TimeUtil.getNowTime("yyyyMMddHHmmss"); try{ content= URLEncoder.encode(content,"utf-8"); }catch (UnsupportedEncodingException e) { e.printStackTrace(); } String param="gateway="+url+"&username="+username+"&password="+ MD5Gen.getMD5(MD5Gen.getMD5(password)+tkey)+"&tkey="+tkey+"&mobile="+mobile+"&content="+content+"&productid="+productid+"&xh"+xh; // String ret= HttpRequest.sendGet(url, param);//sendPost or sendGet 即get和post方式 System.out.println("ret:"+ret+param); return sale; } }

工具类

phoneUtils https://files.cnblogs.com/files/nanstar/phoneUtils.zip