Ver código fonte

优化短信逻辑

woody 1 ano atrás
pai
commit
5dddf2f9f9

+ 31 - 0
framework-base/src/main/java/com/chelvc/framework/base/context/ApplicationContextHolder.java

@@ -316,6 +316,37 @@ public class ApplicationContextHolder implements ApplicationContextAware {
         }
     }
 
+    /**
+     * 获取对象实例
+     *
+     * @param name 对象名称
+     * @param <T>  对象类型泛型
+     * @return 对象实例
+     */
+    public static <T> T getBean(String name) {
+        return getBean(name, true);
+    }
+
+    /**
+     * 获取可以为空的对象实例
+     *
+     * @param name     对象名称
+     * @param required 对象实例是否必须存在
+     * @param <T>      对象类型泛型
+     * @return 对象实例
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T getBean(String name, boolean required) {
+        try {
+            return (T) getApplicationContext().getBean(name);
+        } catch (NoSuchBeanDefinitionException e) {
+            if (required) {
+                throw e;
+            }
+            return null;
+        }
+    }
+
     /**
      * 获取所有application.yml文件资源
      *

+ 1 - 2
framework-sms/src/main/java/com/chelvc/framework/sms/NormalSmsHandler.java

@@ -12,7 +12,6 @@ public interface NormalSmsHandler {
      *
      * @param content 短信内容
      * @param mobiles 手机号数组
-     * @return true/false
      */
-    boolean send(String content, String... mobiles);
+    void send(String content, String... mobiles);
 }

+ 3 - 6
framework-sms/src/main/java/com/chelvc/framework/sms/TemplateSmsHandler.java

@@ -20,9 +20,8 @@ public interface TemplateSmsHandler {
      * @param mobile     手机号
      * @param template   模板标识
      * @param parameters 模版参数
-     * @return true/false
      */
-    boolean send(String mobile, String template, String... parameters);
+    void send(String mobile, String template, String... parameters);
 
     /**
      * 发送短信
@@ -30,9 +29,8 @@ public interface TemplateSmsHandler {
      * @param mobile     手机号
      * @param template   模板标识
      * @param parameters 模版参数
-     * @return true/false
      */
-    boolean send(String mobile, String template, Map<String, ?> parameters);
+    void send(String mobile, String template, Map<String, ?> parameters);
 
     /**
      * 发送短信验证码
@@ -40,7 +38,6 @@ public interface TemplateSmsHandler {
      * @param mobile   手机号
      * @param template 模版标识
      * @param code     验证码
-     * @return true/false
      */
-    boolean sendCaptcha(String mobile, String template, String code);
+    void sendCaptcha(String mobile, String template, String code);
 }

+ 10 - 10
framework-sms/src/main/java/com/chelvc/framework/sms/support/AliyunSmsHandler.java

@@ -34,12 +34,12 @@ public class AliyunSmsHandler implements TemplateSmsHandler {
     private final AliyunSmsProperties properties;
 
     @Override
-    public boolean send(String mobile, String template, String... parameters) {
+    public void send(String mobile, String template, String... parameters) {
         throw new UnsupportedOperationException("Not support method");
     }
 
     @Override
-    public boolean send(@NonNull String mobile, @NonNull String template, @NonNull Map<String, ?> parameters) {
+    public void send(@NonNull String mobile, @NonNull String template, @NonNull Map<String, ?> parameters) {
         String param = JacksonContextHolder.serialize(parameters);
         boolean debug = log.isDebugEnabled();
         if (debug) {
@@ -52,23 +52,23 @@ public class AliyunSmsHandler implements TemplateSmsHandler {
             response = this.client.sendSms(request);
         } catch (Exception e) {
             log.warn("Aliyun sms send failed: {}", e.getMessage());
-            return false;
+            return;
         }
         if (debug) {
             log.debug("Aliyun sms response: {}", JacksonContextHolder.serialize(response));
         }
         SendSmsResponseBody body = response.getBody();
-        if (Objects.equals(body.getCode(), "isv.BUSINESS_LIMIT_CONTROL")) {
-            throw new ResourceUnavailableException(SMS_SEND_FREQUENTLY, body.getMessage());
-        } else if (!Objects.equals(body.getCode(), "OK")) {
+        if (!Objects.equals(body.getCode(), "OK")) {
             log.warn("Aliyun sms send failed: [{}] {}", body.getCode(), body.getMessage());
-            return false;
+            if (Objects.equals(body.getCode(), "isv.BUSINESS_LIMIT_CONTROL")) {
+                throw new ResourceUnavailableException(SMS_SEND_FREQUENTLY, body.getMessage());
+            }
+            throw new ResourceUnavailableException(body.getMessage());
         }
-        return true;
     }
 
     @Override
-    public boolean sendCaptcha(@NonNull String mobile, @NonNull String template, @NonNull String code) {
-        return this.send(mobile, template, ImmutableMap.of("code", code));
+    public void sendCaptcha(@NonNull String mobile, @NonNull String template, @NonNull String code) {
+        this.send(mobile, template, ImmutableMap.of("code", code));
     }
 }

+ 36 - 15
framework-sms/src/main/java/com/chelvc/framework/sms/support/DefaultCaptchaSmsHandler.java

@@ -44,7 +44,6 @@ public class DefaultCaptchaSmsHandler implements CaptchaSmsHandler {
     };
 
     private final CaptchaSmsProperties properties;
-    private final TemplateSmsHandler templateSmsHandler;
     private final RedisTemplate<String, Object> redisTemplate;
 
     /**
@@ -57,12 +56,43 @@ public class DefaultCaptchaSmsHandler implements CaptchaSmsHandler {
         return "sms:token:" + mobile;
     }
 
+    /**
+     * 获取模版短信处理器
+     *
+     * @return 模版短信处理器
+     */
+    private TemplateSmsHandler getTemplateSmsHandler() {
+        return ApplicationContextHolder.getBean(ApplicationContextHolder.getSafeProperty(
+                "platform.sms.captcha.handler", AliyunSmsHandler.class.getName()
+        ));
+    }
+
+    /**
+     * 查找手机号测试验证码
+     *
+     * @param mobile 手机号
+     * @return 验证码
+     */
+    private String lookupTestingCaptcha(String mobile) {
+        List<Captcha> testes = ApplicationContextHolder.getSafeProperty("platform.sms.captcha.test", CAPTCHA_REFERENCE);
+        if (CollectionUtils.isEmpty(testes)) {
+            return null;
+        }
+        return testes.stream().filter(captcha -> Objects.equals(captcha.getMobile(), mobile)).map(Captcha::getCode)
+                .filter(StringUtils::nonEmpty).findFirst().orElse(null);
+    }
+
     @Override
     public SmsSession send(@NonNull String mobile) {
-        String code = String.valueOf(ThreadLocalRandom.current().nextInt(100000, 1000000));
+        // 如果目标手机号属于测试手机号,则直接返回配置的验证码信息,否则获取真实的验证码
+        String test = this.lookupTestingCaptcha(mobile);
+        boolean testing = StringUtils.nonEmpty(test);
+        String code = testing ? test : String.valueOf(ThreadLocalRandom.current().nextInt(100000, 1000000));
         Duration duration = Duration.ofSeconds(this.properties.getInterval());
         return RedisUtils.tryLockAround("sms:interval:" + mobile, duration, () -> {
-            this.templateSmsHandler.sendCaptcha(mobile, this.properties.getTemplate(), code);
+            if (!testing) {
+                this.getTemplateSmsHandler().sendCaptcha(mobile, this.properties.getTemplate(), code);
+            }
             String key = this.key(mobile), token = StringUtils.uuid();
             Captcha captcha = Captcha.builder().token(token).code(code).mobile(mobile).build();
             this.redisTemplate.opsForValue().set(key, captcha, this.properties.getExpiration(), TimeUnit.SECONDS);
@@ -74,15 +104,6 @@ public class DefaultCaptchaSmsHandler implements CaptchaSmsHandler {
 
     @Override
     public Captcha getCaptcha(@NonNull String mobile) {
-        // 如果目标手机号属于测试手机号,则直接返回配置的验证码信息,否则获取真实的验证码
-        List<Captcha> testes = ApplicationContextHolder.getSafeProperty("platform.sms.captcha.test", CAPTCHA_REFERENCE);
-        if (!CollectionUtils.isEmpty(testes)) {
-            Captcha captcha = testes.stream().filter(test -> Objects.equals(test.getMobile(), mobile))
-                    .findFirst().orElse(null);
-            if (captcha != null) {
-                return captcha;
-            }
-        }
         return (Captcha) this.redisTemplate.opsForValue().get(this.key(mobile));
     }
 
@@ -96,14 +117,14 @@ public class DefaultCaptchaSmsHandler implements CaptchaSmsHandler {
     }
 
     @Override
-    public boolean check(String token, @NonNull String mobile, @NonNull String code) {
+    public boolean check(@NonNull String token, @NonNull String mobile, @NonNull String code) {
         Captcha captcha = this.getCaptcha(mobile);
-        return captcha != null && (StringUtils.isEmpty(captcha.getToken()) || Objects.equals(token, captcha.getToken()))
+        return captcha != null && Objects.equals(token, captcha.getToken())
                 && Objects.equals(mobile, captcha.getMobile()) && Objects.equals(code, captcha.getCode());
     }
 
     @Override
-    public boolean validate(String token, @NonNull String mobile, @NonNull String code) {
+    public boolean validate(@NonNull String token, @NonNull String mobile, @NonNull String code) {
         boolean available = this.check(token, mobile, code);
         if (available) {
             this.redisTemplate.delete(this.key(mobile));

+ 11 - 11
framework-sms/src/main/java/com/chelvc/framework/sms/support/TencentTemplateSmsHandler.java → framework-sms/src/main/java/com/chelvc/framework/sms/support/TencentSmsHandler.java

@@ -26,12 +26,12 @@ import org.springframework.stereotype.Component;
 @Component
 @ConditionalOnBean(TencentSmsProperties.class)
 @RequiredArgsConstructor(onConstructor = @__(@Autowired))
-public class TencentTemplateSmsHandler implements TemplateSmsHandler {
+public class TencentSmsHandler implements TemplateSmsHandler {
     private final SmsSingleSender sender;
     private final TencentSmsProperties properties;
 
     @Override
-    public boolean send(@NonNull String mobile, @NonNull String template, @NonNull String... parameters) {
+    public void send(@NonNull String mobile, @NonNull String template, @NonNull String... parameters) {
         boolean debug = log.isDebugEnabled();
         if (debug) {
             log.debug("Tencent sms request: {}, {}", mobile, Arrays.toString(parameters));
@@ -42,27 +42,27 @@ public class TencentTemplateSmsHandler implements TemplateSmsHandler {
                     parameters, this.properties.getSignature(), null, null);
         } catch (Exception e) {
             log.warn("Tencent sms send failed: {}", e.getMessage());
-            return false;
+            return;
         }
         if (debug) {
             log.debug("Tencent sms response: {}", JacksonContextHolder.serialize(result));
         }
-        if (result.result == 1023) {
-            throw new ResourceUnavailableException(SMS_SEND_FREQUENTLY, result.errMsg);
-        } else if (result.result != 0) {
+        if (result.result != 0) {
             log.warn("Tencent sms send failed: [{}] {}", result.result, result.errMsg);
-            return false;
+            if (result.result == 1023) {
+                throw new ResourceUnavailableException(SMS_SEND_FREQUENTLY, result.errMsg);
+            }
+            throw new ResourceUnavailableException(result.errMsg);
         }
-        return true;
     }
 
     @Override
-    public boolean send(String mobile, String template, Map<String, ?> parameters) {
+    public void send(String mobile, String template, Map<String, ?> parameters) {
         throw new UnsupportedOperationException("Not support method");
     }
 
     @Override
-    public boolean sendCaptcha(@NonNull String mobile, @NonNull String template, @NonNull String code) {
-        return this.send(mobile, template, code);
+    public void sendCaptcha(@NonNull String mobile, @NonNull String template, @NonNull String code) {
+        this.send(mobile, template, code);
     }
 }