打造萬能短信組件!Spring Boot 3.x 自定義 Starter 封裝實戰(zhàn),全兼容多平臺
在日益復雜的系統(tǒng)交互中,短信服務不僅僅用于驗證碼,更廣泛應用于訂單通知、運營提醒、系統(tǒng)預警等多種場景。尤其對于出海產品,國際短信支持、動態(tài)模板渲染、故障告警機制成為基本訴求。
為了避免每個項目重復對接不同短信平臺的 SDK,我們通過 Spring Boot 3.x 自定義 Starter 封裝出一套靈活的短信模塊 —— 不僅支持國內常見平臺(騰訊云、阿里云、亞馬遜云),還擴展了:
- 模板通知:通過變量占位符方式渲染動態(tài)內容;
- 國際短信:支持國家碼自動拼接;
- 異常監(jiān)控:發(fā)送失敗記錄到日志系統(tǒng)或后續(xù)告警通道。
整體架構設計
架構圖解
配置文件 → SmsAutoConfiguration → SmsTemplate → SmsHandleFactory → 具體廠商實現(xiàn)類(策略)
↑ ↘
SmsProperties → SmsTemplateSupport(模板渲染)
↑ ↘
國際化開關 異常捕獲與日志告警項目結構(含新增模塊)sms-spring-boot-starter
├── config/
│ ├── SmsAutoConfiguration.java
│ ├── SmsProperties.java
│ ├── SmsTemplate.java
│ └── SmsTemplateSupport.java 模板渲染支持
├── constant/
│ ├── SmsTypeEnum.java
│ └── SmsTemplateEnum.java 模板類型枚舉
├── factory/
│ └── SmsHandleFactory.java
├── service/
│ ├── SmsService.java
│ └── impl/
│ ├── AliCloudSmsServiceImpl.java
│ ├── TxCloudSmsServiceImpl.java
│ └── YmxCloudSmsServiceImpl.java
└── monitor/
└── SmsMonitorLogHandler.java 異常監(jiān)控處理器功能實現(xiàn)詳解
動態(tài)模板能力(支持占位符替換)
枚舉定義常用模板
// com/icoderoad/smsstarter/constant/SmsTemplateEnum.java
public enum SmsTemplateEnum {
LOGIN_CODE("login_code", "您的驗證碼是:${code},請于 ${minute} 分鐘內使用"),
ALERT_NOTIFY("alert_notify", "系統(tǒng)異常!模塊:${module},時間:${time}");
private final String key;
private final String template;
SmsTemplateEnum(String key, String template) {
this.key = key;
this.template = template;
}
public String getTemplate() {
return template;
}
public static String resolve(String key) {
for (SmsTemplateEnum e : values()) {
if (e.key.equals(key)) return e.template;
}
return "";
}
}模板渲染組件
// com/icoderoad/smsstarter/config/SmsTemplateSupport.java
@Component
public class SmsTemplateSupport {
public String render(String template, Map<String, Object> params) {
String result = template;
for (Map.Entry<String, Object> entry : params.entrySet()) {
result = result.replace("${" + entry.getKey() + "}", String.valueOf(entry.getValue()));
}
return result;
}
}國際短信支持
配置類增加國際化開關
// com/icoderoad/smsstarter/config/SmsProperties.java
@ConfigurationProperties(prefix = "sms.server")
public class SmsProperties {
private String type;
private boolean enableIntl = false; // 是否啟用國際短信
public String getType() {
return (type == null || type.isEmpty()) ? SmsTypeEnum.TX_CLOUD.getType() : type;
}
public void setType(String type) {
this.type = type;
}
public boolean isEnableIntl() {
return enableIntl;
}
public void setEnableIntl(boolean enableIntl) {
this.enableIntl = enableIntl;
}
}發(fā)送模板接口與異常監(jiān)控集成
// com/icoderoad/smsstarter/config/SmsTemplate.java
@Component
public class SmsTemplate {
@Autowired
private SmsProperties smsProperties;
@Autowired
private SmsHandleFactory smsHandleFactory;
@Autowired
private SmsTemplateSupport smsTemplateSupport;
@Autowired(required = false)
private SmsMonitorLogHandler smsMonitorLogHandler;
public String sendWithTemplate(String fromPhone, String toPhone, String templateKey, Map<String, Object> params) {
try {
String template = SmsTemplateEnum.resolve(templateKey);
String content = smsTemplateSupport.render(template, params);
String intlTo = smsProperties.isEnableIntl() ? "+86" + toPhone : toPhone;
SmsService service = smsHandleFactory.createSmsService(smsProperties.getType());
return service.send(fromPhone, intlTo, content);
} catch (Exception e) {
if (smsMonitorLogHandler != null) {
smsMonitorLogHandler.handle(e, toPhone, templateKey, params);
}
return "fail";
}
}
}異常監(jiān)控處理器(可接日志 / 釘釘機器人等)
// com/icoderoad/smsstarter/monitor/SmsMonitorLogHandler.java
@Component
public class SmsMonitorLogHandler {
public void handle(Exception e, String phone, String templateKey, Map<String, Object> params) {
// 實際項目中可對接釘釘/飛書/webhook等
System.err.println("【短信發(fā)送失敗】手機號:" + phone);
System.err.println("使用模板:" + templateKey + " 參數(shù):" + params);
e.printStackTrace();
}
}測試模塊增強
// com/icoderoad/startertest/controller/SmsController.java
@RestController
@RequestMapping("/sms")
public class SmsController {
@Resource
private SmsTemplate smsTemplate;
@GetMapping("/send")
public String sendCode() {
Map<String, Object> params = new HashMap<>();
params.put("code", "9527");
params.put("minute", "5");
return smsTemplate.sendWithTemplate("186xxxx8888", "156xxxx9999", "login_code", params);
}
@GetMapping("/alert")
public String sendAlert() {
Map<String, Object> params = new HashMap<>();
params.put("module", "短信服務模塊");
params.put("time", LocalDateTime.now().toString());
return smsTemplate.sendWithTemplate("186xxxx8888", "156xxxx9999", "alert_notify", params);
}
}
# application.properties
sms.server.type=tx
sms.server.enable-intl=true結語:從工具到平臺,打造可演進的短信中臺
通過本文實戰(zhàn),我們不僅實現(xiàn)了一個支持主流云服務商的短信發(fā)送 Starter,更將其能力拓展到:
- 可配置切換云平臺
- 支持國際化前綴處理
- 模板化渲染自定義內容
- 集成異常監(jiān)控機制
這一組件設計清晰,職責分明,可作為構建 統(tǒng)一運營平臺 / 告警系統(tǒng) / 消息中臺 的核心模塊之一。開發(fā)者無需關心短信發(fā)送邏輯,僅需配置參數(shù)與模板,即可完成復雜通知任務。































