因为工作的需求,需要对接短信网关,业务上就是一个注册用户时,需要发送手机验证码;可能别的公司都是使用第三方接口,但是大点的公司,为了安全,他们都有自己的短信消息中心(SMSC)

1.业务需求

- 1.对接短信网关,发送消息,下行发送(MT)   使用openSMPP开源的开发包

- 2.验证码使用redis存储(主要原因是,分布式存储,支持过期时间)

2. 下面是简单的代码实例(包括发送短信和redis存储验证码)

pom中添加依赖

   <dependency>
<groupId>org.opensmpp</groupId>
<artifactId>opensmpp-core</artifactId>
<version>3.0.2</version>
</dependency>
public class SmsController {    

   @Autowiredprivate RedisTemplate redisTemplate;

    public boolean sendVerifyCode() {
String destination = "8613594312686";
String host = "192.168.XX";
String port = "12345";
String userName = "test";
String password = "test";
//存储redis中的key
String key = getDestinationNumKey(destination);
//redis中已存在验证码,则使用redis中存储的验证码(在15分钟的过期时间内发送同一条验证码),否则生成6位数字验证码
Object valueByKey = getValueByKey(key);
String verificationCode = Objects.nonNull(valueByKey) ? valueByKey.toString() : String.valueOf((int) (Math.random() * 900000 + 100000));
//租户(不传,默认default)
boolean sendSuccess = sendMessage(host, port, userName, password, destination, verificationCode);
//发送成功后,验证码存入redis中,并设置过期时间(默认15分钟)
if (sendSuccess) {
putValueToRedisWithTimeout(key, verificationCode, 15, TimeUnit.MINUTES);
}
return sendSuccess;
} private String getDestinationNumKey(String destination) {
return String.format("%s:%s", "DESTINATION", destination);
} public boolean sendMessage(String host,
String port,
String userName,
String password,
String phonenumber,
String verifyCode) {
log.info("start to send sms notification, reciever,host {},port {}, userName {} password {} destinations is {} verifyCode {}", host, port, userName, password, phonenumber, verifyCode);
try {
TCPIPConnection connection = new TCPIPConnection(host, Integer.parseInt(port));
Session session = new Session(connection);
BindRequest request = new BindTransmitter();
request.setSystemId(userName);
request.setPassword(password);
//SMPP protocol version
request.setInterfaceVersion((byte) 0x34);
request.setSystemType("SMPP");
BindResponse bind = session.bind(request);
log.info("bind response debugString {},response command status {}", bind.debugString(), bind.getCommandStatus());
String content = "[Registration]" + verifyCode + " is your verification code. Valid in 15 minutes. Please do not share this code with anyone else.";
SubmitSM submitSM = constructRequest(phonenumber, content);
//bund faild 会导致TCPIPConnection关闭从而导致outputStream关闭从而导致no
SubmitSMResp response = session.submit(submitSM);
log.info("send message result {},command status is {}", response.debugString(), response.getCommandStatus());
} catch (Exception e) {
log.error("invoke sms session exception", e);
} } private SubmitSM constructRequest(String phoneNumber, String content) throws WrongLengthOfStringException, UnsupportedEncodingException {
String recipientPhoneNumber = phoneNumber; SubmitSM request = new SubmitSM();
request.setSourceAddr(createAddress("test")); request.setDestAddr(createAddress(recipientPhoneNumber));
request.setShortMessage(content, Data.ENC_UTF8);
request.setReplaceIfPresentFlag((byte) 0);
request.setEsmClass((byte) 0);
request.setProtocolId((byte) 0);
request.setPriorityFlag((byte) 0);
request.setRegisteredDelivery((byte) 1);// we want delivery reports
request.setDataCoding((byte) 0);
request.setSmDefaultMsgId((byte) 0);
return request;
} private Address createAddress(String address) throws WrongLengthOfStringException {
Address addressInst = new Address();
// national ton
addressInst.setTon((byte) 5);
// numeric plan indicator
addressInst.setNpi((byte) 0);
addressInst.setAddress(address, Data.SM_ADDR_LEN);
return addressInst;
} /**
* Redis中存储Value(value可为string,map,list,set等),并设置过期时间
*
* @param key
* @param value
* @param timeout
* @param unit
*/
public void putValueToRedisWithTimeout(Object key, Object value, final long timeout, final TimeUnit unit) {
try {
ValueOperations valueOperations = redisTemplate.opsForValue();
valueOperations.set(key, value, timeout, unit);
} catch (Exception e) {
}
} /**
* 根据key获取Value值
*
* @param key
*/
public Object getValueByKey(Object key) {
Object value = null;
try {
ValueOperations valueOperations = redisTemplate.opsForValue();
value = valueOperations.get(key);
} catch (Exception e) {
}
return value;
} /**
* 根据key获取Value值
*
* @param key
*/
public Object deleteKey(Object key) {
Object value = null;
try {
if (redisTemplate.hasKey(key)) {
redisTemplate.delete(key);
}
} catch (Exception e) {
}
return value;
} }

3. 校验验证码

此处代码就不贴了,直接根据手机号去redis中查询,若有值进行比较是否对错,若无值,直接抛出验证码无效即可

4. 对接网关的api

请参考https://www.world-text.com/docs/interfaces/SMPP/ 和 https://www.smssolutions.net/tutorials/smpp/smpperrorcodes/

5.短信网关模拟器

对接在测试环境时怎么测试是个问题,从网上找到一个模拟SMPP的,感觉挺好用,此处分享地址:SMPP模拟器

其他的参考:

http://read.pudn.com/downloads97/sourcecode/java/400090/OpenSMPP/src/org/smpp/test/SMPPTest.java__.htm

https://support.nowsms.com/discus/messages/1/SMPP_v3_4_Issue1_2-24857.pdf

https://stackoverflow.com/questions/26729958/using-smpp-to-send-sms-texts-in-java?answertab=active#tab-top

https://www.activexperts.com/sms-component/smpp-specifications/smpp-pdu-definition/

https://www.openmarket.com/docs/Content/apis/v4smpp/bind.htm

https://zhuanlan.zhihu.com/p/58237629

最新文章

  1. windows7设置开机启动方式
  2. 如何获取TypedArray?
  3. python中x,y交换值的问题
  4. hdu acm 1425 sort(哈希表思想)
  5. H5一二事
  6. editGrid自定义列自定义F7
  7. 最长上升子序列[LIS]
  8. 【转】Java HashMap 源码解析(好文章)
  9. java数组与内存控制
  10. unix c 10
  11. C# async await 例子
  12. 一个基于JRTPLIB的轻量级RTSP客户端(myRTSPClient)——实现篇:(三)用户接口层之RTSP命令
  13. 不同路径II(一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?网格中的障碍物和空位置分别用 1 和 0 来表示。)
  14. 使用Github添加标签
  15. linux socket TCP UDP bind 同义IP和port
  16. Dockerfile数据管理
  17. nyoj905 卡片游戏
  18. Coursera SDN M1.1 SDN History: Central Control
  19. 谈谈Copy-on-Write容器
  20. js获得分辨率

热门文章

  1. 【2021/12/31】uniapp之安卓原生插件开发教程
  2. Ranger开源流水线docker化实践案例
  3. nginx rewrite 基础
  4. [ bootstrap ] 实现卡片里面包含图片、内容、操作按钮,形成左中右的布局
  5. Pandas系列(十八)- 多级索引
  6. mysql-5.7.20-winx64安装图解教程
  7. HITsz 数据库笔记
  8. POJ3090Visible Lattice Points
  9. 从内存管理原理,窥探OS内存管理机制
  10. 手把手教你分析解决MySQL死锁问题