Last week in the recruitment fair of the school, when introducing my own project, I was asked by the interviewer how to realize your mobile phone number for registration function? When I answered: “This verification phone number does not seem to have any use, just in front of the re verification and change the password match”. Then the interviewer smiled: “That you this seems to have no use, and can not dynamically obtain verification code?” . After the interview, my roommate, who had been standing next to me, said, I thought I saw the interviewer’s contemptuous eyes. This wave, I admit THAT I was careless ah, at that time I just wanted to quickly realize the course design of Ah CAI, forget the realization of these details. In fact, this method is very simple to find the right SMS service interface.

The preparatory work

Open Tencent cloud market, use wechat scan code after logging in to search these keywords: [106 three networks SMS API] Guoyang

After entering the page, you can see that you can choose the frequency and price of SMS. We choose the free one in the product specifications (you can send SMS for 5 times, so be careful to debug.)Click “Purchase” and go to “Purchase Management” in the buyer’s center in the upper right corner to view the product just now. We need to click “Management” to obtain the ID and key of the product:

Write an implementation class that requests its service provider interface

After knowing the Id and key of our product, we went back to the purchase page, and there was an Api document at the bottom of the page. We could see that the main method was used in the original Api document, and then passed into itmobile.param.smsSignId.templateIdNote that the smsSignId, templateId, and smsSignId are both ‘123456’ and ‘123456’ by default, if you do not request the smsSignId and templateId as the captcha template. //(^v^)\~~~)

But this is the static main method, which obviously doesn’t meet the flexible requirements of our common front-end separated projects, so we need to rewrite this method a bit.

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import sun.misc.BASE64Encoder;
/** * Create by KANG TAIMING * Time: 10:16 * implement verification code to send * adhere to the victory, come on Olly to */
public class SmsCode {
    public static String calcAuthorization(String source, String secretId, String secretKey, String datetime)
            throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException {
        String signStr = "x-date: " + datetime + "\n" + "x-source: " + source;
        Mac mac = Mac.getInstance("HmacSHA1");
        Key sKey = new SecretKeySpec(secretKey.getBytes("UTF-8"), mac.getAlgorithm());
        mac.init(sKey);
        byte[] hash = mac.doFinal(signStr.getBytes("UTF-8"));
        String sig = new BASE64Encoder().encode(hash);

        String auth = "hmac id=\"" + secretId + "\", algorithm=\"hmac-sha1\", headers=\"x-date x-source\", signature=\"" + sig + "\" ";
        return auth;
    }

    public static String urlencode(Map
        map) throws UnsupportedEncodingException {
        StringBuilder sb = new StringBuilder();
        for(Map.Entry<? ,? > entry : map.entrySet()) {if (sb.length() > 0) {
                sb.append("&");
            }
            sb.append(String.format("%s=%s",
                    URLEncoder.encode(entry.getKey().toString(), "UTF-8"),
                    URLEncoder.encode(entry.getValue().toString(), "UTF-8"))); }return sb.toString();
    }
    // Build the parameter method, passing in the phone number and parameters
    public static String getSms(String mobile,String param)throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException{
        // The key Id that can be viewed in the purchased product after purchase is not the Id in the Api document
        String secretId = "xxxx";
        // The Key that can be viewed in the purchased product after purchase is not the Id in the Api document
        String secretKey = "xxx";
        String source = "market";

        String result = "";
        Calendar cd = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
        sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
        String datetime = sdf.format(cd.getTime());
        / / signature
        String auth = calcAuthorization(source, secretId, secretKey, datetime);
        // Request method
        String method = "GET";
        / / request header
        Map<String, String> headers = new HashMap<String, String>();
        headers.put("X-Source", source);
        headers.put("X-Date", datetime);
        headers.put("Authorization", auth);

        // Query parameters
        Map<String, String> queryParams = new HashMap<String, String>();
        queryParams.put("mobile", mobile);
        queryParams.put("param", param);
        queryParams.put("smsSignId"."xxx");// Signature ID, contact customer service personnel to apply for the successful signature ID, test sending function can use the default API document ID
        queryParams.put("templateId"."xxx");// Template ID, contact the customer service personnel to apply for the template ID successfully, and test the sending function can use the default ID of the API document
        / / body parameters
        Map<String, String> bodyParams = new HashMap<String, String>();

        // Url parameter concatenation
        String url = "https://service-m6t5cido-1256923570.gz.apigw.tencentcs.com/release/sms/send";
        if(! queryParams.isEmpty()) { url +="?" + urlencode(queryParams);
        }

        BufferedReader in = null;
        try {
            URL realUrl = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(5000);
            conn.setRequestMethod(method);

            // request headers
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                conn.setRequestProperty(entry.getKey(), entry.getValue());
            }

            // request body
            Map<String, Boolean> methods = new HashMap<>();
            methods.put("POST".true);
            methods.put("PUT".true);
            methods.put("PATCH".true);
            Boolean hasBody = methods.get(method);
            if(hasBody ! =null) {
                conn.setRequestProperty("Content-Type"."application/x-www-form-urlencoded");

                conn.setDoOutput(true);
                DataOutputStream out = new DataOutputStream(conn.getOutputStream());
                out.writeBytes(urlencode(bodyParams));
                out.flush();
                out.close();
            }

            // Define the BufferedReader input stream to read the response to the URL
            in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line;

            while((line = in.readLine()) ! =null) { result += line; }}catch (Exception e) {
            System.out.println(e);
            e.printStackTrace();
        } finally {
            try {
                if(in ! =null) { in.close(); }}catch(Exception e2) { e2.printStackTrace(); }}return result;
    }
Copy the code

Compared to the original Api documentation, we will be static main static method with the result return to getSms () method, and in getSms approach, because smsSignId and templatedId belongs to message template, can need not change, so was written in a fixed parameter, All we need to do is transmit the phone number and self-generated verification code to its interface.

Write Controller to implement its interface calls

We need to know when writing the Controller layerresultWhat is returned in order to return the correct information in the Controller to the front page, again see the return example below its documentation:It can be seen from the document that result returns two JSON formats, MSG and code respectively, and the successful return is character “0”. Therefore, we only need to judge the code according to the document return code in the Controller.

@RestController
public class SmsController {

    @RequestMapping("/getSmsCode")
    // There must be exception handling or throwing
    public R sendCode(@RequestParam("phone") String phone) throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException {
        Integer smscode=((int)((Math.random()*9+1) *100000));// Generate a random 6-digit verification code
        String result = SmsCode.getSms(phone,"**code**:"+smscode);// The **code** here means that you must contact the customer to modify the template to implement the custom captcha
        JSONObject json = JSONObject.fromObject(result);
       //"0" indicates that the SMS message is successfully sent
       if (json.get("code").equals("0")) {return R.ok().setMessage("Verification code sent successfully");
        }else return R.error().setMessage("Unknown error in captcha");// There are too many error codes.}}Copy the code

Controller R class source:

  public class R<D> {
    // Return the status code
    public static int CODE_SUCCESS = 200;
    public static int CODE_ERROR = 500;



    private int code;
    private String message;
    private D data;

    public int getCode(a) {
        return code;
    }

    public R setCode(int code) {
        this.code = code;
        return this;
    }

    public String getMessage(a) {
        return message;
    }

    public R setMessage(String message) {
        this.message = message;
        return this;
    }

    public D getData(a) {
        return data;
    }

    public R setData(D data) {
        this.data = data;
        return this;
    }

    public static R ok(a){

        return new R().setCode(CODE_SUCCESS);
    }

    public static R error(a){
        return newR().setCode(CODE_ERROR); }}Copy the code

The test results

Use Postman to request its interface to see the test effect:About three seconds later, the phone can be seen receiving a text message with the captcha code:

conclusion

In fact, the whole process is not complicated, by obtaining the Key and Id, and implementing the result in the Controller, call the interface, but it needs to be noted that smsSignId and templateId must use the Id they gave after contacting the customer to change the template, otherwise the default verification code is 123456. Next, I will consider saving the verification code in Redis to realize session sharing. I am also very grateful to my roommate Luo for helping me complete this function by taking advantage of such a good opportunity as the practical training class to give me some time.