利用阿里云平台的短信服务进行二次接口开发,可应用场景,登陆验证码等。本文以完成一次短信验证登陆为主线。新手上路,多多指教。
发送短信的service,此段基本和阿里云的demo一致,也可以参考官方的开发文档demo
(http://download.csdn.net/download/qq_33265993/9966476 ali提供的官方sdk及demo)也可以去ali官网下载
本文代码资源
(http://download.csdn.net/download/qq_33265993/9975930)
public class MessageSendServiceImp implements MessageSendService{
public SendSmsResponse sendSms(String number,String code) {
System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
System.setProperty("sun.net.client.defaultReadTimeout", "10000");
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", BaseConfig.accessKeyId, BaseConfig.accessKeySecret);
try {
DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", BaseConfig.product, BaseConfig.domain);
} catch (ClientException e) {
e.printStackTrace();
}
IAcsClient acsClient = new DefaultAcsClient(profile);
//组装请求对象-具体描述见控制台-文档部分内容
SendSmsRequest request = new SendSmsRequest();
//必填:待发送手机号
request.setPhoneNumbers(number);
//必填:短信签名-可在短信控制台中找到
request.setSignName("短信签名");
//必填:短信模板-可在短信控制台中找到
request.setTemplateCode("SMS_80190341");
request.setTemplateParam("{ \"code\":\""+code+"\"}");
//选填-上行短信扩展码(无特殊需求用户请忽略此字段)
//request.setSmsUpExtendCode("90997");
//可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
request.setOutId("yourOutId");
//hint 此处可能会抛出异常,注意catch
SendSmsResponse sendSmsResponse=null;
try {
sendSmsResponse = acsClient.getAcsResponse(request);
} catch (ServerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClientException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return sendSmsResponse;
}
}
public class BaseConfig {
//产品名称:云通信短信API产品,开发者无需替换
public static final String product = "Dysmsapi";
//产品域名,开发者无需替换
public static final String domain = "dysmsapi.aliyuncs.com";
// TODO 此处需要替换成开发者自己的AK(在阿里云访问控制台寻找)
public static final String accessKeyId = "";
public static final String accessKeySecret = "";
//此KEY自己设置调用的时候用的key要和这个一直不然签名会失败
public static final String key="";
}
信息发送的接口类
调用后会返回json,里面有各种信息
{“number”:”xxxxxxxxx”,”code”:”9028”,”nonceStr”:”502e4a16930e414107ee22b6198c578f”,”timeStamp”:”1505210614”,”sign”:”6777FC73D22724442F807F7E6F5FCB5E”,”Code”:”fail”,”message”:”签名错误”}
根据返回的结果判断是否发送成功,成功的时候Code:OK
@Controller
@RequestMapping(value = "/joymeter")
public class MessageSendControl {
@Autowired
private MessageSendService messageSendServiceImp;
@RequestMapping("/messageSend")
public void MessageSend(HttpServletRequest request,HttpServletResponse response) {
String line = null;
StringBuffer jb = new StringBuffer();
BufferedReader reader = null;
try {
reader = request.getReader();
while ((line = reader.readLine()) != null)
jb.append(line);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(jb.toString());
try {
reader.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
JSONObject json = JSONObject.fromObject(jb.toString());
String number = json.getString("number");
String code = json.getString("code");
String sign = json.getString("sign");
String nonceStr = json.getString("nonceStr");
String timeStamp = json.getString("timeStamp");
Map map = new HashMap();
map.put("number", number);
map.put("code", code);
map.put("nonceStr", nonceStr);
map.put("timeStamp", timeStamp);
String sign2 = MerchantApiUtil.getSign(map, BaseConfig.key);
if(!sign.equals(sign2)) {
json.put("Code", "fail");
json.put("message", "签名错误");
}else {
//调用发送短信的方法并返回sendSmsresponse
SendSmsResponse sendSmsresponse = messageSendServiceImp.sendSms(number, code);
//将返回结果封装到json发送给调用接口者处理
json.put("Code", sendSmsresponse.getCode());
json.put("Message", sendSmsresponse.getMessage());
json.put("RequestId",sendSmsresponse.getRequestId());
json.put("BizId", sendSmsresponse.getBizId());
}
PrintWriter writer=null;
try {
writer = response.getWriter();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
writer.print(json.toString());
writer.flush();
}
}
上述代码中用到的工具类MerchantApiUtil,是用来生成签名的,具体签名规则参考微信公共号开发的签名生成规则(照着微信的公共号开发是模式写的签名)具体实现没看明白我拷贝过来的。 签名规则:
设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。
特别注意以下重要规则:
◆ 参数名ASCII码从小到大排序(字典序);
◆ 如果参数的值为空不参与签名;
◆ 参数名区分大小写;
◆ 验证调用返回或微信主动通知签名时,传送的sign参数不参与签名,将生成的签名与该sign值作校验。
◆ 微信接口可能增加字段,验证签名时必须支持增加的扩展字段
不愿意看的我会上传资源的
以上就写好了一个短信二次接口,下面有一个简单的测试接口类
public class Test1 {
private static String key="000000"; //模拟key值
public static void main(String[] args) {
//请求的URL地址
String url="http://localhost:8080/aliduanxin/joymeter/messageSend";
JSONObject json = new JSONObject();
//发送给的电话号码
json.put("number", "xxxxxxxxx");
//要发送的验证码值
json.put("code", "0000");
//随机字符串,随便用什么方式生成
json.put("nonceStr", MerchantApiUtil.getNonceStr());
json.put("timeStamp", MerchantApiUtil.getTimeStamp());
Map map = new HashMap();
map.put("number", "xxxxxxx");
map.put("code", "0000");
//随机字符串
map.put("nonceStr", json.getString("nonceStr"));
//时间戳
map.put("timeStamp", json.getString("timeStamp"));
//生成签名
String sign = MerchantApiUtil.getSign(map, key);
json.put("sign", sign);
String outStr = json.toString();
json= HttpUtil.httpRequest(url, "POST",outStr);
System.out.println(json);
}
}
然后写一个简单的短信验证登陆:
登陆页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登陆title>
<script type="text/javascript" language="javascript" src="<%=request.getContextPath() %>/js/jquery-3.2.1.js">script>
head>
<script type="text/javascript">
var InterValObj; //timer变量,控制时间
var count = 10; //间隔函数,1秒执行
var curCount;//当前剩余秒数
function reloadCode(){
//向后台发送请求生成code并存入session中
$.post("codeCreate.action", { time : new Date().getTime() } );
curCount = count;
//读秒提示
$("#btn").attr("disabled", "true");
$("#btn").val("请在" + curCount + "秒内输入验证码");
//启动定时器
InterValObj = window.setInterval(SetRemainTime, 1000);
}
function SetRemainTime() {
if (curCount == 0) {
window.clearInterval(InterValObj);// 停止计时器
$("#btn").removeAttr("disabled");// 启用按钮
$("#btn").val("重新发送验证码");
// code = ""; // 清除验证码。如果不清除,过时间后,输入收到的验证码依然有效
$.post("sessionRemove.action", { time : new Date().getTime(),codeName:'code' } );
}else {
curCount--;
$("#btn").val("请在" + curCount + "秒内输入验证码");
}
}
script>
<body>
<form method='post' action='login.action'>
<input type="text" name="code" id="code" value=""/>
<input type="button" id="btn" value="点击获取验证码" onclick="reloadCode()"/><br>
<input type="submit" value="Login">
form>
body>
html>
效果就是这样只写了验证码其他的不要了,时间可以自己改,测试的时候不愿意等注意这里请求登陆的地址要写
/test/index.action
后台处理
@Controller
@RequestMapping(value = "/test")
public class Login {
//登陆验证
@RequestMapping("/login.action")
public String login(HttpServletRequest req,HttpServletRequest resp,Map map) {
String code = req.getParameter("code");
System.out.println(code);
System.out.println(req.getSession().getAttribute("code"));
if(code.equals(req.getSession().getAttribute("code"))) {
HttpSession session = req.getSession();
//登陆成功后将code从session中清除
session.removeAttribute("code");
System.out.println("登陆成功");
return "success";
}
else {
System.out.println("登陆失败");
//返回登陆
return "redirect:/test/index.action";
}
}
@RequestMapping("/codeCreate.action")
public void imageCodeCreate(HttpServletRequest req,HttpServletResponse resp) throws IOException {
//实现短信发送接口的key值,要与configbath中一致
String key = "123456789";
String code = (String) ImageCodeCreate.createImageCode().get("code");
String url = "http://localhost:8080/aliduanxin/joymeter/messageSend";
JSONObject json = new JSONObject();
json.put("number", "xxxxxxx");
json.put("code", code);
json.put("nonceStr", MerchantApiUtil.getNonceStr());
json.put("timeStamp", MerchantApiUtil.getTimeStamp());
Map map = new HashMap();
map.put("number", "xxxxxxxx");
map.put("code", code);
//随机字符串
map.put("nonceStr", json.getString("nonceStr"));
//时间戳
map.put("timeStamp", json.getString("timeStamp"));
//生成签名
String sign = MerchantApiUtil.getSign(map, key);
json.put("sign", sign);
String outStr = json.toString();
json= HttpUtil.httpRequest(url, "POST",outStr);
System.out.println(json);
// if(json.getString("Code").equals("OK")) {
HttpSession session = req.getSession();
session.setAttribute("code", code);
// }
}
/**
* 清楚session中的某个属性
* @param req
* @param resp
*/
@RequestMapping("/sessionRemove.action")
public void sessionRemove(HttpServletRequest req,HttpServletResponse resp) {
String codeName = req.getParameter("codeName");
req.getSession().removeAttribute(codeName);
}
@RequestMapping("/index.action")
public String index() {
return "login";
}
}