sms短信网关对接

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

posted @ 2020-02-21 10:42  纵码万水千山  阅读(1944)  评论(0编辑  收藏  举报