1. 程式人生 > 實用技巧 >Java實現簡訊驗證碼--設定傳送間隔時間,以及有效時間(Java+Redis)

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