From b82e78ceb8f52b05203f05eb4b14151b1ab408a2 Mon Sep 17 00:00:00 2001
From: “mitao” <“2763622819@qq.com”>
Date: 星期三, 24 十二月 2025 18:52:23 +0800
Subject: [PATCH] feat:下单功能联调及短信对接

---
 ruoyi-applet/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java |  115 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 101 insertions(+), 14 deletions(-)

diff --git a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
index 59ac191..07efa17 100644
--- a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
+++ b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
@@ -14,6 +14,7 @@
 import com.ruoyi.common.core.redis.RedisCache;
 import com.ruoyi.common.redis.service.RedisService;
 import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.ip.IpUtils;
 import com.ruoyi.framework.web.service.SysLoginService;
 import com.ruoyi.framework.web.service.SysPermissionService;
 import com.ruoyi.framework.web.service.TokenService;
@@ -43,10 +44,11 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
 
 /**
  * 登录验证
- * 
+ *
  * @author ruoyi
  */
 @Slf4j
@@ -80,6 +82,28 @@
     private TAppUserService appUserService;
 
     /**
+     * 手机号正则表达式(11位数字,以1开头)
+     */
+    private static final Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");
+
+    /**
+     * Redis Key 前缀
+     */
+    private static final String SMS_LIMIT_PHONE_KEY = "sms_limit:phone:";
+    private static final String SMS_LIMIT_PHONE_DAILY_KEY = "sms_limit:phone_daily:";
+    private static final String SMS_LIMIT_IP_KEY = "sms_limit:ip:";
+    private static final String SMS_LIMIT_IP_HOURLY_KEY = "sms_limit:ip_hourly:";
+
+    /**
+     * 限制参数
+     */
+    private static final int PHONE_LIMIT_SECONDS = 60;           // 手机号60秒限制
+    private static final int PHONE_DAILY_LIMIT = 10;             // 手机号每日最多10次
+    private static final int PHONE_DAILY_EXPIRE_HOURS = 24;      // 手机号每日限制过期时间
+    private static final int IP_LIMIT_PER_MINUTE = 5;            // IP每分钟最多5次
+    private static final int IP_LIMIT_PER_HOUR = 20;             // IP每小时最多20次
+
+    /**
      * 获取验证码
      *
      * @param phone 手机号
@@ -89,20 +113,83 @@
     @GetMapping("/getCode")
     public AjaxResult getCode(@RequestParam String phone)
     {
-        // 发送验证码并存储到redis
-        if (StringUtils.hasLength(phone)) {
-
-            String code = String.valueOf((int) (Math.random() * 1000000));
-            redisCache.setCacheObject(phone, code,5*60, TimeUnit.SECONDS);
-            try {
-                //TODO 待对接
-//                smsUtil.sendSms(phone, "2369926", new String[]{code});
-            } catch (Exception e) {
-                throw new RuntimeException(e);
-            }
-            return AjaxResult.success("发送短信验证码成功!5分钟内有效");
+        // 1. 校验手机号格式
+        if (!StringUtils.hasLength(phone) || !PHONE_PATTERN.matcher(phone).matches()) {
+            return AjaxResult.error(500, "手机号格式不正确");
         }
-        return AjaxResult.error(500, "发送短信验证码失败,请确认手机号码!");
+
+        // 2. 获取客户端IP
+        String clientIp = IpUtils.getIpAddr();
+
+        // 3. 检查手机号60秒限制
+        String phoneKey = SMS_LIMIT_PHONE_KEY + phone;
+        if (redisCache.hasKey(phoneKey)) {
+            Long ttl = redisCache.getExpire(phoneKey);
+            return AjaxResult.error(500, "请求过于频繁,请" + ttl + "秒后再试");
+        }
+
+        // 4. 检查手机号24小时限制
+        String phoneDailyKey = SMS_LIMIT_PHONE_DAILY_KEY + phone;
+        Integer phoneDailyCount = redisCache.getCacheObject(phoneDailyKey);
+        if (phoneDailyCount != null && phoneDailyCount >= PHONE_DAILY_LIMIT) {
+            return AjaxResult.error(500, "该手机号今日获取验证码次数已达上限");
+        }
+
+        // 5. 检查IP每分钟限制
+        String ipKey = SMS_LIMIT_IP_KEY + clientIp;
+        Integer ipCount = redisCache.getCacheObject(ipKey);
+        if (ipCount != null && ipCount >= IP_LIMIT_PER_MINUTE) {
+            return AjaxResult.error(500, "请求过于频繁,请稍后再试");
+        }
+
+        // 6. 检查IP每小时限制
+        String ipHourlyKey = SMS_LIMIT_IP_HOURLY_KEY + clientIp;
+        Integer ipHourlyCount = redisCache.getCacheObject(ipHourlyKey);
+        if (ipHourlyCount != null && ipHourlyCount >= IP_LIMIT_PER_HOUR) {
+            return AjaxResult.error(500, "请求次数过多,请1小时后再试");
+        }
+
+        // 7. 生成并发送验证码
+        String code = String.valueOf((int) (Math.random() * 900000) + 100000);
+        redisCache.setCacheObject(phone, code, 5 * 60, TimeUnit.SECONDS);
+        try {
+            msgUtils.sendMsg(phone, code);
+        } catch (Exception e) {
+            log.error("发送短信验证码失败,手机号:{},错误:{}", phone, e.getMessage());
+            return AjaxResult.error(500, "发送短信验证码失败,请稍后重试");
+        }
+
+        // 8. 更新限制计数器
+        // 手机号60秒限制
+        redisCache.setCacheObject(phoneKey, 1, PHONE_LIMIT_SECONDS, TimeUnit.SECONDS);
+
+        // 手机号每日限制
+        if (phoneDailyCount == null) {
+            redisCache.setCacheObject(phoneDailyKey, 1, PHONE_DAILY_EXPIRE_HOURS, TimeUnit.HOURS);
+        } else {
+            redisCache.setCacheObject(phoneDailyKey, phoneDailyCount + 1, PHONE_DAILY_EXPIRE_HOURS, TimeUnit.HOURS);
+        }
+
+        // IP每分钟限制
+        if (ipCount == null) {
+            redisCache.setCacheObject(ipKey, 1, 1, TimeUnit.MINUTES);
+        } else {
+            // 保持原有过期时间
+            Long ipTtl = redisCache.getExpire(ipKey);
+            redisCache.setCacheObject(ipKey, ipCount + 1, ipTtl.intValue() > 0 ? ipTtl.intValue() : 60, TimeUnit.SECONDS);
+        }
+
+        // IP每小时限制
+        if (ipHourlyCount == null) {
+            redisCache.setCacheObject(ipHourlyKey, 1, 1, TimeUnit.HOURS);
+        } else {
+            // 保持原有过期时间
+            Long ipHourlyTtl = redisCache.getExpire(ipHourlyKey);
+            redisCache.setCacheObject(ipHourlyKey, ipHourlyCount + 1, ipHourlyTtl.intValue() > 0 ? ipHourlyTtl.intValue() : 3600, TimeUnit.SECONDS);
+        }
+
+        log.info("验证码发送成功,手机号:{},IP:{}", phone, clientIp);
+        return AjaxResult.success("发送短信验证码成功!5分钟内有效");
     }
 
     /**

--
Gitblit v1.7.1