Java 发送短信验证码给手机
发送短信验证码其实很简单,就是调用一下第三方的短信API接口,填写参数,发送请求,第三方平台会将信息发送给对方手机当中
介绍
我个人测试所使用的第三方API是“秒嘀”,理由是因为新用户注册送十元,不用自己充值,做测试十元够了,哈哈哈
注册登录之后,可以查看自己的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"}
结语
短信服务的使用过程就是这么一回事了,做后台验证码校验也不难,验证码都是后台给出去的,那后台想办法做比较就可以验证了。