使用Java實現短信驗證碼功能

Java實現短信驗證功能其實就是調用接口,通過URL和設置請求參數來訪問各個短信平臺達到發送短信的目的,不同平臺的API有着不同的要求,需要自己去仔細閱讀相關的文檔和接入實例。

下面介紹一下網易雲的短信發送實現(國內比較好找的平臺還挺多的比如阿里雲,秒滴雲,阿里雲有着自己造的輪子,已經非常成熟和複雜,同時也有他們自己的http協議能讓更多的編程語言快速開發,所以這裏不對阿里雲實現。秒滴雲則是專門面向企業的平臺而對於個人開發和學習則可能需要各位按照各自公司的規章制度來。市面上的短信平臺API雖然各不相同,但是其底層原理都是大同小異的而網易雲的相對比較簡單,下面就使用秒滴雲中給的Demo來請求網易雲的URL發送短信)

首先我們需要註冊並登錄網易雲,然後在控制檯找到我們需要的通信服務然後創建應用,開通短信服務並獲取短信的App_Key和創建模板並獲取模板ID

1.創建一個常量類用來存放我們剛剛獲取到的信息,把你獲取到信息的替換掉其中的星號,當然這個你也可以不用常量類存儲,看個人需求而來。

package com.wzh.util;

/**
 * @author Wzh
 * @since 2019-4-22
 * 根據項目需求把不需要的刪掉
 */
public class MessageConfig {


    /**
     * URL
     */
    public static final String BASE_URL = "https://api.netease.im/sms/sendcode.action";




    /*===============================網易雲==========================================*/

    /**
     * 網易App_Key
     */
    public static final String App_Key = "***********";

    /**
     * 網易App_Secret
     */
    public static final String App_Secret = "***********";

    /**
     * 短信驗證模板ID
     */
    public static final String TEMPLATEID="***********";

    /**
     * 驗證碼長度
     */
    public static final String CODELEN="6";


    /*===============================秒滴雲==========================================*/

    /**
     * 系統生成的帳號
     */
    public static final String ACCOUNT_SID = "***********";

    /**
     * 生成的TOKEN
     */
    public static final String AUTH_TOKEN = "***********";


    /**
     * 響應的數據格式
     */
    public static final String RESP_TYPE = "JSON";


}

2.創建Util類用來發送請求並設置請求頭的參數

package com.wzh.util;




import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Date;

/**
 * @author Wzh
 * @since 2019-4-22
 */
public class MessageUtil {



    /**
     * post請求
     *
     * @param url  請求地址
     * @param body 請求內容
     * @return
     * @throws IOException
     */
    public static String post(String url, String body) throws IOException {
        System.out.println("url:" + System.lineSeparator() + url);
        System.out.println("body:" + System.lineSeparator() + body);
        String result = "";
        String curTime = String.valueOf((new Date()).getTime() / 1000L);
        // 這個不是驗證碼,應該是用於請求頭的簽名和加密,隨機驗證碼是網易雲生成的
        String NONCE = IndustrySMS.smsCode();
        String checkSum = CheckSumBuilder.getCheckSum(MessageConfig.App_Secret, NONCE, curTime);
        // 建立連接
        try {
            OutputStreamWriter out = null;
            BufferedReader in = null;
            URL realUrl = new URL(url);
            URLConnection conn = realUrl.openConnection();

            // 設置連接參數
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(20000);
            // 設置請求頭
            conn.setRequestProperty("AppKey", MessageConfig.App_Key);
            conn.setRequestProperty("Nonce", NONCE);
            conn.setRequestProperty("CurTime", curTime);
            conn.setRequestProperty("CheckSum", checkSum);
            conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
            // 提交數據
            out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");
            out.write(body);
            out.flush();

            // 讀取返回數據
            in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
            String line = "";
            // 讀第一行不加換行符
            boolean firstLine = true;
            while ((line = in.readLine()) != null) {
                if (firstLine) {
                    firstLine = false;
                } else {
                    result += System.lineSeparator();
                }
                result += line;
            }


        } catch (MalformedURLException e) {
            e.printStackTrace();
        }

        return result;
    }
}

到這裏和秒滴雲有些不同的地方就在於一個checkSum(應該是用來加密或簽名的)的生成和一些請求頭的設置(這些請求頭設置是根據所用平臺的API來設置的),CheckSumBuilder類是網易雲官方給我們提供的類可以在他們的API中找到,我會把代碼放到後面。

 

3.創建實現類來發送短信

package com.wzh.util;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;


/**
 * 驗證碼短信通知接口
 * @author Wzh
 * @since 2019-4-22
 */
public class IndustrySMS {

    // 要發送的手機號
    private static String mobile = "13*******66";


    /**
     * 驗證碼通知短信
     */
    public static void execute() throws IOException {
        String tmpSmsContent = null;

        try {
            // URLEncode.encode();是將你要傳遞的參數在post請求以流的方式發送,這裏我們需要的參數是模板ID,手機號,驗證碼長度
            tmpSmsContent = "templateid=" + URLEncoder.encode(MessageConfig.TEMPLATEID,"UTF-8");
            tmpSmsContent += "&mobile=" + URLEncoder.encode(mobile,"UTF-8");
            tmpSmsContent += "&codeLen=" + URLEncoder.encode(MessageConfig.CODELEN,"UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        // 各個平臺的接口URL
        String url = MessageConfig.BASE_URL;
        String body =tmpSmsContent;

        String result = MessageUtil.post(url,body);
        // 返回結果是一個json數據{"code":200,"msg":"7","obj":"xxx"},我們要用處理json數據的包來將他轉換成集合,obj就是我們需要來匹配的驗證碼
        System.out.println("result:" + System.lineSeparator() + result);
    }



    // 創建隨機數
    public static String smsCode(){
        String random=(int)((Math.random()*9+1)*100000)+"";
        return random;
    }



}

 

mobile:要發送的手機號碼,可從將它放到參數中,由用戶填寫來獲取。

URLEncoder.encode() 方法將我們要傳遞的參數以二進制流的形式在post請求中傳輸,參數之間用&分隔。

獲取到的result是一個json格式的數據可以用處理json數據的工具類來將它轉換成集合,數據中obj的值就是我們需要匹配的驗證碼(視各個平臺而定)

4.CheckSumBuilder類

package com.wzh.util;

import java.security.MessageDigest;

/**
 * @author anyone
 */
public class CheckSumBuilder {
    // 計算並獲取CheckSum
    public static String getCheckSum(String appSecret, String nonce, String curTime) {
        return encode("sha1", appSecret + nonce + curTime);
    }

    // 計算並獲取md5值
    public static String getMD5(String requestBody) {
        return encode("md5", requestBody);
    }

    private static String encode(String algorithm, String value) {
        if (value == null) {
            return null;
        }
        try {
            MessageDigest messageDigest
                    = MessageDigest.getInstance(algorithm);
            messageDigest.update(value.getBytes());
            return getFormattedText(messageDigest.digest());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    private static String getFormattedText(byte[] bytes) {
        int len = bytes.length;
        StringBuilder buf = new StringBuilder(len * 2);
        for (int j = 0; j < len; j++) {
            buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
            buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
        }
        return buf.toString();
    }
    private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5',
            '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
}

5.測試類

根據個人項目需求編寫

package com.wzh.entity;

import com.wzh.util.IndustrySMS;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.IOException;

@RunWith(SpringRunner.class)
@SpringBootTest
public class HgerApplicationTests {

	@Test
	public void testSms() {
		try {
			IndustrySMS.execute();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

6.總結

Java實現短信驗證功能簡單來說就是調用外部短信平臺接口來開發,我們只要嚴格的遵守所調用平臺所定的規範,那麼這個功能是非常容易實現的,所以說多去仔細看看官方文檔是肯定沒錯的。其實在上述網易雲的接口調用實例中,網易雲官方有着更簡單的示例,之所以用這麼複雜的方式來實現是爲了我們更好的理解其中通信的原理,各個平臺之間底層的原理都是一致的,只要我們理解了那麼今後當我們需要去學習另外的規範時也能快速掌握。下面將官方的接入示例也展示出來

package com.netease.code;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import com.netease.checksum.CheckSumBuilder;
/**
 * 發送驗證碼
 * @author liuxuanlin
 *
 */
public class SendCode {
    //發送驗證碼的請求路徑URL
    private static final String
            SERVER_URL="https://api.netease.im/sms/sendcode.action";
    //網易雲信分配的賬號,請替換你在管理後臺應用下申請的Appkey
    private static final String 
            APP_KEY="fd460d34e786e7754e505bc4fab0f027";
    //網易雲信分配的密鑰,請替換你在管理後臺應用下申請的appSecret
    private static final String APP_SECRET="dffdf7757248";
    //隨機數
    private static final String NONCE="123456";
    //短信模板ID
    private static final String TEMPLATEID="3057527";
    //手機號
    private static final String MOBILE="13888888888";
    //驗證碼長度,範圍4~10,默認爲4
    private static final String CODELEN="6";
    
    public static void main(String[] args) throws Exception {
        
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(SERVER_URL);
        String curTime = String.valueOf((new Date()).getTime() / 1000L);
        /*
         * 參考計算CheckSum的java代碼,在上述文檔的參數列表中,有CheckSum的計算文檔示例
         */
        String checkSum = CheckSumBuilder.getCheckSum(APP_SECRET, NONCE, curTime);

        // 設置請求的header
        httpPost.addHeader("AppKey", APP_KEY);
        httpPost.addHeader("Nonce", NONCE);
        httpPost.addHeader("CurTime", curTime);
        httpPost.addHeader("CheckSum", checkSum);
        httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");

        // 設置請求的的參數,requestBody參數
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        /*
         * 1.如果是模板短信,請注意參數mobile是有s的,詳細參數配置請參考“發送模板短信文檔”
         * 2.參數格式是jsonArray的格式,例如 "['13888888888','13666666666']"
         * 3.params是根據你模板裏面有幾個參數,那裏面的參數也是jsonArray格式
         */
        nvps.add(new BasicNameValuePair("templateid", TEMPLATEID));
        nvps.add(new BasicNameValuePair("mobile", MOBILE));
        nvps.add(new BasicNameValuePair("codeLen", CODELEN));
        
        httpPost.setEntity(new UrlEncodedFormEntity(nvps, "utf-8"));

        // 執行請求
        HttpResponse response = httpClient.execute(httpPost);
        /*
         * 1.打印執行結果,打印結果一般會200、315、403、404、413、414、500
         * 2.具體的code有問題的可以參考官網的Code狀態表
         */
        System.out.println(EntityUtils.toString(response.getEntity(), "utf-8"));

    }
}

需要導入jar包httpcore-4.4.3.jarhttpclient-4.5.1.jar

如果需要了解的更詳細的可以去官方文檔中查閱

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章