最近由于业务需求,需要将原先的阿里元短信功能修改成中国移动的Mas。经过几天的研究接口文档,最终实现了:将移动的Mas的普通短信功能打成一个 jar 包,运行在服务器上,实现在业务代码中调用接口中的接口,发送短信的功能。
要使用中国移动的Mas短信功能,就要先了解接口文档(本案例使用HTTP的方式)。
浏览器打开:http://mas.10086.cn/login ,下载相关接口文档和案例。
这里我使用的是普通短信功能,由于账号未开通模板短信功能。暂不进行说明(与普通短信差不多)。
mvn install:install-file -DgroupId=com.masmgc -DartifactId=masmgc-sdk -Dversion=0.0.1-SNAPSHOT -Dpackaging=jar -Dfile=C:\masmgc.sdk.sms-0.0.1-SNAPSHOT.jar
mvn install:install-file -DgroupId=com.masmgc -DartifactId=mmasmgc-sdk-mms -Dversion=0.0.1-SNAPSHOT -Dpackaging=jar -Dfile=C:\masmgc.sdk.mms-0.0.1-SNAPSHOT.jar
使用SpringBoot初始化一个Maven项目,加入以下依赖:
<!--web模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--移动短信-->
<dependency>
<groupId>com.masmgc</groupId>
<artifactId>masmgc-sdk</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.masmgc</groupId>
<artifactId>masmgc-sdk-mms</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
package com.ifknow.pojo;
import lombok.Data;
/**
* @author: GongShiYong <br>
* @date: 2020/10/9 15:05 <br>
* @description: NO Description
*/
@Data
public class SendReq {
/**
* 集团客户名称
*/
private String ecName;
/**
* 用户名
*/
private String apId;
/**
* 密码
*/
private String secretKey;
/**
* 手机号码逗号分隔。(如“18137282928,18137282922,18137282923”)
*/
private String mobiles;
/**
* 发送短信内容
*/
private String content;
/**
* 网关签名编码,必填,签名编码在中国移动集团开通帐号后分配,可以在云MAS网页端管理子系统-SMS接口管理功能中下载。
*/
private String sign;
/**
* 扩展码,根据向移动公司申请的通道填写,如果申请的精确匹配通道,则填写空字符串(""),否则添加移动公司允许的扩展码。
*/
private String addSerial;
/**
* API输入参数签名结果,签名算法:将ecName,apId,secretKey,mobiles,content ,sign,addSerial按照顺序拼接,然后通过md5(32位小写)计算后得出的值。
*/
private String mac;
/**
* 参数
*/
private String params;
/**
* 模板id
*/
private String templateId;
}
package com.ifknow.pojo;
import lombok.Data;
/**
* @author: GongShiYong <br>
* @date: 2020/10/9 15:11 <br>
* @description: NO Description
*/
@Data
public class SendRes {
/**
* 响应状态码
*/
private String rspcod;
/**
* 消息批次号,由云MAS平台生成,用于验证短信提交报告和状态报告的一致性(取值msgGroup)注:如果数据验证不通过msgGroup为空
*/
private String msgGroup;
/**
* 数据校验结果
*/
private boolean success;
}
package com.ifknow.utils;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
/**
* @author: GongShiYong <br>
* @date: 2020/10/10 15:11 <br>
* @description: Md5 加密工具类
*/
public class Md5Util {
static final char hexDigits[] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
/**
* 生成MD5码
*
* @param plainText 要加密的字符串
* @return md5值
*/
public final static String MD5(String plainText) {
try {
byte[] strTemp = plainText.getBytes("UTF-8");
MessageDigest mdTemp = MessageDigest.getInstance("MD5");
mdTemp.update(strTemp);
byte[] md = mdTemp.digest();
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
return null;
}
}
/**
* 生成MD5码
*
* @param plainText 要加密的字符串
* @return md5值
*/
public final static String MD5(byte[] plainText) {
try {
byte[] strTemp = plainText;
MessageDigest mdTemp = MessageDigest.getInstance("MD5");
mdTemp.update(strTemp);
byte[] md = mdTemp.digest();
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
return null;
}
}
/**
* 先进行HmacSHA1转码再进行Base64编码
*
* @param data 要SHA1的串
* @param key 秘钥
* @return
* @throws Exception
*/
public static String HmacSHA1ToBase64(String data, String key) throws Exception {
SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(signingKey);
byte[] rawHmac = mac.doFinal(data.getBytes());
return Base64.encodeBase64String(rawHmac);
}
/**
* 校验MD5码
*
* @param text 要校验的字符串
* @param md5 md5值
* @return 校验结果
*/
public static boolean valid(String text, String md5) {
return md5.equals(MD5(text)) || md5.equals(MD5(text).toUpperCase());
}
/**
* @param params
* @return
*/
public static String MD5(String... params) {
StringBuilder sb = new StringBuilder();
for (String param : params) {
sb.append(param);
}
return MD5(sb.toString());
}
}
package com.ifknow.service;
import com.alibaba.fastjson.JSON;
import com.ifknow.pojo.SendReq;
import com.ifknow.pojo.SendRes;
import com.ifknow.utils.Md5Util;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;
/**
* @author: GongShiYong <br>
* @date: 2020/10/9 15:01 <br>
* @description: 普通短信发送 一对一
*/
@Component
public class SMSService {
/**
* 登录名
*/
private static String apId = "apId";
/**
* 登录密码
*/
private static String secretKey = "secretKey";
/**
* 集团名称
*/
private static String ecName = "ecName";
/**
* 网关签名编码
*/
private static String sign = "sign";
/**
* 拓展码 填空
*/
private static String addSerial = "";
/**
* 请求url 该接口为模板短信
*/
private static String url = "http://112.35.1.155:1992/sms/norsubmit";
private static Logger logger = LoggerFactory.getLogger(SMSService.class);
/**
* 多用户发送短信信息
*
* @param mobiles 手机号码逗号分隔
* @param content 短信内容
* @return 返回1表示成功,0表示失败
* @throws IOException
*/
public int sendMsg(String mobiles, String content) throws IOException {
//Calendar calendar = Calendar.getInstance();
//SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//String nowDatestr = sdf.format(calendar.getTimeInMillis());
//短信内容后跟个日期时间(可有可无),需求要求
//content += nowDatestr;
SendReq sendReq = new SendReq();
sendReq.setApId(apId);
sendReq.setEcName(ecName);
sendReq.setSecretKey(secretKey);
sendReq.setContent(content);
sendReq.setMobiles(mobiles);
sendReq.setAddSerial(addSerial);
sendReq.setSign(sign);
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(sendReq.getEcName());
stringBuffer.append(sendReq.getApId());
stringBuffer.append(sendReq.getSecretKey());
stringBuffer.append(sendReq.getMobiles());
stringBuffer.append(sendReq.getContent());
stringBuffer.append(sendReq.getSign());
stringBuffer.append(sendReq.getAddSerial());
sendReq.setMac(Md5Util.MD5(stringBuffer.toString()).toLowerCase());
String reqText = JSON.toJSONString(sendReq);
String encode = Base64.encodeBase64String(reqText.getBytes("UTF-8"));
String resStr = sendPost(url, encode);
logger.info("发送短信结果:" + resStr);
SendRes sendRes = JSON.parseObject(resStr, SendRes.class);
if (sendRes.isSuccess() && !"".equals(sendRes.getMsgGroup()) && "success".equals(sendRes.getRspcod())) {
return 1;
} else {
return 0;
}
}
/**
* 向指定 URL 发送POST方法的请求
*
* @param url 发送请求的 URL
* @param param 请求参数
* @return 所代表远程资源的响应结果
*/
public String sendPost(String url, String param) {
OutputStreamWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
URLConnection conn = realUrl.openConnection();
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("contentType", "utf-8");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
conn.setDoOutput(true);
conn.setDoInput(true);
out = new OutputStreamWriter(conn.getOutputStream());
out.write(param);
out.flush();
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += "\n" + line;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return result;
}
}
注意:需要将代码中的 apId、secretKey等变量进行修改。
我们的需求是将该短信服务做成一个jar包,进行部署使用,这就要求暴露出一个向外的接口,仅仅传手机号和发送的短信内容即可。
package com.ifknow.controller;
import com.ifknow.service.SMSService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
/**
* @author: GongShiYong <br>
* @date: 2020/10/10 10:20 <br>
* @description: 移动 mas 发送 【普通短信】
*/
@RestController
public class HttpMasSendController {
@Autowired
private SMSService smsService;
private Logger logger = LoggerFactory.getLogger(getClass());
@PostMapping("/sendMas")
public Integer sendMas(String mobile, String msg) {
try {
int result = smsService.sendMsg(mobile, msg);
System.out.println("短信发送成功===" + result);
return 1;
} catch (IOException e) {
logger.error("短信发送失败===" + mobile + msg);
}
return 0;
}
}
经过本地接口测试 http://localhost:8088/sendMas?mobile=123&msg=123
使用PostMan或者其他接口测试工具,进行调试。
打开控制台
// 清理
mvn clean
// 打包
mvn install / mvn package
将最终生成的 jar 包,传到服务器上,并放开服务器相关端口。
package com.ifknow.utils;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.SocketTimeoutException;
/**
* @author: GongShiYong <br>
* @date: 2020/10/10 13:53 <br>
* @description: 使用移动 Mas 发送普通短信的 工具类
*/
public class MasSendUtil {
private static Logger logger = LoggerFactory.getLogger(MasSendUtil.class);
public static int MasSend(String mobile, String msg) {
String url = null;
try {
CloseableHttpClient httpClient = HttpClients.createDefault();
RequestConfig requestConfig =
RequestConfig.custom().setSocketTimeout(300 * 1000).setConnectTimeout(300 * 1000).build();
url = "http://192.168.1.104:8088/sendMas?mobile=" + mobile + "&msg=" + msg;
HttpPost post = new HttpPost(url);
post.setConfig(requestConfig);
post.setHeader("Content-Type", "application/json;charset=utf-8");
HttpResponse response = httpClient.execute(post);
String content = EntityUtils.toString(response.getEntity());
System.out.println(content);
return 1;
} catch (SocketTimeoutException e) {
logger.error("调用sendMas接口超时,超时时间:" + 300 + "秒,url:" + url, e);
return 0;
} catch (Exception e) {
logger.error("调用sendMas接口失败,url:" + url, e);
return 0;
}
}
}
工具类的使用很简单,只需要传一个手机号和要发送的内容。
到这里,中国移动云Mas发送普通短信就完成了。
文章浏览阅读1.6k次。根据公司需求 需要在linux 上安装sqlserver数据库,已经安装了好长一段时间了,写的不好,但是我自己使用中确实没问题第一步:下载安装包wget https://packages.microsoft.com/rhel/7/mssql-server-2017/mssql-server-14.0.1000.169-2.x86_64.rpm第二部:解压安装包rpm -ivh mssql-...
文章浏览阅读2k次。codeblock配置调试器(debugger)1.settings-debugger settings-defaultExecutable path:添加Code Blocks\MinGW\bin中的gdb32.exe2.本身没有打开编译器的-g标志,具体:在setting->complier and debugger->global complier setting->..._c++codeblocks debugger选择
文章浏览阅读1w次,点赞3次,收藏17次。我们在安装python第三方库(扩展库)时,经常遇到下载速度慢的问题,即使换了源也不行。好不容易下载到第三方库的文件(比如whl)后,我们可以把这些文件(比如whl)保存下来,然后可以发给同学、队友(团队开发时环境最好一致),还可以方便自己之后的重新安装。那pip安装python第三方库时的缓存路径在哪呢?在下面这个路径中:C:\Users\Administrator\AppData\Local\pip\cache\http如何找自己想要的?只有根据时间和大小…比如我于2022-06-14 09:_pip下载的whl包在什么路径
文章浏览阅读1.4k次。第一章 概述受人类智能、生物群体社会性或自然现象规律的启发,人们发明了很多智能优化算法,主要包括:(1)遗传算法: 模仿自然界生物进化机制(2)差分进化算法: 通过群体个体间的合作与竞争来优化搜索(3)免疫算法: 模拟生物免疫系统学习和认知功能(4)蚁群算法:模拟蚂蚁集体寻径行为(5)粒子群算法:模拟鸟群和鱼群群体行为(6)模拟退火算法:源于固体物质退火过程(7)禁忌搜索算法:模拟人类智力记忆过程(8)神经网络算法:模拟动物神经网络行为特征大体可以分为以下五类:(1)进化类算法:遗传_智能优化算法系列读书报告
文章浏览阅读796次。今天看到CSDN网友sunlen在BLOG中写的“程序开发的心理研究”,让我想起了Weinberg先生的著作——《程序开发心理学》 。在计算机界,还没有任何一本计算机方面的书,在初次出版之后,能够在长达25年的岁月中一直保持活力,而且这种活力到今天仍在继续。 《程序开发心理学》 是开创“以人为本”研究方法的先驱,它以其对程序员们在智力、技巧、团队和问题求解能力等方面独特的视角和敏锐的观察经受住了时
文章浏览阅读514次。拿到的企业微信头像是正方形 我需要使用canvas处理成圆形但处理时发现会有跨域问题正常微信的图片就没有问题 只有企业微信的域名头像会提示跨域const canvas = document.createElement('canvas');const contex = canvas.getContext('2d');const img = new Image()img.crossOrigin = '...
文章浏览阅读658次。CSS中常用的单位一、长度单位长度单位是Web页设计中最常用的一个单位。一个排列无序、杂乱无章的页面不可能给人们留下什么好的印象。于是,在设计的时候需要为元素的位置、尺寸精确地定义一些值,以使其达到预期的效果。CSS给予人们精确控制网页的能力,这一点为人们津津乐道。它允许人们定义外观、尺寸、空间及其他的样式。但是,CSS所给出的控制同时也是一个危险的东西,这不仅表现在设计者缺乏经验,更在于如何给出..._html em ex
文章浏览阅读2.2k次。shiro-会话管理(session管理)shiro自己实现了一套session管理体系可以在不借助任何web容器或servlet的情况下使用session。1.SessionManager(session管理器)、SessionDAO(实现session的增删改查)2.Redis实现Session共享3.Redis实现Session共享存在的问题代码:pom.xml文件中添加依赖 ..._shiro会话共享
文章浏览阅读844次。animation :可以用 name 设置动画的名称,用 duration 设置动画完成的周期,用 timing-function 设置动画的速度曲线,delay 设置动画什么时候开始,iteration-count 设置动画播放的次数,direction 规定下一个周期是否逆向的播放,play-state 动画是否正在进行或者暂停,fill-mode 设置动画停了之后位置什么状态trans..._css3 animation和transition的区别
文章浏览阅读6.8w次,点赞4次,收藏14次。错误主要是jdk版本出现问题,博主也出现过这样的错误。当时使用的是jdk1.8一直报错,百度也没有效果。最终找到了答案,分享给大家。通过configure build path 换了jdk版本1.7,同时也要讲java compiler 改成jdk1.7 不然会报不匹配的错误。..._context initialization failed
文章浏览阅读926次。今天主要写一下,如何配置,保存前端代码后,浏览器自动刷新的功能,双屏操作,真的会方便很多,对于前端开发来说,一边写样式,一边看效果,爽翻~图片发自简书App一、开发环境1.电脑系统:mac2.代码编辑器:sublime text 33.项目框架:最简单的前端项目,html+css+js(最多用下jq)4.浏览器:chrome5.热加载:liveReload二、配置步骤好了现在就可以开始一步一步的配..._复制的html代码在浏览器打开不停的刷新
文章浏览阅读162次。前端: 车辆登记