Java 发送短信验证码

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_37701381/article/details/82115965

Java 发送短信验证码给手机

发送短信验证码其实很简单,就是调用一下第三方的短信API接口,填写参数,发送请求,第三方平台会将信息发送给对方手机当中

介绍

我个人测试所使用的第三方API是“秒嘀”,理由是因为新用户注册送十元,不用自己充值,做测试十元够了,哈哈哈

官网:http://www.miaodiyun.com

注册登录之后,可以查看自己的token和sid,便于传参,另外点击左边菜单栏,有一个“配置中心”
这里写图片描述

在配置中心里点击验证码短信模版,新增一个模版,新增成功后等待审核通过就行;在右上角,有一点API文档,点击后跳转一个开发者网页,有相关的传参数说明:地址传送门

调用API发送短信

1. 创建一个Maven或者Spring Boot项目

为了演示,我直接就创建一个Maven项目,在pom文件中加入如下依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.ruxuanwo</groupId>
    <artifactId>sendmsg</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
    </properties>
    <dependencies>
        <!-- https://mvnrepository.com/artifact/commons-httpclient/commons-httpclient -->
        <dependency>
            <groupId>commons-httpclient</groupId>
            <artifactId>commons-httpclient</artifactId>
            <version>3.1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.10</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.44</version>
        </dependency>
    </dependencies>
</project>

2. 制作一个HttpClient.java

调用API就要用到http请求,本来是准备用java自带net包中的URL工具,但相比之下还是选择了common开源项目中的httpclient,比较好用,自己也封装了一下,便于扩展


import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 网络请求工具类
 *
 * @Author: 如漩涡
 * @Date: 2018/8/15/0015 17:03
 */

public class HttpClientUtil {
    private static final String GET = "get";
    /**
     * 默认GET请求模式,不带参数
     *
     * @param url 请求地址
     * @return
     */
    public static String method(String url) {
        return method(url, null, null);
    }

    /**
     * 默认GET请求模式,带参数
     *
     * @param url    请求地址
     * @param params 请求参数
     * @return
     */
    public static String method(String url, Map<String, String> params) {
        return method(url, params, null);
    }

    /**
     * 根据请求模式选择GET或者POST,不带参数
     *
     * @param url    请求地址
     * @param method 请求模式
     * @return
     */
    public static String method(String url, String method) {
        return method(url, null, method);
    }

    /**
     * 根据请求模式选择GET或者POST,带参数
     *
     * @param url    请求地址
     * @param params 请求参数
     * @param method 请求模式
     * @return
     */
    public static String method(String url, Map<String, String> params, String method) {
        if (method != null && !"".equals(method)) {
            if (method.equalsIgnoreCase(GET)) {
                return get(url, params);
            } else {
                return post(url, params);
            }
        } else {
            return get(url, params);
        }
    }

    /**
     * POST请求
     *
     * @param url    请求的地址
     * @param params 参数map
     * @return 请求结果
     */
    private static String post(String url, Map<String, String> params) {
        //构造HttpClient的实例
        HttpClient httpClient = new HttpClient();
        //创建POST方法的实例
        PostMethod postMethod = new PostMethod(url);
        //参数不为空添加参数
        if (params != null) {
            NameValuePair[] data = new NameValuePair[params.size()];
            System.out.println(data.length);
            int i = 0;
            for (Map.Entry<String, String> entry : params.entrySet()) {
                System.out.println(entry.getKey() + ":" + entry.getValue());
                data[i] = new NameValuePair(entry.getKey(), entry.getValue());
                i++;
            }
            postMethod.setRequestBody(data);
        }
        //使用系统提供的默认的恢复策略,设置请求重试处理,用的是默认的重试处理:请求三次
        httpClient.getParams().setBooleanParameter("http.protocol.expect-continue", false);
        String result = execute(postMethod, httpClient);
        return result;
    }

    /**
     * GET请求
     *
     * @param url    请求地址
     * @param params 参数map
     * @return String 返回的结果
     */
    private static String get(String url, Map<String, String> params) {
        //构造HttpClient实例
        HttpClient client = new HttpClient();
        //参数不为空拼接参数
        if (params != null) {
            String paramStr = "";
            for (String key : params.keySet()) {
                paramStr += "&" + key + "=" + params.get(key);
            }
            paramStr = paramStr.substring(1);
            url += "?" + paramStr;
        }
        //创建GET方法的实例
        GetMethod method = new GetMethod(url);
        String result = execute(method, client);
        return result;
    }

    /**
     * 执行请求
     * @param method 连接
     * @param client 客户端
     * @return 请求结果
     */
    private static String execute(HttpMethod method, HttpClient client){
        String result = "";
        try {
            //设置请求头信息
            method.addRequestHeader("Content-Type",
                    "application/x-www-form-urlencoded;charset=utf-8");
            //执行HTTP GET方法请求
            client.executeMethod(method);
            //返回处理结果
            result = method.getResponseBodyAsString();
        } catch (HttpException e) {
            throw new RuntimeException("请检查输入的URL![" + e.getMessage() + "]");
        } catch (IOException e) {
            throw new RuntimeException("发生网络异常![" + e.getMessage() + "]");
        } finally {
            closeConnection(method, client);
        }
        return result;
    }

    /**
     * 释放所有资源
     *
     * @param method 链接
     * @param client 客户端
     */
    private static void closeConnection(HttpMethod method, HttpClient client) {
        //释放链接
        if (method != null) {
            method.releaseConnection();
            method = null;
        }
        //关闭HttpClient实例
        if (client != null) {
            ((SimpleHttpConnectionManager) client.getHttpConnectionManager()).shutdown();
            client = null;
        }
    }

    public static void main(String[] args) {
        Map<String, String> params = new HashMap<>(16);
        params.put("page", "1");
        params.put("size", "1");
        String url = "http://127.0.0.1:8081/list";
        System.out.println(get(url, params));
    }
}

3. 编写一个发送短信的工具类

这个工具类主要作用是将发送给第三方API的参数进行一次封装,便于只要传几个重要参数以外,其余不用传

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * 短信服务
 *
 * @Author: 如漩涡
 * @Date: 2018/8/15/0015 17:04
 */
public class SendMsgUtil {

    private static final String GET = "get";
    /**
     * 发送短信消息
     *
     * @param url        请求地址
     * @param accountSid 开发者主账号ID
     * @param authToken  开发者主账号 TOKEN
     * @param content    短信内容,和模板保持一致
     * @param method     请求模式,get或者post
     * @param phones     短信接收端手机号码,可多个号码
     * @return String    请求结果
     */
    public static String sendMsg(String url, String accountSid, String authToken, String content, String method, String... phones) {
        //如果是get请求,对请求中文加上编码,防止中文乱码
        if (method.equalsIgnoreCase(GET)) {
            try {
                content = java.net.URLEncoder.encode(content, "utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        //可以多个手机号,用,号拼接起来
        String phone = "";
        for (String data : phones) {
            phone += data + ",";
        }
        phone.substring(0, phone.lastIndexOf(","));
        //秒嘀API需要的接口参数
        Map<String, String> params = new HashMap<>(16);
        params.put("accountSid", accountSid);
        params.put("smsContent", content);
        params.put("to", phone);
        params.put("sig", this.queryArguments(accountSid, authToken));
        params.put("timestamp", this.getTimestamp());
        //调用Http工具类
        return HttpClientUtil.method(url, params, method);
    }

    /**
     * 随机生成6位随机验证码
     *
     * @return 验证码
     */
    public static String getRandNum() {
        String randNum = new Random().nextInt(1000000) + "";
        //如果生成的不是6位数随机数则返回该方法继续生成
        int num = 6;
        if (randNum.length() != num) {
            return getRandNum();
        }
        return randNum;
    }

    /**
     * @return 获取时间戳
     */
    public static String getTimestamp() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        return sdf.format(new Date());
    }

    /**
     * 签名,MD5(sid + token+ timestamp),共32位(小写)
     * 注意:MD5中的内容不包含”+”号。
     *
     * @param accountSid
     * @param authToken
     * @return
     */
    public static String queryArguments(String accountSid, String authToken) {
        //时间戳
        String timestamp = getTimestamp();
        //签名认证
        String sig = getMD5(accountSid, authToken, timestamp);
        return sig;
    }

    /**
     * MD5加密
     *
     * @param args 动态参数
     * @return
     */
    public static String getMD5(String... args) {
        StringBuffer result = new StringBuffer();
        if (args == null || args.length == 0) {
            return "";
        } else {
            StringBuffer str = new StringBuffer();
            for (String string : args) {
                str.append(string);
            }
            System.out.println("加密前:\t" + str.toString());
            try {
                MessageDigest digest = MessageDigest.getInstance("MD5");
                byte[] bytes = digest.digest(str.toString().getBytes());
                for (byte b : bytes) {
                    //转化十六进制
                    String hex = Integer.toHexString(b & 0xff);
                    if (hex.length() == 1) {
                        result.append("0" + hex);
                    } else {
                        result.append(hex);
                    }
                }

            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        }
        System.out.println("加密后:\t" + result.toString());
        return result.toString();
    }

    public static void main(String[] args) {
        //短信接口URL提交地址
        String url = "https://api.miaodiyun.com/20150822/industrySMS/sendSMS";
        String sid = "你的SID";
        String token = "你的TOKEN";
        String num = SendMsgUtil.getRandNum();
        //与新增的模版内容一致
        String smsContent = "【新增模版时填写的短信签名】您的验证码为" + num + ",请于" + 2 + "分钟内正确输入,如非本人操作,请忽略此短信。";
        //群发也可以,单发也可以
        System.out.println(sendMsg(url, sid, token, smsContent, "post", "对方手机号码", "对方手机号码", "对方手机号码"));
    }

}

短信发送成功会返回一串JSON格式

{"respCode":"00000","respDesc":"请求成功。","failCount":"0","failList":[],"smsId":"5af6f76639a740b78eb602dfcc4a58b5"}

结语

短信服务的使用过程就是这么一回事了,做后台验证码校验也不难,验证码都是后台给出去的,那后台想办法做比较就可以验证了。

猜你喜欢

转载自blog.csdn.net/m0_37701381/article/details/82115965