短信相关逻辑,仅仅接口状态标记

This commit is contained in:
zk
2026-06-04 17:22:41 +08:00
parent e3ed3e94d4
commit f318e44481
3 changed files with 39 additions and 39 deletions
@@ -26,8 +26,8 @@ public class LoginController {
private LoginService loginService; private LoginService loginService;
@PostMapping("/sms/sendCode") @PostMapping("/sms/sendCode")
public boolean sendCode(@RequestParam @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确") String mobileNumber) { public void sendCode(@RequestParam @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确") String mobileNumber) {
return loginService.sendCode(mobileNumber); loginService.sendCode(mobileNumber);
} }
@PostMapping("/login/smsLogin") @PostMapping("/login/smsLogin")
@@ -66,16 +66,16 @@ public class LoginService {
/** /**
* 发送短信验证码 * 发送短信验证码
* <p>1. 生成6位随机验证码 2. 委托SmsService发送</p> * <p>1. 生成6位随机验证码 2. 委托SmsService发送,失败抛异常</p>
*/ */
public boolean sendCode(String mobileNumber) { public void sendCode(String mobileNumber) {
Assert.hasText(mobileNumber, "手机号不能为空"); Assert.hasText(mobileNumber, "手机号不能为空");
UniversalSmsVariable variable = new UniversalSmsVariable(); UniversalSmsVariable variable = new UniversalSmsVariable();
String code = String.valueOf((int) ((Math.random() * 9 + 1) * 100000)); String code = String.valueOf((int) ((Math.random() * 9 + 1) * 100000));
variable.setCode(code); variable.setCode(code);
return smsService.send(mobileNumber, SmsTemplateEnum.UNIVERSAL, variable); smsService.send(mobileNumber, SmsTemplateEnum.UNIVERSAL, variable);
} }
/** /**
@@ -5,6 +5,8 @@ import lombok.extern.slf4j.Slf4j;
import org.jiayunet.constant.SmsTemplateEnum; import org.jiayunet.constant.SmsTemplateEnum;
import org.jiayunet.constant.sms.SmsVariableAllows; import org.jiayunet.constant.sms.SmsVariableAllows;
import org.jiayunet.constant.sms.UniversalSmsVariable; import org.jiayunet.constant.sms.UniversalSmsVariable;
import org.jiayunet.exception.BusinessException;
import org.jiayunet.exception.BusinessExpCodeEnum;
import org.jiayunet.sms.AliYunSmsAbility; import org.jiayunet.sms.AliYunSmsAbility;
import org.jiayunet.tool.server.RedisServerTool; import org.jiayunet.tool.server.RedisServerTool;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -41,10 +43,9 @@ public class SmsService {
* @param phone 目标手机号,不能为空 * @param phone 目标手机号,不能为空
* @param template 短信模板枚举,必须与 {@code variable} 的类型匹配 * @param template 短信模板枚举,必须与 {@code variable} 的类型匹配
* @param variable 短信参数对象,可能是 {@link UniversalSmsVariable}(验证码)或其他实现 * @param variable 短信参数对象,可能是 {@link UniversalSmsVariable}(验证码)或其他实现
* @return {@code true} 表示短信发送成功,{@code false} 表示发送失败或前置参数校验未通过 * @throws BusinessException 发送失败时抛出业务异常
*/ */
public boolean send(String phone, SmsTemplateEnum template, SmsVariableAllows variable) { public void send(String phone, SmsTemplateEnum template, SmsVariableAllows variable) {
try {
Assert.hasText(phone, "手机号不能为空"); Assert.hasText(phone, "手机号不能为空");
Assert.notNull(template, "短信模板不能为空"); Assert.notNull(template, "短信模板不能为空");
Assert.notNull(variable, "短信参数不能为空"); Assert.notNull(variable, "短信参数不能为空");
@@ -52,21 +53,16 @@ public class SmsService {
// 校验参数类型是否匹配 // 校验参数类型是否匹配
if (!template.getVariableClass().isInstance(variable)) { if (!template.getVariableClass().isInstance(variable)) {
log.error("短信参数类型不匹配: template={}, expectedClass={}, actualClass={}", template.name(), template.getVariableClass().getName(), variable.getClass().getName()); log.error("短信参数类型不匹配: template={}, expectedClass={}, actualClass={}", template.name(), template.getVariableClass().getName(), variable.getClass().getName());
throw new RuntimeException("短信发送失败"); throw new BusinessException(BusinessExpCodeEnum.UNKNOWN_ERROR, "短信发送失败");
} }
// 判断是否激活验证码模式 // 判断是否激活验证码模式
boolean isVerifyMode = isVerifyCodeMode(template, variable); boolean isVerifyMode = isVerifyCodeMode(template, variable);
if (isVerifyMode) { if (isVerifyMode) {
return sendVerifyCode(phone, template, (UniversalSmsVariable) variable); sendVerifyCode(phone, template, (UniversalSmsVariable) variable);
} else { } else {
return sendNormalSms(phone, template, variable); sendNormalSms(phone, template, variable);
}
} catch (Exception e) {
log.error("发送短信异常: phone={}, template={}", phone, template.name(), e);
return false;
} }
} }
@@ -163,7 +159,7 @@ public class SmsService {
return false; return false;
} }
/** /**
* 发送验证码短信。 * 发送验证码短信。
* *
* 在发送前先检查 Redis 中是否已有未过期的验证码,防止重复发送。 * 在发送前先检查 Redis 中是否已有未过期的验证码,防止重复发送。
@@ -172,9 +168,9 @@ public class SmsService {
* @param phone 目标手机号,不能为空 * @param phone 目标手机号,不能为空
* @param template 短信模板枚举,必须包含验证码相关配置(如有效时间) * @param template 短信模板枚举,必须包含验证码相关配置(如有效时间)
* @param variable {@link UniversalSmsVariable},其中必须包含非空的 {@code code} * @param variable {@link UniversalSmsVariable},其中必须包含非空的 {@code code}
* @return {@code true} 表示短信发送及缓存成功,{@code false} 表示发送被拦截或失败 * @throws BusinessException 发送被拦截或失败时抛出业务异常
*/ */
private boolean sendVerifyCode(String phone, SmsTemplateEnum template, UniversalSmsVariable variable) { private void sendVerifyCode(String phone, SmsTemplateEnum template, UniversalSmsVariable variable) {
String key = buildVerifyCodeKey(template, phone); String key = buildVerifyCodeKey(template, phone);
// 检查是否允许重发 // 检查是否允许重发
@@ -185,7 +181,7 @@ public class SmsService {
long elapsedSeconds = template.getEffectiveTime() * 60L - (remainSeconds != null ? remainSeconds : 0L); long elapsedSeconds = template.getEffectiveTime() * 60L - (remainSeconds != null ? remainSeconds : 0L);
if (elapsedSeconds < template.getRetryTime() * 60L) { if (elapsedSeconds < template.getRetryTime() * 60L) {
log.warn("重发间隔未到,请{}分钟后再试: phone={}, template={}", template.getRetryTime(), phone, template.name()); log.warn("重发间隔未到,请{}分钟后再试: phone={}, template={}", template.getRetryTime(), phone, template.name());
throw new RuntimeException("请勿重复发送"); throw new BusinessException(BusinessExpCodeEnum.UNKNOWN_ERROR, "请勿重复发送");
} }
// 已超过重发间隔,允许重新发送,后续会覆盖旧验证码 // 已超过重发间隔,允许重新发送,后续会覆盖旧验证码
} }
@@ -203,30 +199,34 @@ public class SmsService {
variableMap variableMap
); );
if (!success) {
throw new BusinessException(BusinessExpCodeEnum.UNKNOWN_ERROR, "短信发送失败,请稍后重试");
}
// 发送成功后存储验证码 // 发送成功后存储验证码
if (success) {
redisServerTool.set(key, variable.getCode(), template.getEffectiveTime(), TimeUnit.MINUTES); redisServerTool.set(key, variable.getCode(), template.getEffectiveTime(), TimeUnit.MINUTES);
log.info("验证码已存储: phone={}, template={}, effectiveTime={}分钟", log.info("验证码已存储: phone={}, template={}, effectiveTime={}分钟",
phone, template.name(), template.getEffectiveTime()); phone, template.name(), template.getEffectiveTime());
} }
return success;
}
/** /**
* 发送普通短信 * 发送普通短信
*/ */
private boolean sendNormalSms(String phone, SmsTemplateEnum template, SmsVariableAllows variable) { private void sendNormalSms(String phone, SmsTemplateEnum template, SmsVariableAllows variable) {
// 转换参数对象为 Map<String, String> // 转换参数对象为 Map<String, String>
Map<String, String> variableMap = objectMapper.convertValue(variable, new com.fasterxml.jackson.core.type.TypeReference<Map<String, String>>() {}); Map<String, String> variableMap = objectMapper.convertValue(variable, new com.fasterxml.jackson.core.type.TypeReference<Map<String, String>>() {});
// 直接发送短信 // 直接发送短信
return aliYunSmsAbility.sendSms( boolean success = aliYunSmsAbility.sendSms(
phone, phone,
template.getSignName(), template.getSignName(),
template.getTemplateCode(), template.getTemplateCode(),
variableMap variableMap
); );
if (!success) {
throw new BusinessException(BusinessExpCodeEnum.UNKNOWN_ERROR, "短信发送失败,请稍后重试");
}
} }
/** /**