聊聊如何在Java應用中傳送簡訊

2023-11-07 18:00:51

很多業務場景裡,我們都需要傳送簡訊,比如登陸驗證碼、告警、行銷通知、節日祝福等等。

這篇文章,我們聊聊 Java 應用中如何優雅的傳送簡訊。

1 使用者端/伺服器端兩種模式

Java 應用中傳送簡訊通常需要使用簡訊服務提供商提供的簡訊 API 。

我們經常使用的簡訊渠道有:阿里雲騰訊雲華為雲億美等。

傳送簡訊模式分為兩種:

1、使用者端模式

使用者端模式是指應用系統直接呼叫簡訊服務提供商提供的簡訊 API 傳送簡訊。

2、伺服器端模式

伺服器端模式是獨立建立一個簡訊平臺服務,應用系統直接使用簡訊平臺服務提供的 SDK 傳送簡訊。

核心流程如下:

  1. 前端呼叫應用服務介面傳送簡訊 ;
  2. 應用服務收到簡訊請求後,呼叫 SDK 方法根據模版傳送簡訊;
  3. 簡訊平臺服務收到請求,根據路由演演算法選擇設定的渠道(比如阿里雲、騰訊雲)傳送簡訊;
  4. 簡訊成功傳送到使用者手機 。

2 使用者端模式

1、使用三方簡訊渠道 SDK

使用者端模式是非常簡單的模式,很多簡訊服務提供商會提供成熟的 SDK ,業務系統只需要新增 SDK 依賴以及相關設定,就可以呼叫 SDK 提供的方法傳送簡訊。

我們以阿里雲簡訊服務為例, 呼叫 API 傳送簡訊的全流程如下所示:

使用 SDK 範例如下:

國內雲廠商阿里雲、騰訊雲、華為雲的簡訊服務,都需要依次申請簽名申請模版,稽核通過之後才能傳送簡訊。

2、封裝多個三方渠道介面

雖然使用三方簡訊渠道 SDK 非常簡單,但是在實際專案中,可能會存在多個三方渠道,也就是說:可能有的簡訊是通過騰訊雲傳送,有的是通過阿里雲傳送。 這樣就需要在工程中設定不同渠道的 SDK 依賴。

但這種方式會有兩個明顯的問題 :

  • 不同渠道的傳送簡訊程式碼不一致,業務程式碼偏混亂。
  • 工程中引入到 SDK 包比較多,不同的 SDK 依賴並不相同,可能存在衝突問題 。

為了解決這個問題,有一種方法是擯棄三方渠道 SDK ,自己實現 SDK 的傳送簡訊方法,這樣可以統一傳送簡訊程式碼,易於管理。

筆者發現一個開源專案 SMS4J,該專案為簡訊聚合框架,旨在整合多家簡訊服務,解決接入多個簡訊 SDK 的繁瑣流程。

下面我們展示在 SpringBoot 環境如何整合。

  1. maven 引入
<dependency>
 <groupId>org.dromara.sms4j</groupId>
 <artifactId>sms4j-spring-boot-starter</artifactId>
 <version>3.0.2</version>
</dependency>
  1. 設定組態檔
sms:
   alibaba:
      #阿里雲的accessKey
      accessKeyId: 您的accessKey
      #阿里雲的accessKeySecret
      accessKeySecret: 您的accessKeySecret
      #簡訊簽名
      signature: 測試簽名
      #模板ID 用於傳送固定模板簡訊使用
      templateId: SMS_215125134
      #模板變數 上述模板的變數
      templateName: code
      #請求地址 預設為dysmsapi.aliyuncs.com 如無特殊改變可以不用設定
      requestUrl: dysmsapi.aliyuncs.com
   huawei:
      #華為簡訊appKey
      appKey: 5N6fvXXXX920HaWhVXXXXXX7fYa
      #華為簡訊appSecret
      app-secret: Wujt7EYzZTBXXXXXXEhSP6XXXX
      #簡訊簽名
      signature: 華為簡訊測試
      #通道號
      sender: 8823040504797
      #模板ID 如果使用自定義模板傳送方法可不設定
      template-id: acXXXXXXXXc274b2a8263479b954c1ab5
      #華為回撥地址,如不需要可不設定或為空
      statusCallBack:
      #華為分配的app請求地址
      url: https://XXXXX.cn-north-4.XXXXXXXX.com:443
   zhutong:
      #助通簡訊
      #助通終端使用者管理的使用者名稱 username 必填;非登入賬號密碼,請登入後臺管理地址進行檢視:http://mix2.zthysms.com/login
      accessKeyId: tushu1122XXX
      #助通終端使用者管理的使用者名稱 passwrod 必填;
      accessKeySecret: UbXXX4SL
      #簡訊簽名,可選;可選的時候,只能使用自定義簡訊不能使用模板簡訊; 具體在這裡檢視稽核過的簡訊簽名:https://mix2.zthysms.com/index.html#/SignatureManagement
      signature: 上海千XXXX
  1. 方法使用
@RestController
@RequestMapping("/test/")
public class DemoController {
  // 測試傳送固定模板簡訊
  @RequestMapping("/")
  public void doLogin(String username, String password) {
     //阿里雲向此手機號傳送簡訊
     SmsFactory.createSmsBlend(SupplierType.ALIBABA).
                       sendMessage("18888888888","123456");
     //華為簡訊向此手機號傳送簡訊
     SmsFactory.createSmsBlend(SupplierType.HUAWEI).
                       sendMessage("16666666666","000000");
  }
}

使用者端模式是簡單實用的模式,我們可以直接引入三方渠道的 SDK 傳送簡訊,但當存在多種渠道簡訊時,可能程式碼會比較混亂。

雖然我們可以封裝多個三方渠道介面來解決問題,但研發成本還是比較高的。

另外,當研發小組分散,傳送簡訊各自自成體系時,當某一個渠道由於某種原因被棄用時,大部分研發小組都可能會受影響。

3 伺服器端模式

伺服器端模式是獨立建立一個簡訊平臺服務,應用服務直接使用簡訊平臺提供的 SDK 傳送簡訊。

簡訊平臺的設計有如下要點:

1、應用管理

簡訊平臺為每一個接入的應用分配單獨的 appKeyappSecret ,每一個應用可以設定獨立的限流策略。

2、精簡的 SDK 提供按照模版單發/群發的功能

public SmsSenderResult sendSmsByTemplateId(	
  			            String mobile, 
                    String templateId, 
                    Map<String, String> templateParam);

3、簽名、模版管理

每個應用服務涉及到的簽名、模版的管理都中心化 ,我們可以讓一個模板繫結多個渠道。

當某條簡訊通過渠道 A 傳送失敗時,可以通過另一個渠道 B 傳送,如此可以達到高可用的效果。

4、多渠道適配

伺服器端要載入多個渠道的 SDK ,那麼可能導致依賴衝突,可以採取 SPI 機載入渠道外掛。

筆者曾經重構過一個簡訊平臺服務,架構圖如下:

  1. 模仿騰訊雲的 SDK 設計,提供簡單易用的簡訊介面;
  2. 設計簡訊服務 API 端,接收傳簡訊請求,傳送簡訊資訊到訊息佇列;
  3. worker 服務消費訊息,按照負載均衡的演演算法,呼叫不同渠道商的簡訊介面;
  4. Dashboard 可以檢視簡訊傳送記錄,設定渠道商資訊。

如果我的文章對你有所幫助,還請幫忙點贊、在看、轉發一下,你的支援會激勵我輸出更高質量的文章,非常感謝!