Java实现短信验证码--设置发送间隔时间,以及有效时间(Java+Redis)

Posted 孤水寒月

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java实现短信验证码--设置发送间隔时间,以及有效时间(Java+Redis)相关的知识,希望对你有一定的参考价值。

Java实现短信验证码--设置发送间隔时间,以及有效时间(Java+Redis)

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

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

代码部分

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

以上是关于Java实现短信验证码--设置发送间隔时间,以及有效时间(Java+Redis)的主要内容,如果未能解决你的问题,请参考以下文章

防止恶意攻击短信验证码接口方法

php实现的IMEI限制的短信验证码发送类

验证码---短信验证码

如何解决短信验证码接口被攻击的问题?

这是一个简单的前台短信验证码功能 ajax实现异步处理 (发送和校验)

腾讯云短信服务实现 Java 发送手机验证码(SpringBoot+Redis 实现)