很多業務場景裡,我們都需要傳送簡訊,比如登陸驗證碼、告警、營銷通知、節日祝福等等。
這篇文章,我們聊聊 Java 應用中如何優雅的傳送簡訊。
1 客戶端/服務端兩種模式
Java 應用中傳送簡訊通常需要使用簡訊服務提供商提供的簡訊 API 。
我們經常使用的簡訊渠道有:阿里雲
、騰訊雲
、華為雲
、億美
等。
傳送簡訊模式分為兩種:
1、客戶端模式
客戶端模式是指應用系統直接呼叫簡訊服務提供商提供的簡訊 API 傳送簡訊。
2、服務端模式
服務端模式是獨立建立一個簡訊平臺服務,應用系統直接使用簡訊平臺服務提供的 SDK 傳送簡訊。
核心流程如下:
- 前端呼叫應用服務介面傳送簡訊 ;
- 應用服務收到簡訊請求後,呼叫 SDK 方法根據模版傳送簡訊;
- 簡訊平臺服務收到請求,根據路由演算法選擇配置的渠道(比如阿里雲、騰訊雲)傳送簡訊;
- 簡訊成功傳送到使用者手機 。
2 客戶端模式
1、使用三方簡訊渠道 SDK
客戶端模式是非常簡單的模式,很多簡訊服務提供商會提供成熟的 SDK ,業務系統只需要新增 SDK 依賴以及相關配置,就可以呼叫 SDK 提供的方法傳送簡訊。
我們以阿里雲簡訊
服務為例, 呼叫 API 傳送簡訊的全流程如下所示:
使用 SDK 示例如下:
國內雲廠商阿里雲、騰訊雲、華為雲的簡訊服務,都需要依次申請簽名,申請模版,稽核透過之後才能傳送簡訊。
2、封裝多個三方渠道介面
雖然使用三方簡訊渠道 SDK 非常簡單,但是在實際專案中,可能會存在多個三方渠道,也就是說:可能有的簡訊是透過騰訊雲傳送,有的是透過阿里雲傳送。 這樣就需要在工程中配置不同渠道的 SDK 依賴。
但這種方式會有兩個明顯的問題 :
- 不同渠道的傳送簡訊程式碼不一致,業務程式碼偏混亂。
- 工程中引入到 SDK 包比較多,不同的 SDK 依賴並不相同,可能存在衝突問題 。
為了解決這個問題,有一種方法是擯棄三方渠道 SDK ,自己實現 SDK 的傳送簡訊方法,這樣可以統一傳送簡訊程式碼,易於管理。
筆者發現一個開源專案 SMS4J
,該專案為簡訊聚合框架,旨在整合多家簡訊服務,解決接入多個簡訊 SDK 的繁瑣流程。
下面我們展示在 SpringBoot 環境如何整合。
- maven 引入
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-spring-boot-starter</artifactId>
<version>3.0.2</version>
</dependency>
- 設定配置檔案
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
- 方法使用
@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、應用管理
簡訊平臺為每一個接入的應用分配單獨的 appKey
和 appSecret
,每一個應用可以配置獨立的限流策略。
2、精簡的 SDK 提供按照模版單發/群發的功能
public SmsSenderResult sendSmsByTemplateId(
String mobile,
String templateId,
Map<String, String> templateParam);
3、簽名、模版管理
每個應用服務涉及到的簽名、模版的管理都中心化 ,我們可以讓一個模板繫結多個渠道。
當某條簡訊透過渠道 A 傳送失敗時,可以透過另一個渠道 B 傳送,如此可以達到高可用的效果。
4、多渠道適配
服務端要載入多個渠道的 SDK ,那麼可能導致依賴衝突,可以採取 SPI 機載入渠道外掛。
筆者曾經重構過一個簡訊平臺服務,架構圖如下:
- 模仿騰訊雲的 SDK 設計,提供簡單易用的簡訊介面;
- 設計簡訊服務 API 端,接收發簡訊請求,傳送簡訊資訊到訊息佇列;
- worker 服務消費訊息,按照負載均衡的演算法,呼叫不同渠道商的簡訊介面;
- Dashboard 可以檢視簡訊傳送記錄,配置渠道商資訊。
如果我的文章對你有所幫助,還請幫忙點贊、在看、轉發一下,你的支援會激勵我輸出更高質量的文章,非常感謝!