📱 短信服务设计
1. 模块概述
短信服务模块是系统的核心功能之一,基于策略模式和工厂模式实现,支持多种短信服务商(阿里云、腾讯云等)。该模块采用数据库存储配置(JSON格式),提供了短信发送、模板管理、记录管理等功能,适用于各种业务场景下的短信发送需求。
2. 设计目标
| 目标 | 描述 |
|---|---|
| 🎯 多服务商支持 | 支持阿里云、腾讯云等多种短信服务商 |
| 🔧 易于扩展 | 基于策略模式和工厂模式,易于扩展新的短信服务商 |
| � 数据库配置 | 配置信息存储在数据库中,使用JSON格式管理 |
| �📊 完整的功能 | 提供短信发送、模板管理、记录管理等功能 |
| 🚀 高性能 | 支持异步发送短信,提高系统响应速度 |
| 🔐 安全性 | 完善的异常处理机制,确保系统稳定性 |
| 📋 可追溯性 | 记录短信发送状态和内容,便于查询和统计 |
3. 目录结构
zs-sms/
├── zs-sms-api/ # 短信API定义
├── zs-sms-service/ # 短信服务实现
│ ├── src/main/java/com/zs/sms/
│ │ ├── controller/ # 控制器
│ │ ├── domain/ # 数据模型
│ │ │ ├── entity/ # 实体类
│ │ │ ├── excel/ # Excel导出模型
│ │ │ ├── params/ # 请求参数
│ │ │ └── vo/ # 响应VO
│ │ ├── factory/ # 工厂类
│ │ ├── mapper/ # Mapper接口
│ │ ├── service/ # 服务层
│ │ └── strategy/ # 短信发送策略
│ └── resources/ # 资源文件
└── pom.xml # Maven依赖4. 核心设计
4.1 设计模式
4.1.1 策略模式
短信服务采用策略模式实现,定义了统一的短信发送接口 SendSmsStrategy,不同的短信服务商实现该接口,提供不同的发送逻辑。
优点:
- ✅ 易于扩展新的短信服务商
- ✅ 便于切换不同的短信服务商
- ✅ 符合开闭原则,对扩展开放,对修改关闭
4.1.2 工厂模式
提供 SmsFactory 工厂类,用于创建不同的短信发送策略实例。
优点:
- ✅ 封装了策略的创建逻辑
- ✅ 客户端无需直接依赖具体的策略实现
- ✅ 便于统一管理和配置
4.2 核心接口和类
4.2.1 SendSmsStrategy 接口
java
/**
* 📱 短信发送策略接口
* 定义统一的短信发送方法,不同短信服务商实现该接口
*/
public interface SendSmsStrategy {
/**
* 发送短信
* @param params 短信参数
* @return 发送结果
*/
boolean sendSms(SysSmsParams params);
}4.2.2 SmsFactory 工厂类
java
/**
* 📱 短信工厂类
* 用于创建不同的短信发送策略实例
*/
public class SmsFactory {
/**
* 创建短信发送策略
* @param type 短信服务商类型
* @return 短信发送策略实例
*/
public static SendSmsStrategy createStrategy(String type) {
switch (type) {
case "aliyun":
return new AliyunSendSmsStrategy();
case "tencent":
return new TencentSendSmsStrategy();
default:
throw new IllegalArgumentException("Unsupported sms provider type: " + type);
}
}
}4.2.3 策略实现类
| 类名 | 描述 |
|---|---|
| AliyunSendSmsStrategy | 阿里云短信发送策略 |
| TencentSendSmsStrategy | 腾讯云短信发送策略 |
4.3 数据模型
4.3.1 SysSmsRecordEntity
短信发送记录实体类,记录短信发送状态和内容。
| 字段名 | 类型 | 描述 |
|---|---|---|
| id | Long | 记录ID |
| mobile | String | 手机号 |
| templateId | String | 模板ID |
| templateParams | String | 模板参数 |
| content | String | 短信内容 |
| status | Integer | 发送状态(0:失败,1:成功) |
| errorMsg | String | 错误信息 |
| sendTime | Date | 发送时间 |
| createTime | Date | 创建时间 |
4.3.2 SysSmsTemplateEntity
短信模板实体类,记录短信模板信息。
| 字段名 | 类型 | 描述 |
|---|---|---|
| id | Long | 模板ID |
| templateCode | String | 模板编码 |
| templateContent | String | 模板内容 |
| templateType | String | 模板类型 |
| status | Integer | 状态(0:禁用,1:启用) |
| createTime | Date | 创建时间 |
| updateTime | Date | 更新时间 |
4.3.3 SysSmsConfigEntity
数据库存储配置信息,使用JSON格式,记录短信服务商配置。
| 字段名 | 类型 | 描述 |
|---|---|---|
| id | Long | 配置ID |
| providerType | String | 服务商类型(aliyun、tencent等) |
| config | String | 配置信息(JSON格式) |
| status | Integer | 状态(0:禁用,1:启用) |
| createTime | Date | 创建时间 |
| updateTime | Date | 更新时间 |
| remark | String | 备注信息 |
4.3.4 SysSmsParams
短信发送参数类,用于封装短信发送所需的参数。
| 字段名 | 类型 | 描述 |
|---|---|---|
| mobile | String | 手机号 |
| templateId | String | 模板ID |
| templateParams | Map<String, String> | 模板参数 |
| signName | String | 签名名称 |
5. 核心流程
5.1 短信发送流程
mermaid
sequenceDiagram
participant Client as 客户端
participant Controller as 控制器
participant SmsService as 短信服务
participant ConfigService as 配置服务
participant SmsFactory as 短信工厂
participant Strategy as 短信策略
participant DB as 数据库
Client->>Controller: 调用短信发送接口
Controller->>SmsService: 调用sendSms方法
SmsService->>SmsService: 验证模板是否存在且启用
SmsService->>ConfigService: 查询数据库获取短信配置
ConfigService->>DB: 查询配置信息
DB-->>ConfigService: 返回配置(JSON格式)
ConfigService-->>SmsService: 返回解析后的配置对象
SmsService->>SmsFactory: 创建短信发送策略
SmsFactory->>Strategy: 创建具体策略实例
SmsService->>Strategy: 调用sendSms方法
Strategy-->>SmsService: 返回发送结果
SmsService->>DB: 保存发送记录
SmsService-->>Controller: 返回发送结果
Controller-->>Client: 返回响应5.2 模板管理流程
mermaid
sequenceDiagram
participant Admin as 管理员
participant Controller as 控制器
participant TemplateService as 模板服务
participant DB as 数据库
Admin->>Controller: 添加短信模板
Controller->>TemplateService: 调用addTemplate方法
TemplateService->>DB: 保存模板信息
TemplateService-->>Controller: 返回添加结果
Controller-->>Admin: 返回响应
Admin->>Controller: 审核短信模板
Controller->>TemplateService: 调用auditTemplate方法
TemplateService->>DB: 更新模板状态
TemplateService-->>Controller: 返回审核结果
Controller-->>Admin: 返回响应
Admin->>Controller: 启用短信模板
Controller->>TemplateService: 调用enableTemplate方法
TemplateService->>DB: 更新模板状态
TemplateService-->>Controller: 返回启用结果
Controller-->>Admin: 返回响应6. 使用示例
6.1 短信发送示例
java
@Service
public class SmsServiceImpl implements SmsService {
@Autowired
private SysSmsTemplateService sysSmsTemplateService;
@Autowired
private SysSmsRecordService sysSmsRecordService;
@Autowired
private SysSmsConfigService sysSmsConfigService;
@Override
public boolean sendSms(SysSmsParams params) {
// 1. 验证模板是否存在且启用
SysSmsTemplateVO template = sysSmsTemplateService.getByCode(params.getTemplateId());
if (template == null || template.getStatus() != 1) {
throw new IllegalArgumentException("Template not found or disabled");
}
// 2. 从数据库获取短信服务商配置(JSON格式)
SysSmsConfigVO config = sysSmsConfigService.getEnabledConfig();
if (config == null) {
throw new IllegalStateException("No enabled SMS provider config found");
}
// 3. 创建短信发送策略
SendSmsStrategy strategy = SmsFactory.createStrategy(config.getProviderType());
// 4. 发送短信
boolean success = strategy.sendSms(params);
// 5. 保存发送记录
SysSmsRecordAddParams recordParams = new SysSmsRecordAddParams();
recordParams.setMobile(params.getMobile());
recordParams.setTemplateId(params.getTemplateId());
recordParams.setTemplateParams(JSONUtil.toJsonStr(params.getTemplateParams()));
recordParams.setContent(generateContent(template, params.getTemplateParams()));
recordParams.setStatus(success ? 1 : 0);
recordParams.setSendTime(new Date());
sysSmsRecordService.save(recordParams);
return success;
}
private String generateContent(SysSmsTemplateVO template, Map<String, String> params) {
// 根据模板和参数生成短信内容
String content = template.getTemplateContent();
for (Map.Entry<String, String> entry : params.entrySet()) {
content = content.replace("{" + entry.getKey() + "}", entry.getValue());
}
return content;
}
}6.2 配置管理示例
java
@Service
public class SysSmsConfigServiceImpl implements SysSmsConfigService {
@Autowired
private SysSmsConfigMapper sysSmsConfigMapper;
@Override
public SysSmsConfigVO getEnabledConfig() {
// 查询启用的配置
SysSmsConfigEntity configEntity = sysSmsConfigMapper.selectEnabledConfig();
if (configEntity == null) {
return null;
}
// 解析JSON配置
SysSmsConfigVO configVO = new SysSmsConfigVO();
configVO.setId(configEntity.getId());
configVO.setProviderType(configEntity.getProviderType());
configVO.setConfig(JSONUtil.parseObj(configEntity.getConfig()));
configVO.setStatus(configEntity.getStatus());
configVO.setRemark(configEntity.getRemark());
return configVO;
}
@Override
public void saveConfig(SysSmsConfigAddParams params) {
// 保存配置到数据库
SysSmsConfigEntity entity = new SysSmsConfigEntity();
entity.setProviderType(params.getProviderType());
entity.setConfig(JSONUtil.toJsonStr(params.getConfig()));
entity.setStatus(params.getStatus());
entity.setRemark(params.getRemark());
if (params.getId() != null) {
entity.setId(params.getId());
sysSmsConfigMapper.updateById(entity);
} else {
sysSmsConfigMapper.insert(entity);
}
}
}6.3 控制器示例
java
@RestController
@RequestMapping("/sms")
public class SysSmsController {
@Autowired
private SmsService smsService;
@Autowired
private SysSmsConfigService sysSmsConfigService;
@PostMapping("/send")
public Result<Boolean> sendSms(@RequestBody SysSmsParams params) {
try {
boolean success = smsService.sendSms(params);
return Result.ok(success, success ? "短信发送成功" : "短信发送失败");
} catch (Exception e) {
return Result.error("短信发送失败:" + e.getMessage());
}
}
@PostMapping("/config")
public Result<Boolean> saveConfig(@RequestBody SysSmsConfigAddParams params) {
try {
sysSmsConfigService.saveConfig(params);
return Result.ok(true, "配置保存成功");
} catch (Exception e) {
return Result.error("配置保存失败:" + e.getMessage());
}
}
@GetMapping("/config")
public Result<SysSmsConfigVO> getConfig() {
try {
SysSmsConfigVO config = sysSmsConfigService.getEnabledConfig();
return Result.ok(config, "配置获取成功");
} catch (Exception e) {
return Result.error("配置获取失败:" + e.getMessage());
}
}
}7. 配置说明
7.1 阿里云短信配置(JSON格式)
| 配置项 | 类型 | 描述 |
|---|---|---|
| accessKeyId | String | 阿里云AccessKey ID |
| accessKeySecret | String | 阿里云AccessKey Secret |
| signName | String | 短信签名 |
| endpoint | String | 阿里云短信服务端点 |
| regionId | String | 阿里云区域ID,默认cn-hangzhou |
配置示例:
json
{
"accessKeyId": "your_access_key_id",
"accessKeySecret": "your_access_key_secret",
"signName": "your_sign_name",
"endpoint": "dysmsapi.aliyuncs.com",
"regionId": "cn-hangzhou"
}7.2 腾讯云短信配置(JSON格式)
| 配置项 | 类型 | 描述 |
|---|---|---|
| secretId | String | 腾讯云SecretId |
| secretKey | String | 腾讯云SecretKey |
| signName | String | 短信签名 |
| endpoint | String | 腾讯云短信服务端点 |
| region | String | 腾讯云区域,默认ap-guangzhou |
配置示例:
json
{
"secretId": "your_secret_id",
"secretKey": "your_secret_key",
"signName": "your_sign_name",
"endpoint": "sms.tencentcloudapi.com",
"region": "ap-guangzhou"
}8. 注意事项
- 模板审核:短信模板需要经过短信服务商审核才能使用
- 发送频率限制:避免频繁发送短信,防止被短信服务商拉黑
- 异常处理:短信发送可能失败,需做好异常处理和重试机制
- 签名配置:确保已在短信服务商平台配置了正确的签名
- 参数验证:严格验证短信发送参数,防止恶意调用
- 记录保存:保存短信发送记录,便于调试和审计
- 配置安全:妥善保管短信服务商的密钥信息,建议使用加密存储
- 数据库配置:配置信息存储在数据库中,使用JSON格式管理,便于动态修改
9. 扩展建议
- 添加更多服务商:支持更多短信服务商,如百度云、华为云等
- 添加短信队列:实现异步发送短信,提高系统响应速度
- 添加短信统计:统计短信发送量、成功率等指标
- 支持批量发送:支持一次性发送多条短信
- 添加短信模板变量验证:验证模板参数是否与模板匹配
- 支持短信状态回调:接收短信服务商的状态回调,更新发送状态
- 添加短信黑名单:支持配置短信黑名单,防止恶意发送
- 添加短信模板版本管理:支持模板的版本管理和回滚
10. 常见问题排查
10.1 短信发送失败
问题:调用短信发送接口后返回失败
可能原因:
- 数据库中短信服务商配置错误
- 模板ID或签名配置错误
- 手机号格式错误
- 短信内容包含敏感词
- 网络连接问题
解决方案:
- 检查数据库中的配置信息
- 验证模板ID和签名
- 验证手机号格式
- 检查短信内容
- 检查网络连接
10.2 短信发送成功但接收者未收到
问题:短信发送接口返回成功,但接收者未收到短信
可能原因:
- 手机号错误
- 短信被运营商拦截
- 短信服务商延迟
- 接收者手机问题
解决方案:
- 验证手机号
- 检查短信内容是否包含敏感词
- 等待一段时间后再次检查
- 尝试发送到其他手机号
10.3 模板审核不通过
问题:短信模板审核不通过
可能原因:
- 模板内容不符合要求
- 模板用途描述不清晰
- 缺少必要的资质证明
解决方案:
- 调整模板内容,确保符合短信服务商要求
- 清晰描述模板用途
- 提供必要的资质证明
10.4 发送频率超限
问题:发送短信时提示频率超限
可能原因:
- 短时间内发送短信次数过多
- 超过了短信服务商的频率限制
解决方案:
- 减少短信发送频率
- 联系短信服务商调整频率限制
- 实现短信发送队列,控制发送速度
11. 总结
短信服务模块基于策略模式和工厂模式实现,支持多种短信服务商,采用数据库存储配置(JSON格式),具有良好的扩展性和灵活性。该模块提供了短信发送、模板管理、记录管理等功能,适用于各种业务场景下的短信发送需求。
通过合理配置和使用,可以避免常见问题,提高短信发送的可靠性和安全性。同时,该模块具有良好的扩展性,可以根据业务需求进行功能扩展和优化。