mirror of
https://gitee.com/dromara/RuoYi-Vue-Plus.git
synced 2026-09-17 17:15:28 +08:00
docs 新增 sms 短信功能 enabled 开关设计文档
对齐 mail.enabled 的软开关方案:新增 SmsProperties、条件化 SmsAutoConfiguration、 CaptchaController.smsCode 调用层判断。详见 docs/superpowers/specs/2026-06-30-sms-toggle-design.md Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
e49f02f89e
commit
18f51687b0
142
docs/superpowers/specs/2026-06-30-sms-toggle-design.md
Normal file
142
docs/superpowers/specs/2026-06-30-sms-toggle-design.md
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
# 设计文档:为 SMS 增加 `enabled` 开关(对齐 mail)
|
||||||
|
|
||||||
|
- 日期:2026-06-30
|
||||||
|
- 分支:5.X
|
||||||
|
- 状态:已批准(待实现)
|
||||||
|
|
||||||
|
## 1. 背景与目标
|
||||||
|
|
||||||
|
RuoYi-Vue-Plus 中,部分服务在配置文件里带开关,例如 `mail.enabled` 可以关闭邮件功能;但 `sms` 没有开关,短信功能始终启用。
|
||||||
|
|
||||||
|
**目标**:为 `sms` 增加一个 `enabled` 开关,使其与 `mail.enabled` 在语义与代码结构上完全对齐(软开关)。
|
||||||
|
|
||||||
|
## 2. 现状
|
||||||
|
|
||||||
|
### 2.1 Mail(有开关)——两层防护
|
||||||
|
|
||||||
|
- **配置层**:`application-dev.yml` 中 `mail.enabled: false`。
|
||||||
|
- **Bean 层**:`MailConfig`(`ruoyi-common-mail/.../config/MailConfig.java`)用 `@ConditionalOnProperty(value="mail.enabled", havingValue="true")` 创建 `MailAccount`;关掉时不创建该 Bean。
|
||||||
|
- **调用层**:`CaptchaController.emailCode()` 显式判断 `mailProperties.getEnabled()`,关掉时返回 `R.fail("当前系统没有开启邮箱功能!")`,并拆出独立的 `emailCodeImpl()` 承载 `@RateLimiter`,避免功能关闭后仍消耗限流配额。
|
||||||
|
|
||||||
|
### 2.2 SMS(无开关)
|
||||||
|
|
||||||
|
- **配置层**:`application-dev.yml` 中 `sms:` 只有 `config-type` / `restricted` / `minute-max` / `account-max` / `blends`,无 `enabled`。
|
||||||
|
- **Bean 层**:`SmsAutoConfiguration`(`ruoyi-common-sms/.../config/SmsAutoConfiguration.java`)**无条件**注册 `PlusSmsDao`(`@Primary SmsDao`,Redis 实现)与 `SmsExceptionHandler`;模块内**没有** properties 类、也没有 `SmsUtils`。
|
||||||
|
- **第三方层**:`sms4j-spring-boot-starter` 自身的自动配置读取 `sms.blends.*`,始终初始化 `SmsFactory` / `SmsBlend`。
|
||||||
|
- **调用层**:直接调用 `SmsFactory.getSmsBlend("config1")`。
|
||||||
|
- 活跃调用方:`CaptchaController.smsCode()`(真实场景,短信验证码)、`SmsController`(demo)。
|
||||||
|
- `FlwCommonServiceImpl` 中对 `SmsFactory` 的引用是**注释代码**,不计入范围。
|
||||||
|
|
||||||
|
### 2.3 关键差异
|
||||||
|
|
||||||
|
`MailAccount` 是**项目自有** Bean,可用 `@ConditionalOnProperty` 精确掐断;`SmsFactory` 是**第三方 sms4j** 自动初始化的,无法用同一注解直接掐掉。本设计采用软开关:真正"关掉发送"由调用层判断完成;Bean 层只做与 `MailConfig` 对齐的清理(关掉时不创建项目自有的 SMS Bean)。
|
||||||
|
|
||||||
|
## 3. 决策记录
|
||||||
|
|
||||||
|
- **开关语义:软开关**(已确认)。`sms.enabled=false` 时:调用层返回友好"未开启"提示;项目自有的 `PlusSmsDao` / `SmsExceptionHandler` 不创建;sms4j starter 仍会在后台初始化(其默认 in-memory `SmsDao` 兜底,不影响应用启动,且不会真实发信)。
|
||||||
|
- **默认值:`false`**(与 mail 一致)。
|
||||||
|
- **命名:`sms.enabled`**(与 `mail.enabled` 完全一致)。
|
||||||
|
- **范围:仅覆盖真实调用方 `CaptchaController.smsCode()`**;demo `SmsController` 不动。
|
||||||
|
|
||||||
|
## 4. 详细设计
|
||||||
|
|
||||||
|
### 4.1 配置文件
|
||||||
|
|
||||||
|
文件:`ruoyi-admin/src/main/resources/application-dev.yml` 与 `application-prod.yml`。
|
||||||
|
|
||||||
|
在 `sms:` 节点顶部新增 `enabled`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商
|
||||||
|
sms:
|
||||||
|
# 是否开启短信功能(默认关,与 mail 保持一致)
|
||||||
|
enabled: false
|
||||||
|
# 配置源类型用于标定配置来源(interface,yaml)
|
||||||
|
config-type: yaml
|
||||||
|
# ...其余原配置不变
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 新增 `SmsProperties`
|
||||||
|
|
||||||
|
文件:`ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/properties/SmsProperties.java`
|
||||||
|
|
||||||
|
```java
|
||||||
|
package org.dromara.common.sms.config.properties;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 短信配置属性
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ConfigurationProperties(prefix = "sms")
|
||||||
|
public class SmsProperties {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否开启短信功能
|
||||||
|
*/
|
||||||
|
private Boolean enabled;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> `sms` 前缀与 sms4j 的 `blends` 等配置共存。Spring Boot 允许同一前缀绑定多个 `@ConfigurationProperties` 类,只要字段不冲突;`enabled` 不属于 sms4j 使用的字段。该假设须在实现阶段通过启动验证。
|
||||||
|
|
||||||
|
### 4.3 `SmsAutoConfiguration` 条件化
|
||||||
|
|
||||||
|
文件:`ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsAutoConfiguration.java`
|
||||||
|
|
||||||
|
- 类上新增 `@EnableConfigurationProperties(SmsProperties.class)`。
|
||||||
|
- `smsDao()` 与 `smsExceptionHandler()` 两个 `@Bean` 方法各加 `@ConditionalOnProperty(prefix = "sms", name = "enabled", havingValue = "true")`。
|
||||||
|
|
||||||
|
效果:`sms.enabled=false` 时不创建 `PlusSmsDao`、`SmsExceptionHandler`(对齐 `MailConfig` 关掉后不创建 `MailAccount`)。
|
||||||
|
|
||||||
|
### 4.4 `CaptchaController.smsCode` 调用层判断
|
||||||
|
|
||||||
|
文件:`ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java`
|
||||||
|
|
||||||
|
照搬 `emailCode` / `emailCodeImpl` 的拆分手法:
|
||||||
|
|
||||||
|
1. 类字段注入 `SmsProperties`(与已有的 `MailProperties` 并列)。
|
||||||
|
2. `smsCode(String phonenumber)`:
|
||||||
|
- 保留 `@GetMapping("/resource/sms/code")`。
|
||||||
|
- **移除**方法上的 `@RateLimiter`。
|
||||||
|
- 开头判断 `if (!smsProperties.getEnabled()) return R.fail("当前系统没有开启短信功能!");`。
|
||||||
|
- 否则调用 `SpringUtils.getAopProxy(this).smsCodeImpl(phonenumber);` 并 `return R.ok();`。
|
||||||
|
3. 新增 `smsCodeImpl(String phonenumber)`:
|
||||||
|
- 标注 `@RateLimiter(key = "#phonenumber", time = 60, count = 1)`。
|
||||||
|
- 承载原 `smsCode` 内部的验证码生成、Redis 缓存、`SmsFactory.getSmsBlend("config1").sendMessage(...)` 逻辑。
|
||||||
|
|
||||||
|
> 这样功能关闭时不再消耗限流配额,与 `emailCode` 的实现一致。
|
||||||
|
|
||||||
|
## 5. 不在范围内(YAGNI)
|
||||||
|
|
||||||
|
- 不新建 `SmsUtils` 包装类:现有调用方直接使用 `SmsFactory`,开关不需要它。
|
||||||
|
- 不修改 demo `SmsController`:仅测试用途;如需一致可后续补充。
|
||||||
|
- 不改动 sms4j 自身的自动配置:属于"硬开关"范畴,本次明确排除。
|
||||||
|
|
||||||
|
## 6. 风险与验证(TDD)
|
||||||
|
|
||||||
|
| 风险 | 验证方式 |
|
||||||
|
|---|---|
|
||||||
|
| `sms` 前缀与 sms4j 共存绑定时启动报错 | 启动 Spring 上下文,断言 `SmsProperties.enabled` 能被正确读取 |
|
||||||
|
| 关掉 `PlusSmsDao` 后 sms4j 找不到 `SmsDao` 而崩溃 | `sms.enabled=false` 下上下文正常启动,sms4j 使用默认 in-memory `SmsDao` 兜底 |
|
||||||
|
|
||||||
|
> **`PlusSmsDao` 条件化的回退决策**:实现阶段先验证 sms4j 是否自带默认 `SmsDao`。
|
||||||
|
> - 若**自带默认** `SmsDao`:按设计对 `PlusSmsDao` 加条件化(关掉时用默认兜底)。
|
||||||
|
> - 若**不自带**且启动强依赖 `SmsDao` Bean:则 `PlusSmsDao` **保持无条件注册**(始终提供 Redis 实现),仅对 `SmsExceptionHandler` 加条件化,真正"关掉发送"完全由 4.4 的调用层判断承担。届时回退方案不影响本设计的开关语义(仍是软开关)。
|
||||||
|
| 开关行为不符合预期 | `enabled=false`:无 `PlusSmsDao` Bean + 调用 `/resource/sms/code` 返回"未开启"提示;`enabled=true`:逻辑与现状一致 |
|
||||||
|
|
||||||
|
测试要点:
|
||||||
|
- `sms.enabled=false`:(1) 不存在 `PlusSmsDao` Bean;(2) 调用 `smsCode` 返回失败提示且**不**进入 `smsCodeImpl`;(3) 上下文正常启动。
|
||||||
|
- `sms.enabled=true`:`PlusSmsDao` 存在且为 `@Primary`;`smsCode` 正常进入发送流程(与改动前行为一致)。
|
||||||
|
|
||||||
|
## 7. 影响面
|
||||||
|
|
||||||
|
- 配置:`application-dev.yml`、`application-prod.yml`(`sms:` 节点新增 `enabled`)。
|
||||||
|
- 代码:
|
||||||
|
- 新增 `SmsProperties.java`。
|
||||||
|
- 修改 `SmsAutoConfiguration.java`。
|
||||||
|
- 修改 `CaptchaController.java`(`smsCode` 拆分 + 注入 `SmsProperties`)。
|
||||||
|
- 注册:`SmsAutoConfiguration` 已在 `ruoyi-common-sms` 的 `AutoConfiguration.imports` 中,无需改动;新增的 `SmsProperties` 通过 `@EnableConfigurationProperties` 注册,无需改动 imports。
|
||||||
|
- 兼容性:默认 `false` 与 mail 一致;现有未配置 `sms.enabled` 的环境需显式设置才能开启短信功能。
|
||||||
Loading…
Reference in New Issue
Block a user