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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM