diff --git a/.gitee/ISSUE_TEMPLATE.zh-CN.md b/.gitee/ISSUE_TEMPLATE.zh-CN.md new file mode 100644 index 0000000000000000000000000000000000000000..5abe9d746e94f78baf829c36159867f0e673e7b1 --- /dev/null +++ b/.gitee/ISSUE_TEMPLATE.zh-CN.md @@ -0,0 +1,11 @@ +# 版本信息 (必填): +当前使用的版本(必填):2.0.X 或其它 +JDK 版本(必填) : JDK 8 或其他一定写明至具体的小版本号 + +# 问题描述: + +# 报错截图 + +# 日志信息 + +# 重现步骤 diff --git a/.gitee/ISSUE_TEMPLATE/bug.yml b/.gitee/ISSUE_TEMPLATE/bug.yml new file mode 100644 index 0000000000000000000000000000000000000000..d7b5f9034023bcd1a74a8e987104adfbce73a481 --- /dev/null +++ b/.gitee/ISSUE_TEMPLATE/bug.yml @@ -0,0 +1,76 @@ +name: Bug 反馈 +description: 当你中发现了一个 Bug,导致应用崩溃或抛出异常,或者有一个组件存在问题,或者某些地方看起来不对劲。 +title: "[Bug]: " +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + 感谢对项目的支持与关注。在提出问题之前,请确保您已查看相关开发或使用文档: + - https://wind.kim + - type: checkboxes + attributes: + label: 这个问题是否已经存在? + options: + - label: 我已经搜索过现有的问题 (https://gitee.com/dromara/sms4j/issues) + required: true + - type: textarea + attributes: + label: 如何复现 + description: 请详细告诉我们如何复现你遇到的问题,如涉及代码,可提供一个最小代码示例,并使用反引号```附上它 + placeholder: | + 1. ... + 2. ... + 3. ... + validations: + required: true + - type: textarea + attributes: + label: 错误堆栈 + description: 请将错误堆栈抹除关键信息后贴到这里。 + validations: + required: true + - type: textarea + attributes: + label: 实际结果 + description: 请告诉我们实际发生了什么。 + validations: + required: true + - type: textarea + attributes: + label: 截图或视频 + description: 如果可以的话,上传任何关于 bug 的截图。 + value: | + [在这里上传图片] + - type: dropdown + id: jdk_version + attributes: + label: JDK 版本 + description: 你当前正在使用 JDK 的哪个版本? + options: + - JDK8 + - JDK17 + validations: + required: true + - type: dropdown + id: version + attributes: + label: SMS4J 版本 + description: 你当前正在使用我们软件的哪个版本/分支? + options: + - 3.1.0 + - 3.0.4 + - 3.0.3 + - 3.0.2 + - 3.0.1 + - 3.0.0 + - 2.2.0 + - 2.1.1 + - 2.1.0 + - 2.0.3 + - 2.0.2 + - 2.0.1 + - 2.0.0 + - 1.0.4 + validations: + required: true \ No newline at end of file diff --git a/.gitee/ISSUE_TEMPLATE/config.yml b/.gitee/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000000000000000000000000000000000..3752544c556ff1a64e9c21d92f5e2e2e8cb77c48 --- /dev/null +++ b/.gitee/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: sms4j文档中心 + url: https://wind.kim + about: 提供 sms4j 搭建使用指南、平台基本开发使用方式、介绍、基础知识和常见问题解答 \ No newline at end of file diff --git a/.gitee/ISSUE_TEMPLATE/feature.yml b/.gitee/ISSUE_TEMPLATE/feature.yml new file mode 100644 index 0000000000000000000000000000000000000000..5639dbb071a9ceca067b666e2acd2e349cd64fed --- /dev/null +++ b/.gitee/ISSUE_TEMPLATE/feature.yml @@ -0,0 +1,43 @@ +name: 功能建议 +description: 对本项目提出一个功能建议 +title: "[功能建议]: " +labels: ["enhancement"] +body: + - type: markdown + attributes: + value: | + 感谢提出功能建议,我们将仔细考虑!请持续关注该issues,在加入计划后我们会有贡献者设置为负责人,同时状态成为进行中。 + - type: textarea + id: related-problem + attributes: + label: 你的功能建议是否和某个问题相关? + description: 清晰并简洁地描述问题是什么,例如,当我...时,我总是感到困扰。 + validations: + required: false + - type: textarea + id: desired-solution + attributes: + label: 你希望看到什么解决方案? + description: 清晰并简洁地描述你希望发生的事情。 + validations: + required: true + - type: textarea + id: alternatives + attributes: + label: 你考虑过哪些替代方案? + description: 清晰并简洁地描述你考虑过的任何替代解决方案或功能。 + validations: + required: false + - type: textarea + id: additional-context + attributes: + label: 你有其他上下文或截图吗? + description: 在此处添加有关功能请求的任何其他上下文或截图。 + validations: + required: false + - type: checkboxes + attributes: + label: 意向参与贡献 + options: + - label: 我有意向参与具体功能的开发实现并将代码贡献回到上游社区 + required: false \ No newline at end of file diff --git a/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md b/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md new file mode 100644 index 0000000000000000000000000000000000000000..e2e5f78bdd0dfa1a19c921ea435091e9c9212210 --- /dev/null +++ b/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md @@ -0,0 +1,10 @@ +### 相关的Issue(注意: 请提交到版本对应的dev分支) + + +### 原因(目的、解决的问题等) + + +### 描述(做了什么,变更了什么) + + +### 测试用例(新增、改动、可能影响的功能) \ No newline at end of file diff --git a/.idea/icon.png b/.idea/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8a364cd7d5a65afec1e2c3b3417320d67cf0e9ea Binary files /dev/null and b/.idea/icon.png differ diff --git a/.workflow/branch-pipeline.yml b/.workflow/branch-pipeline.yml new file mode 100644 index 0000000000000000000000000000000000000000..9d2a2926f31b55f68083a3cb58c4cb6d6f43a07f --- /dev/null +++ b/.workflow/branch-pipeline.yml @@ -0,0 +1,53 @@ +version: '1.0' +name: branch-pipeline +displayName: BranchPipeline +stages: + - stage: + name: compile + displayName: 编译 + steps: + - step: build@maven + name: build_maven + displayName: Maven 构建 + # 支持6、7、8、9、10、11六个版本 + jdkVersion: 8 + # 支持2.2.1、3.2.5、3.3.9、3.5.2、3.5.3、3.5.4、3.6.1、3.6.3八个版本 + mavenVersion: 3.3.9 + # 构建命令 + commands: + - mvn -B clean package -Dmaven.test.skip=true + # 非必填字段,开启后表示将构建产物暂存,但不会上传到制品库中,7天后自动清除 + artifacts: + # 构建产物名字,作为产物的唯一标识可向下传递,支持自定义,默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址 + - name: BUILD_ARTIFACT + # 构建产物获取路径,是指代码编译完毕之后构建物的所在路径,如通常jar包在target目录下。当前目录为代码库根目录 + path: + - ./target + - step: publish@general_artifacts + name: publish_general_artifacts + displayName: 上传制品 + # 上游构建任务定义的产物名,默认BUILD_ARTIFACT + dependArtifact: BUILD_ARTIFACT + # 上传到制品库时的制品命名,默认output + artifactName: output + dependsOn: build_maven + - stage: + name: release + displayName: 发布 + steps: + - step: publish@release_artifacts + name: publish_release_artifacts + displayName: '发布' + # 上游上传制品任务的产出 + dependArtifact: output + # 发布制品版本号 + version: '1.0.0.0' + # 是否开启版本号自增,默认开启 + autoIncrement: true +triggers: + push: + branches: + exclude: + - master + include: + - .* diff --git a/.workflow/master-pipeline.yml b/.workflow/master-pipeline.yml new file mode 100644 index 0000000000000000000000000000000000000000..5d926c26f79e41d10427f87bf003ef99fe2fbd79 --- /dev/null +++ b/.workflow/master-pipeline.yml @@ -0,0 +1,51 @@ +version: '1.0' +name: master-pipeline +displayName: MasterPipeline +stages: + - stage: + name: compile + displayName: 编译 + steps: + - step: build@maven + name: build_maven + displayName: Maven 构建 + # 支持6、7、8、9、10、11六个版本 + jdkVersion: 8 + # 支持2.2.1、3.2.5、3.3.9、3.5.2、3.5.3、3.5.4、3.6.1、3.6.3八个版本 + mavenVersion: 3.3.9 + # 构建命令 + commands: + - mvn -B clean package -Dmaven.test.skip=true + # 非必填字段,开启后表示将构建产物暂存,但不会上传到制品库中,7天后自动清除 + artifacts: + # 构建产物名字,作为产物的唯一标识可向下传递,支持自定义,默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址 + - name: BUILD_ARTIFACT + # 构建产物获取路径,是指代码编译完毕之后构建物的所在路径,如通常jar包在target目录下。当前目录为代码库根目录 + path: + - ./target + - step: publish@general_artifacts + name: publish_general_artifacts + displayName: 上传制品 + # 上游构建任务定义的产物名,默认BUILD_ARTIFACT + dependArtifact: BUILD_ARTIFACT + # 上传到制品库时的制品命名,默认output + artifactName: output + dependsOn: build_maven + - stage: + name: release + displayName: 发布 + steps: + - step: publish@release_artifacts + name: publish_release_artifacts + displayName: '发布' + # 上游上传制品任务的产出 + dependArtifact: output + # 发布制品版本号 + version: '1.0.0.0' + # 是否开启版本号自增,默认开启 + autoIncrement: true +triggers: + push: + branches: + include: + - master diff --git a/.workflow/pr-pipeline.yml b/.workflow/pr-pipeline.yml new file mode 100644 index 0000000000000000000000000000000000000000..3f7579dd405c85f97f77df0357ec4893e616f85f --- /dev/null +++ b/.workflow/pr-pipeline.yml @@ -0,0 +1,40 @@ +version: '1.0' +name: pr-pipeline +displayName: PRPipeline +stages: + - stage: + name: compile + displayName: 编译 + steps: + - step: build@maven + name: build_maven + displayName: Maven 构建 + # 支持6、7、8、9、10、11六个版本 + jdkVersion: 8 + # 支持2.2.1、3.2.5、3.3.9、3.5.2、3.5.3、3.5.4、3.6.1、3.6.3八个版本 + mavenVersion: 3.3.9 + # 构建命令 + commands: + - mvn -B clean package -Dmaven.test.skip=true + # 非必填字段,开启后表示将构建产物暂存,但不会上传到制品库中,7天后自动清除 + artifacts: + # 构建产物名字,作为产物的唯一标识可向下传递,支持自定义,默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址 + - name: BUILD_ARTIFACT + # 构建产物获取路径,是指代码编译完毕之后构建物的所在路径,如通常jar包在target目录下。当前目录为代码库根目录 + path: + - ./target + - step: publish@general_artifacts + name: publish_general_artifacts + displayName: 上传制品 + # 上游构建任务定义的产物名,默认BUILD_ARTIFACT + dependArtifact: BUILD_ARTIFACT + # 构建产物制品库,默认default,系统默认创建 + artifactRepository: default + # 上传到制品库时的制品命名,默认output + artifactName: output + dependsOn: build_maven +triggers: + pr: + branches: + include: + - master diff --git a/README.md b/README.md index 63cd6c0465aa1ebe38d06894bac23855e9c06fe3..5a7d7ecdde9537621c9a8d0de3297fa090237bca 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ [gitee](https://gitee.com/dromara/sms4j) [github](https://github.com/dromara/sms4j) -#### [官方文档](http://wind.kim) +#### [官方文档](http://sms4j.com) #### [JavaDoc文档](https://apidoc.gitee.com/dromara/sms4j/) ## 支持厂商一览 diff --git a/sms4j-api/src/main/java/org/dromara/sms4j/api/SmsBlend.java b/sms4j-api/src/main/java/org/dromara/sms4j/api/SmsBlend.java index 3141103df53aeab346199a44c7be4a509f72b75d..221446ea03bde902fee21b3bccb190abda02055f 100644 --- a/sms4j-api/src/main/java/org/dromara/sms4j/api/SmsBlend.java +++ b/sms4j-api/src/main/java/org/dromara/sms4j/api/SmsBlend.java @@ -3,6 +3,7 @@ package org.dromara.sms4j.api; import org.dromara.sms4j.api.callback.CallBack; import org.dromara.sms4j.api.entity.SmsResponse; +import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; @@ -202,4 +203,23 @@ public interface SmsBlend { */ default void batchRemovalFromBlacklist(List phones) { } + + /** + *

说明:获取黑名单命中记录【为了sms4j组件有统一入口,同时这个需要有全局操作的同时需要操作缓存,那么不给smsblend实际处理,代理部分处理】 + * getTriggerRecording + * + * @author :sh1yu + */ + default List getTriggerRecord() { + return new ArrayList<>(); + } + + /** + *

说明:清理黑名单命中记录【为了sms4j组件有统一入口,同时这个需要有全局操作的同时需要操作缓存,那么不给smsblend实际处理,代理部分处理】 + * clearTriggerRecording + * + * @author :sh1yu + */ + default void clearTriggerRecord() { + } } diff --git a/sms4j-api/src/main/java/org/dromara/sms4j/api/manage/InterceptorStrategySmsManager.java b/sms4j-api/src/main/java/org/dromara/sms4j/api/manage/InterceptorStrategySmsManager.java new file mode 100644 index 0000000000000000000000000000000000000000..7b5066541f6c56631e1f7b7219e519197c92e71b --- /dev/null +++ b/sms4j-api/src/main/java/org/dromara/sms4j/api/manage/InterceptorStrategySmsManager.java @@ -0,0 +1,111 @@ +package org.dromara.sms4j.api.manage; + +import lombok.Getter; +import org.dromara.sms4j.api.dao.SmsDao; +import org.dromara.sms4j.api.dao.SmsDaoDefaultImpl; +import org.dromara.sms4j.api.proxy.aware.InterceptorStrategySmsBlendConfigAware; +import org.dromara.sms4j.api.proxy.aware.InterceptorStrategySmsConfigAware; +import org.dromara.sms4j.api.proxy.aware.InterceptorStrategySmsDaoAware; +import org.dromara.sms4j.api.strategy.IInterceptorStrategy; + +import java.util.HashMap; +import java.util.Map; + + +/* + * Sms主要组件管理 + * + * */ +public abstract class InterceptorStrategySmsManager { + + //拦截器策略映射关系 + private static final HashMap, IInterceptorStrategy> interceptorStrategyMap = new HashMap<>(); + + private static boolean forzen = false; + + //sms全局配置 + @Getter + private static Object smsConfig; + + //所有厂商配置 + @Getter + private static Map> blends; + + //缓存配置 + private static SmsDao smsDao; + + //获取缓存实现 + public static SmsDao getSmsDao() { + return InterceptorStrategySmsManager.smsDao; + } + + /* + * 设置缓存实现,若初始化阶段已过,再调用此方法会抛出异常 + * */ + public static void setSmsDao(SmsDao smsDao) { + checkStatus(); + if (null == smsDao) { + InterceptorStrategySmsManager.smsDao = SmsDaoDefaultImpl.getInstance(); + return; + } + InterceptorStrategySmsManager.smsDao = smsDao; + } + + /* + * 设置全局配置,若初始化阶段已过,再调用此方法会抛出异常 + * */ + public static void setSmsConfig(Object smsConfig) { + checkStatus(); + InterceptorStrategySmsManager.smsConfig = smsConfig; + } + + + /* + * 设置各渠道配置,若初始化阶段已过,再调用此方法会抛出异常 + * */ + public static void setBlends(Map> blends) { + checkStatus(); + if (null == blends) { + InterceptorStrategySmsManager.blends = new HashMap<>(); + return; + } + InterceptorStrategySmsManager.blends = blends; + } + + /* + * 添加一个拦截器和执行策略的映射 + * */ + public static void setInterceptorStrategyMapping(IInterceptorStrategy strategy) { + awareTransfer(strategy); + interceptorStrategyMap.put(strategy.aPendingProblemWith(), strategy); + } + + private static void awareTransfer(IInterceptorStrategy strategy) { + if (strategy instanceof InterceptorStrategySmsDaoAware) { + ((InterceptorStrategySmsDaoAware) strategy).setSmsDao(InterceptorStrategySmsManager.getSmsDao()); + } + if (strategy instanceof InterceptorStrategySmsConfigAware) { + ((InterceptorStrategySmsConfigAware) strategy).setSmsConfig(InterceptorStrategySmsManager.getSmsConfig()); + } + if (strategy instanceof InterceptorStrategySmsBlendConfigAware) { + ((InterceptorStrategySmsBlendConfigAware) strategy).setSmsBlendsConfig(InterceptorStrategySmsManager.getBlends()); + } + } + + /* + * 根据拦截器类型获取一个执行策略 + * */ + public static IInterceptorStrategy getStrategyByProblemClass(Class clazz) { + return interceptorStrategyMap.get(clazz); + } + + private static void checkStatus() { + if (forzen) { + throw new RuntimeException("初始化后不可以更改SMS4J的组件实现引用"); + } + } + + public static void freezes() { + forzen = true; + } +} diff --git a/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/AbstractGenericMethodInterceptor.java b/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/AbstractGenericMethodInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..71e119eff2a05da0a2787018c93fb060db972255 --- /dev/null +++ b/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/AbstractGenericMethodInterceptor.java @@ -0,0 +1,472 @@ +package org.dromara.sms4j.api.proxy; + +import org.dromara.sms4j.api.callback.CallBack; +import org.dromara.sms4j.api.strategy.IInterceptorStrategy; + +import java.lang.reflect.Method; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Objects; + +/** + * {@link SmsMethodInterceptor}的通用实现, + * 能够根据{@link SmsMethodType}将调用分发到某个具体的拦截方法上。 + * + * @author sh1yu + * @since 2023/10/27 13:03 + */ +public abstract class AbstractGenericMethodInterceptor implements SmsMethodInterceptor { + + /** + * 前置拦截,在方法执行前调用 interceptor尽量仅作分发,使用 IInterceptorStrategy 进行具体处理 + * + * @param methodType 方法类型,若不是{@link SmsMethodType}则可能为{@code null} + * @param method 方法 + * @param target 调用对象 + * @param params 调用参数 + * @return 调用参数 + * @implNote 若重写此方法,则务必调用{@link #doBeforeInvoke}方法实现调用分发 + */ + @Override + public Object[] beforeInvoke(SmsMethodType methodType, Method method, Object target, Object[] params) { + if (Objects.nonNull(methodType)) { + // 将方法分发到具体的调用 + doBeforeInvoke(params, methodType); + } + return params; + } + + @SuppressWarnings("unchecked") + protected final void doBeforeInvoke(Object[] params, SmsMethodType methodType) { + Objects.requireNonNull(methodType); + switch (methodType) { + case SEND_MESSAGE: + beforeSendMessage((String)params[0], (String)params[1]); + break; + case SEND_MESSAGE_WITH_TEMPLATE: + beforeSendMessageWithTemplate((String)params[0], (LinkedHashMap)params[1]); + break; + case SEND_MESSAGE_WITH_CUSTOM_TEMPLATE: + beforeSendMessageWithCustomTemplate((String)params[0], (String)params[1], (LinkedHashMap)params[2]); + break; + case MASS_TEXTING: + beforeMassTexting((List)params[0], (String)params[1]); + break; + case MASS_TEXTING_WITH_TEMPLATE: + beforeMassTextingWithTemplate((List)params[0], (String)params[1], (LinkedHashMap)params[2]); + break; + case SEND_MESSAGE_ASYNC: + beforeSendMessageAsync((String)params[0], (String)params[1], (CallBack)params[2]); + break; + case SEND_MESSAGE_ASYNC_NO_CALLBACK: + beforeSendMessageAsyncNoCallback((String)params[0], (String)params[1]); + break; + case SEND_MESSAGE_ASYNC_WITH_TEMPLATE: + beforeSendMessageAsyncWithTemplate((String)params[0], (String)params[1], (LinkedHashMap)params[2], (CallBack)params[3]); + break; + case SEND_MESSAGE_ASYNC_WITH_TEMPLATE_NO_CALLBACK: + beforeSendMessageAsyncWithTemplateNoCallback((String)params[0], (String)params[1], (LinkedHashMap)params[2]); + break; + case DELAYED_MESSAGE: + beforeDelayedMessage((String)params[0], (String)params[1], (Long)params[2]); + break; + case DELAYED_MESSAGE_WITH_TEMPLATE: + beforeDelayedMessageWithTemplate((String)params[0], (String)params[1], (LinkedHashMap)params[2], (Long)params[3]); + break; + case DELAY_MASS_TEXTING: + beforeDelayMassTexting((List)params[0], (String)params[1], (Long)params[2]); + break; + case DELAY_MASS_TEXTING_WITH_TEMPLATE: + beforeDelayMassTextingWithTemplate((List)params[0], (String)params[1], (LinkedHashMap)params[2], (Long)params[3]); + break; + default: // do nothing + } + } + + /** + * 后置拦截,在方法执行后,无论是否发生异常都会调用 + * + * @param methodType 方法类型,若不是{@link SmsMethodType}则可能为{@code null} + * @param method 调用方法 + * @param params 调用参数 + * @param result 返回值 + * @param ex 调用过程捕获的异常,可能为{@code null} + * @return 返回值,不为{@code null}时将覆盖原有的返回值 + * @implNote 若重写此方法,则务必调用{@link ##doAfterCompletion}方法实现调用分发 + */ + @Override + public Object afterCompletion(SmsMethodType methodType, Method method, Object target,Object[] params, Object result, Exception ex) { + if (Objects.nonNull(methodType)) { + // 将方法分发到具体调用... + doAfterCompletion(params, result, ex, methodType); + } + return result; + } + + @SuppressWarnings("unchecked") + private void doAfterCompletion(Object[] params, Object result, Exception ex, SmsMethodType methodType) { + Objects.requireNonNull(methodType); + switch (methodType) { + case SEND_MESSAGE: + afterSendMessage((String)params[0], (String)params[1], result, ex); + break; + case SEND_MESSAGE_WITH_TEMPLATE: + afterSendMessageWithTemplate((String)params[0], (LinkedHashMap)params[1], result, ex); + break; + case SEND_MESSAGE_WITH_CUSTOM_TEMPLATE: + afterSendMessageWithCustomTemplate((String)params[0], (String)params[1], (LinkedHashMap)params[2], result, ex); + break; + case MASS_TEXTING: + afterMassTexting((List)params[0], (String)params[1], result, ex); + break; + case MASS_TEXTING_WITH_TEMPLATE: + afterMassTextingWithTemplate((List)params[0], (String)params[1], (LinkedHashMap)params[2], result, ex); + break; + case SEND_MESSAGE_ASYNC: + afterSendMessageAsync((String)params[0], (String)params[1], (CallBack)params[2], result, ex); + break; + case SEND_MESSAGE_ASYNC_NO_CALLBACK: + afterSendMessageAsyncNoCallback((String)params[0], (String)params[1], result, ex); + break; + case SEND_MESSAGE_ASYNC_WITH_TEMPLATE: + afterSendMessageAsyncWithTemplate((String)params[0], (String)params[1], (LinkedHashMap)params[2], (CallBack)params[3], result, ex); + break; + case SEND_MESSAGE_ASYNC_WITH_TEMPLATE_NO_CALLBACK: + afterSendMessageAsyncWithTemplateNoCallback((String)params[0], (String)params[1], (LinkedHashMap)params[2], result, ex); + break; + case DELAYED_MESSAGE: + afterDelayedMessage((String)params[0], (String)params[1], (Long)params[2], result, ex); + break; + case DELAYED_MESSAGE_WITH_TEMPLATE: + afterDelayedMessageWithTemplate((String)params[0], (String)params[1], (LinkedHashMap)params[2], (Long)params[3], result, ex); + break; + case DELAY_MASS_TEXTING: + afterDelayMassTexting((List)params[0], (String)params[1], (Long)params[2], result, ex); + break; + case DELAY_MASS_TEXTING_WITH_TEMPLATE: + afterDelayMassTextingWithTemplate((List)params[0], (String)params[1], (LinkedHashMap)params[2], (Long)params[3], result, ex); + break; + default: // do nothing + } + } + + // region ===== before ===== + + /** + * {@link org.dromara.sms4j.api.SmsBlend#sendMessage(String, String)} + * + * @param phone 接收短信的手机号 + * @param message 内容 + */ + protected void beforeSendMessage(String phone, String message) { + // do nothing + } + + /** + * {@link org.dromara.sms4j.api.SmsBlend#sendMessage(String, LinkedHashMap)} + * + * @param phone 接收短信的手机号 + * @param messages 模板内容 + */ + protected void beforeSendMessageWithTemplate(String phone, LinkedHashMap messages) { + // do nothing + } + + /** + * {@link org.dromara.sms4j.api.SmsBlend#sendMessage(String, String, LinkedHashMap)} + * + * @param phone 接收短信的手机号 + * @param templateId 模板ID + * @param messages 内容 + */ + protected void beforeSendMessageWithCustomTemplate( + String phone, String templateId, LinkedHashMap messages) { + // do nothing + } + + /** + * {@link org.dromara.sms4j.api.SmsBlend#massTexting(List, String)} + * + * @param phones 接收短信的手机号 + * @param message 内容 + */ + protected void beforeMassTexting(List phones, String message) { + // do nothing + } + + /** + * {@link org.dromara.sms4j.api.SmsBlend#massTexting(List, String, LinkedHashMap)} + * + * @param phones 接收短信的手机号 + * @param templateId 模板ID + * @param messages 内容 + */ + protected void beforeMassTextingWithTemplate( + List phones, String templateId, LinkedHashMap messages) { + // do nothing + } + + /** + * 前置处理 {@link org.dromara.sms4j.api.SmsBlend#sendMessageAsync(String, String, CallBack)} + * + * @param phone 接收短信的手机号 + * @param message 内容 + * @param callBack 回调 + */ + protected void beforeSendMessageAsync(String phone, String message, CallBack callBack) { + // do nothing + } + + /** + * 前置处理 {@link org.dromara.sms4j.api.SmsBlend#sendMessageAsync(String, String)} + * + * @param phone 接收短信的手机号 + * @param message 内容 + */ + protected void beforeSendMessageAsyncNoCallback(String phone, String message) { + // do nothing + } + + /** + * 前置处理 {@link org.dromara.sms4j.api.SmsBlend#sendMessageAsync(String, String, LinkedHashMap, CallBack)} + * + * @param phone 接收短信的手机号 + * @param message 内容 + * @param template 模板 + * @param callBack 回调 + */ + protected void beforeSendMessageAsyncWithTemplate(String phone, String message, LinkedHashMap template, CallBack callBack) { + // do nothing + } + + /** + * 前置处理 {@link org.dromara.sms4j.api.SmsBlend#sendMessageAsync(String, String, LinkedHashMap)} + * + * @param phone 接收短信的手机号 + * @param message 内容 + * @param template 模板 + */ + protected void beforeSendMessageAsyncWithTemplateNoCallback(String phone, String message, LinkedHashMap template) { + // do nothing + } + + /** + * 前置处理 {@link org.dromara.sms4j.api.SmsBlend#delayedMessage(String, String, Long)} + * + * @param phone 接收短信的手机号 + * @param message 内容 + * @param delay 延迟时间 + */ + protected void beforeDelayedMessage(String phone, String message, Long delay) { + // do nothing + } + + /** + * 前置处理 {@link org.dromara.sms4j.api.SmsBlend#delayedMessage(String, String, LinkedHashMap, Long)} + * + * @param phone 接收短信的手机号 + * @param message 内容 + * @param template 模板 + * @param delay 延迟时间 + */ + protected void beforeDelayedMessageWithTemplate(String phone, String message, LinkedHashMap template, Long delay) { + // do nothing + } + + /** + * 前置处理 {@link org.dromara.sms4j.api.SmsBlend#delayMassTexting(List, String, Long)} + * + * @param phones 接收短信的手机号 + * @param message 内容 + * @param delay 延迟时间 + */ + protected void beforeDelayMassTexting(List phones, String message, Long delay) { + // do nothing + } + + /** + * 前置处理 {@link org.dromara.sms4j.api.SmsBlend#delayMassTexting(List, String, LinkedHashMap, Long)} + * + * @param phones 接收短信的手机号 + * @param message 内容 + * @param template 模板 + * @param delay 延迟时间 + */ + protected void beforeDelayMassTextingWithTemplate(List phones, String message, LinkedHashMap template, Long delay) { + // do nothing + } + + // endregion + + // region ===== after ===== + + /** + * 后置处理 {@link org.dromara.sms4j.api.SmsBlend#sendMessage(String, String)} + * + * @param phone 接收短信的手机号 + * @param message 内容 + * @param result 方法返回值 + * @param ex 异常信息 + */ + protected void afterSendMessage(String phone, String message, Object result, Exception ex) { + // do nothing + } + + /** + * 后置处理 {@link org.dromara.sms4j.api.SmsBlend#sendMessage(String, LinkedHashMap)} + * + * @param phone 接收短信的手机号 + * @param messages 模板内容 + * @param result 方法返回值 + * @param ex 异常信息 + */ + protected void afterSendMessageWithTemplate(String phone, LinkedHashMap messages, Object result, Exception ex) { + // do nothing + } + + /** + * 后置处理 {@link org.dromara.sms4j.api.SmsBlend#sendMessage(String, String, LinkedHashMap)} + * + * @param phone 接收短信的手机号 + * @param templateId 模板ID + * @param messages 内容 + * @param result 方法返回值 + * @param ex 异常信息 + */ + protected void afterSendMessageWithCustomTemplate(String phone, String templateId, LinkedHashMap messages, Object result, Exception ex) { + // do nothing + } + + /** + * 后置处理 {@link org.dromara.sms4j.api.SmsBlend#massTexting(List, String)} + * + * @param phones 接收短信的手机号 + * @param message 内容 + * @param result 方法返回值 + * @param ex 异常信息 + */ + protected void afterMassTexting(List phones, String message, Object result, Exception ex) { + // do nothing + } + + /** + * 后置处理 {@link org.dromara.sms4j.api.SmsBlend#massTexting(List, String, LinkedHashMap)} + * + * @param phones 接收短信的手机号 + * @param templateId 模板ID + * @param messages 内容 + * @param result 方法返回值 + * @param ex 异常信息 + */ + protected void afterMassTextingWithTemplate(List phones, String templateId, LinkedHashMap messages, Object result, Exception ex) { + // do nothing + } + + /** + * 后置处理 {@link org.dromara.sms4j.api.SmsBlend#sendMessageAsync(String, String, CallBack)} + * + * @param phone 接收短信的手机号 + * @param message 内容 + * @param callBack 回调 + * @param result 方法返回值 + * @param ex 异常信息 + */ + protected void afterSendMessageAsync(String phone, String message, CallBack callBack, Object result, Exception ex) { + // do nothing + } + + /** + * 后置处理 {@link org.dromara.sms4j.api.SmsBlend#sendMessageAsync(String, String)} + * + * @param phone 接收短信的手机号 + * @param message 内容 + * @param result 方法返回值 + * @param ex 异常信息 + */ + protected void afterSendMessageAsyncNoCallback(String phone, String message, Object result, Exception ex) { + // do nothing + } + + /** + * 后置处理 {@link org.dromara.sms4j.api.SmsBlend#sendMessageAsync(String, String, LinkedHashMap, CallBack)} + * + * @param phone 接收短信的手机号 + * @param message 内容 + * @param template 模板 + * @param callBack 回调 + * @param result 方法返回值 + * @param ex 异常信息 + */ + protected void afterSendMessageAsyncWithTemplate(String phone, String message, LinkedHashMap template, CallBack callBack, Object result, Exception ex) { + // do nothing + } + + /** + * 后置处理 {@link org.dromara.sms4j.api.SmsBlend#sendMessageAsync(String, String, LinkedHashMap)} + * + * @param phone 接收短信的手机号 + * @param message 内容 + * @param template 模板 + * @param result 方法返回值 + * @param ex 异常信息 + */ + protected void afterSendMessageAsyncWithTemplateNoCallback(String phone, String message, LinkedHashMap template, Object result, Exception ex) { + // do nothing + } + + /** + * 后置处理 {@link org.dromara.sms4j.api.SmsBlend#delayedMessage(String, String, Long)} + * + * @param phone 接收短信的手机号 + * @param message 内容 + * @param delay 延迟时间 + * @param result 方法返回值 + * @param ex 异常信息 + */ + protected void afterDelayedMessage(String phone, String message, Long delay, Object result, Exception ex) { + // do nothing + } + + /** + * 后置处理 {@link org.dromara.sms4j.api.SmsBlend#delayedMessage(String, String, LinkedHashMap, Long)} + * + * @param phone 接收短信的手机号 + * @param message 内容 + * @param template 模板 + * @param delay 延迟时间 + * @param result 方法返回值 + * @param ex 异常信息 + */ + protected void afterDelayedMessageWithTemplate(String phone, String message, LinkedHashMap template, Long delay, Object result, Exception ex) { + // do nothing + } + + /** + * 后置处理 {@link org.dromara.sms4j.api.SmsBlend#delayMassTexting(List, String, Long)} + * + * @param phones 接收短信的手机号 + * @param message 内容 + * @param delay 延迟时间 + * @param result 方法返回值 + * @param ex 异常信息 + */ + protected void afterDelayMassTexting(List phones, String message, Long delay, Object result, Exception ex) { + // do nothing + } + + /** + * 后置处理 {@link org.dromara.sms4j.api.SmsBlend#delayMassTexting(List, String, LinkedHashMap, Long)} + * + * @param phones 接收短信的手机号 + * @param message 内容 + * @param template 模板 + * @param delay 延迟时间 + * @param result 方法返回值 + * @param ex 异常信息 + */ + protected void afterDelayMassTextingWithTemplate(List phones, String message, LinkedHashMap template, Long delay, Object result, Exception ex) { + // do nothing + } + + // endregion +} diff --git a/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/CoreMethodProcessor.java b/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/CoreMethodProcessor.java deleted file mode 100644 index 2f0d1cbe63353cfd88dfaec2e0c6a4c46b0dd9a9..0000000000000000000000000000000000000000 --- a/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/CoreMethodProcessor.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.dromara.sms4j.api.proxy; - -import org.dromara.sms4j.comm.constant.NumberOfParasmeters; - -import java.lang.reflect.Method; -import java.util.LinkedHashMap; -import java.util.List; -/** - * 核心方法执行器接口 - * - * @author sh1yu - * @since 2023/10/27 13:03 - */ -public interface CoreMethodProcessor extends SmsProcessor { - @Override - default Object[] preProcessor(Method method, Object source, Object[] param) { - String name = method.getName(); - int parameterCount = method.getParameterCount(); - if ("sendMessage".equals(name)) { - if (NumberOfParasmeters.TWO == NumberOfParasmeters.getNumberOfParasmetersEnum(parameterCount)) { - sendMessagePreProcess((String) param[0], param[1]); - return param; - } - if (NumberOfParasmeters.THREE == NumberOfParasmeters.getNumberOfParasmetersEnum(parameterCount)) { - sendMessageByTemplatePreProcess((String)param[0],(String) param[1],(LinkedHashMap)param[2]); - return param; - } - } - if ("massTexting".equals(name)) { - if (NumberOfParasmeters.TWO == NumberOfParasmeters.getNumberOfParasmetersEnum(parameterCount)) { - massTextingPreProcess((List)param[0],(String)param[1]); - return param; - } - if (NumberOfParasmeters.THREE == NumberOfParasmeters.getNumberOfParasmetersEnum(parameterCount)) { - massTextingByTemplatePreProcess((List)param[0],(String)param[1],(LinkedHashMap)param[2]); - return param; - } - } - return param; - } - void sendMessagePreProcess(String phone, Object message); - void sendMessageByTemplatePreProcess(String phone, String templateId, LinkedHashMap messages); - void massTextingPreProcess(List phones, String message); - void massTextingByTemplatePreProcess(List phones, String templateId, LinkedHashMap messages); -} diff --git a/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/Order.java b/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/Order.java index c6b49e91bb1a3b3054729288786e82b030984941..c12364e08c92661324ec06777d9543ef96818a5a 100644 --- a/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/Order.java +++ b/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/Order.java @@ -1,4 +1,5 @@ package org.dromara.sms4j.api.proxy; + /** * 排序接口 * @@ -6,7 +7,13 @@ package org.dromara.sms4j.api.proxy; * @since 2023/10/27 13:03 */ public interface Order { - default public int getOrder(){ - return 999; + + /** + * 获取排序值,排序值越大的对象则优先级越低 + * + * @return 排序值 + */ + default int getOrder(){ + return Integer.MAX_VALUE; } } diff --git a/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/Restricted.java b/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/Restricted.java new file mode 100644 index 0000000000000000000000000000000000000000..1234a0aec696c543dd2daf10c2b4ee7df520a263 --- /dev/null +++ b/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/Restricted.java @@ -0,0 +1,4 @@ +package org.dromara.sms4j.api.proxy; + +public interface Restricted { +} diff --git a/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/SmsMethodInterceptor.java b/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/SmsMethodInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..761b27806976d0d835986ccea33c80c470f2ca2d --- /dev/null +++ b/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/SmsMethodInterceptor.java @@ -0,0 +1,53 @@ +package org.dromara.sms4j.api.proxy; + +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.manage.InterceptorStrategySmsManager; +import org.dromara.sms4j.api.strategy.IInterceptorStrategy; + +import java.lang.reflect.Method; + +/** + *

方法拦截器,用于拦截{@link SmsBlend}中的方法。
+ * 推荐基于{@link AbstractGenericMethodInterceptor}实现自定义拦截器。 + * + * @author sh1yu + * @since 2023/10/27 13:03 + * @see AbstractGenericMethodInterceptor + * @see SmsMethodType + */ +public interface SmsMethodInterceptor extends Order { + + /** + * 前置拦截,在方法执行前调用 + * + * @param methodType 方法类型,若不是{@link SmsMethodType}则可能为{@code null} + * @param method 方法 + * @param target 调用对象 + * @param params 调用参数 + * @return 调用参数 + */ + default Object[] beforeInvoke( + SmsMethodType methodType, Method method, Object target, Object[] params) { + return params; + } + + /** + * 后置拦截,在方法执行后,无论是否发生异常都会调用 + * + * @param methodType 方法类型,若不是{@link SmsMethodType}则可能为{@code null} + * @param method 调用方法 + * @param params 调用参数 + * @param result 返回值 + * @param ex 调用过程捕获的异常,可能为{@code null} + * @return 返回值,不为{@code null}时将覆盖原有的返回值 + */ + default Object afterCompletion( + SmsMethodType methodType, Method method, Object target,Object[] params, Object result, Exception ex) { + return result; + } + + default C getStrategy(){ + return (C) InterceptorStrategySmsManager.getStrategyByProblemClass(this.getClass()); + } + +} diff --git a/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/SmsMethodType.java b/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/SmsMethodType.java new file mode 100644 index 0000000000000000000000000000000000000000..e712a2c7f1e61a37a434e67fee12960b7238367c --- /dev/null +++ b/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/SmsMethodType.java @@ -0,0 +1,169 @@ +package org.dromara.sms4j.api.proxy; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ClassUtil; +import cn.hutool.core.util.ReflectUtil; +import lombok.Getter; +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.callback.CallBack; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; + +/** + * {@link SmsBlend}中的主要方法 + * + * @author huangchengxing + */ +@Getter +public enum SmsMethodType { + + /** + * {@link SmsBlend#sendMessage(String, String)} + */ + SEND_MESSAGE("sendMessage", String.class, String.class), + + /** + * {@link SmsBlend#sendMessage(String, LinkedHashMap)} + */ + SEND_MESSAGE_WITH_TEMPLATE("sendMessage", String.class, LinkedHashMap.class), + + /** + * {@link SmsBlend#sendMessage(String, String, LinkedHashMap)} + */ + SEND_MESSAGE_WITH_CUSTOM_TEMPLATE("sendMessage", String.class, String.class, LinkedHashMap.class), + + /** + * {@link SmsBlend#massTexting(List, String)} + */ + MASS_TEXTING("massTexting", List.class, String.class), + + /** + * {@link SmsBlend#massTexting(List, String, LinkedHashMap)} + */ + MASS_TEXTING_WITH_TEMPLATE("massTexting", List.class, String.class, LinkedHashMap.class), + + /** + * {@link SmsBlend#sendMessageAsync(String, String, CallBack)} + */ + SEND_MESSAGE_ASYNC("sendMessageAsync", String.class, String.class, CallBack.class), + + /** + * {@link SmsBlend#sendMessageAsync(String, String)} + */ + SEND_MESSAGE_ASYNC_NO_CALLBACK("sendMessageAsync", String.class, String.class), + + /** + * {@link SmsBlend#sendMessageAsync(String, String, LinkedHashMap, CallBack)} + */ + SEND_MESSAGE_ASYNC_WITH_TEMPLATE("sendMessageAsync", String.class, String.class, LinkedHashMap.class, CallBack.class), + + /** + * {@link SmsBlend#sendMessageAsync(String, String, LinkedHashMap)} + */ + SEND_MESSAGE_ASYNC_WITH_TEMPLATE_NO_CALLBACK("sendMessageAsync", String.class, String.class, LinkedHashMap.class), + + /** + * {@link SmsBlend#delayedMessage(String, String, Long)} + */ + DELAYED_MESSAGE("delayedMessage", String.class, String.class, Long.class), + + /** + * {@link SmsBlend#delayedMessage(String, String, LinkedHashMap, Long)} + */ + DELAYED_MESSAGE_WITH_TEMPLATE("delayedMessage", String.class, String.class, LinkedHashMap.class, Long.class), + + /** + * {@link SmsBlend#delayMassTexting(List, String, Long)} + */ + DELAY_MASS_TEXTING("delayMassTexting", List.class, String.class, Long.class), + + /** + * {@link SmsBlend#delayMassTexting(List, String, LinkedHashMap, Long)} + */ + DELAY_MASS_TEXTING_WITH_TEMPLATE("delayMassTexting", List.class, String.class, LinkedHashMap.class, Long.class), + + /** + * {@link SmsBlend#joinInBlacklist(String)} + */ + ADD_BLACK_LIST_ITEM("joinInBlacklist", String.class), + + /** + * {@link SmsBlend#removeFromBlacklist( String)} + */ + REMOVE_BLACK_LIST_ITEM("removeFromBlacklist", String.class), + + /** + * {@link SmsBlend#batchJoinBlacklist(List)} + */ + ADD_BLACK_LIST_ITEMS("batchJoinBlacklist", List.class), + + /** + * {@link SmsBlend#batchRemovalFromBlacklist(List)} + */ + REMOVE_BLACK_LIST_ITEMS("batchRemovalFromBlacklist", List.class), + /** + * {@link SmsBlend#getTriggerRecord()} + */ + GET_TRIGGER_RECORD("getTriggerRecord"), + + /** + * {@link SmsBlend#clearTriggerRecord()} + */ + CLEAR_TRIGGER_RECORD("clearTriggerRecord"); + + /** + * 方法 + */ + private final Method method; + + /** + * 获取方法名称 + * + * @return 方法名称 + */ + public String getName() { + return method.getName(); + } + + /** + * 检查指定方法是否与{@link SmsBlend}中的方法匹配 + * + * @param target 目标方法 + * @return 是否 + */ + public boolean isMatch(Method target) { + if (target == method) { + return true; + } + return Objects.nonNull(target) + && Objects.equals(method.getName(), target.getName()) + && ClassUtil.isAllAssignableFrom(method.getParameterTypes(), target.getParameterTypes()) + && ClassUtil.isAssignable(method.getReturnType(), target.getReturnType()); + } + + /** + * 获取与目标方法对应的{@link SmsBlend}方法 + * + * @param targetMethod 目标方法 + * @return {@link SmsMethodType} + */ + public static SmsMethodType of(Method targetMethod) { + return Stream.of(values()) + .filter(m -> m.isMatch(targetMethod)) + .findFirst() + .orElse(null); + } + + SmsMethodType(String methodName, Class... parameterTypes) { + this.method = ReflectUtil.getMethod(SmsBlend.class, methodName, parameterTypes); + Assert.notNull( + method, "Cannot find best match method from SmsBlend: ({})[{}]", + methodName, Arrays.asList(parameterTypes) + ); + } +} diff --git a/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/SmsProcessor.java b/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/SmsProcessor.java deleted file mode 100644 index e4c2657246ccc6787432322a2e75332e04c80933..0000000000000000000000000000000000000000 --- a/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/SmsProcessor.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.dromara.sms4j.api.proxy; - - -import java.lang.reflect.Method; -/** - * 执行器接口 - * - * @author sh1yu - * @since 2023/10/27 13:03 - */ -public interface SmsProcessor extends Order { - default Object[] preProcessor(Method method, Object source, Object[] param) { - return null; - } - - default Object postProcessor(Object result, Object[] param) { - return null; - } - - default Object exceptionHandleProcessor(Method method, Object source, Object[] param,Exception exception) { - return null; - } -} diff --git a/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/SupplierSupportedMethodInterceptor.java b/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/SupplierSupportedMethodInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..ed87b81aff983fc4b74dc1d9a5ca4104648a2aed --- /dev/null +++ b/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/SupplierSupportedMethodInterceptor.java @@ -0,0 +1,19 @@ +package org.dromara.sms4j.api.proxy; + +import java.util.Set; + +/** + * 限制拦截器仅针对哪些厂商生效,如果拦截器需要根据支持厂商加载,那可以实现此接口 + * + * @author sh1yu + * @since 2023/10/27 13:03 + */ +public interface SupplierSupportedMethodInterceptor extends SmsMethodInterceptor { + + /** + * 获取支持的供应商名称 + * + * @return 供应商名称 + */ + Set getSupportedSuppliers(); +} diff --git a/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/SuppotFilter.java b/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/SuppotFilter.java deleted file mode 100644 index 58453afa5ec7001a28daeb871c15f060376d2850..0000000000000000000000000000000000000000 --- a/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/SuppotFilter.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.dromara.sms4j.api.proxy; - -import java.util.List; -/** - * 支持接口,如果执行器需要根据支持厂商加载,那可以实现此接口 - * - * @author sh1yu - * @since 2023/10/27 13:03 - */ -public interface SuppotFilter{ - List getSupports(); -} diff --git a/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/aware/SmsBlendConfigAware.java b/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/aware/InterceptorStrategySmsBlendConfigAware.java similarity index 62% rename from sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/aware/SmsBlendConfigAware.java rename to sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/aware/InterceptorStrategySmsBlendConfigAware.java index 13e01430a3f11e3e0c4855027aba83854df55e97..2afbcca7183418efc867391a8951dcc03bea70c0 100644 --- a/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/aware/SmsBlendConfigAware.java +++ b/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/aware/InterceptorStrategySmsBlendConfigAware.java @@ -3,11 +3,11 @@ package org.dromara.sms4j.api.proxy.aware; import java.util.Map; /** - * 厂商配置感知接口 + * 给InterceptorStrate使用的厂商配置感知接口 * * @author sh1yu * @since 2023/10/27 13:03 */ -public interface SmsBlendConfigAware { +public interface InterceptorStrategySmsBlendConfigAware { void setSmsBlendsConfig(Map> blends); } diff --git a/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/aware/SmsConfigAware.java b/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/aware/InterceptorStrategySmsConfigAware.java similarity index 56% rename from sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/aware/SmsConfigAware.java rename to sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/aware/InterceptorStrategySmsConfigAware.java index 34b6b38aea06cd7d579ec8fc600545df802a60e0..50eb2a36efbc4a2e3112918df764575f05e5e1f9 100644 --- a/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/aware/SmsConfigAware.java +++ b/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/aware/InterceptorStrategySmsConfigAware.java @@ -2,11 +2,11 @@ package org.dromara.sms4j.api.proxy.aware; /** - * 系统配置感知接口 + * 给InterceptorStrate使用的系统配置感知接口 * * @author sh1yu * @since 2023/10/27 13:03 */ -public interface SmsConfigAware { +public interface InterceptorStrategySmsConfigAware { void setSmsConfig(Object config); } diff --git a/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/aware/SmsDaoAware.java b/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/aware/InterceptorStrategySmsDaoAware.java similarity index 63% rename from sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/aware/SmsDaoAware.java rename to sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/aware/InterceptorStrategySmsDaoAware.java index f17a6297a11e806b52ffbe6174dd7a3631bb542e..8ba75ffd3a76cc13889a72dae37553af15bf23b1 100644 --- a/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/aware/SmsDaoAware.java +++ b/sms4j-api/src/main/java/org/dromara/sms4j/api/proxy/aware/InterceptorStrategySmsDaoAware.java @@ -2,11 +2,11 @@ package org.dromara.sms4j.api.proxy.aware; import org.dromara.sms4j.api.dao.SmsDao; /** - * 缓存感知接口 + * 给InterceptorStrate使用的缓存感知接口 * * @author sh1yu * @since 2023/10/27 13:03 */ -public interface SmsDaoAware { +public interface InterceptorStrategySmsDaoAware { void setSmsDao(SmsDao smsDao); } diff --git a/sms4j-api/src/main/java/org/dromara/sms4j/api/strategy/IInterceptorStrategy.java b/sms4j-api/src/main/java/org/dromara/sms4j/api/strategy/IInterceptorStrategy.java new file mode 100644 index 0000000000000000000000000000000000000000..d625e9a5e6af00d5ae393b7d486e5f703e80e999 --- /dev/null +++ b/sms4j-api/src/main/java/org/dromara/sms4j/api/strategy/IInterceptorStrategy.java @@ -0,0 +1,15 @@ +package org.dromara.sms4j.api.strategy; + +/** + *

说明:拦截器执行策略接口 + * + * @author :sh1yu + */ +public interface IInterceptorStrategy { + + /** + * 本策略适配与哪个拦截器 + * @return :拦截器的class + */ + Class aPendingProblemWith(); +} diff --git a/sms4j-api/src/main/java/org/dromara/sms4j/api/verify/PhoneVerify.java b/sms4j-api/src/main/java/org/dromara/sms4j/api/verify/PhoneVerify.java new file mode 100644 index 0000000000000000000000000000000000000000..d5b6cb78957cf060442ea7003a59599357aa6315 --- /dev/null +++ b/sms4j-api/src/main/java/org/dromara/sms4j/api/verify/PhoneVerify.java @@ -0,0 +1,23 @@ +package org.dromara.sms4j.api.verify; + +/** + * PhoneVerify + *

实现校验手机号合规的接口 + * @author :Wind + * 2024/3/28 14:15 + **/ +public interface PhoneVerify{ + + /** + * verifyPhone + *

用于校验手机号是否合理的规则方法,可以尝试重写此方法以改变规则,例如你可以选择使用正则表达式来进行 + * 一系列更加精准和严格的校验,此校验优先级最高,会在黑名单和其他拦截之前执行。 + * 当此校验触发时候,将会直接以异常形式进行抛出,并终止后续向厂商请求的动作,故而不会有返回值。 + * 当校验手机号合格时返回 true 否则返回 false + * @param phone 被校验的手机号 + * @author :Wind + */ + default boolean verifyPhone(String phone){ + return phone.length() == 11; + } +} diff --git a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/constant/Constant.java b/sms4j-comm/src/main/java/org/dromara/sms4j/comm/constant/Constant.java index 00dbea905180f216302244b371a8bcafe316964a..89759b85b0c94670cbc18c0b5712a41d9ee7d557 100644 --- a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/constant/Constant.java +++ b/sms4j-comm/src/main/java/org/dromara/sms4j/comm/constant/Constant.java @@ -11,7 +11,7 @@ public abstract class Constant { /** * 项目版本号 */ - public static final String VERSION = "V 3.0.1"; + public static final String VERSION = "V 3.2.0"; /** * 用于格式化鉴权头域,给"Authorization"参数赋值 @@ -34,6 +34,18 @@ public abstract class Constant { public static final String APPLICATION_JSON_UTF8 = "application/json; charset=utf-8"; + /** + * 通用请求头 CONTENT_TYPE + */ + public static final String CONTENT_TYPE = "Content-Type"; + + /** + * Accept-Charset + */ + public static final String ACCEPT_CHARSET = "Accept-Charset"; + + + /** * 华为云规定 java时间格式 */ diff --git a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/constant/SupplierConstant.java b/sms4j-comm/src/main/java/org/dromara/sms4j/comm/constant/SupplierConstant.java index 7706a9c5b986c5b8787f5780f2a97f9dc297051e..6448d94ae4ef16ffe56157edbe768f14d32425f2 100644 --- a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/constant/SupplierConstant.java +++ b/sms4j-comm/src/main/java/org/dromara/sms4j/comm/constant/SupplierConstant.java @@ -5,6 +5,10 @@ package org.dromara.sms4j.comm.constant; */ public abstract class SupplierConstant { + /** + * 无,用于测试 + */ + public static final String LOCAL = "local"; /** * 阿里 */ @@ -59,6 +63,15 @@ public abstract class SupplierConstant { * 鼎众 */ public static final String DINGZHONG = "dingzhong"; + + /** + * 七牛 + */ public static final String QINIU = "qiniu"; + + /** + * 油客 + */ + public static final String YOKE = "yoke"; } diff --git a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/exception/SmsBlendException.java b/sms4j-comm/src/main/java/org/dromara/sms4j/comm/exception/SmsBlendException.java index f49f1028d52815b292400821b56d8765af4c7fb9..36b502177d5a442b9d83335576c1b06b85efc744 100644 --- a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/exception/SmsBlendException.java +++ b/sms4j-comm/src/main/java/org/dromara/sms4j/comm/exception/SmsBlendException.java @@ -1,6 +1,6 @@ package org.dromara.sms4j.comm.exception; -public class SmsBlendException extends RuntimeException{ +public class SmsBlendException extends RuntimeException { public String code; public final String message; public String requestId; @@ -22,4 +22,16 @@ public class SmsBlendException extends RuntimeException{ this.code = code; this.requestId = requestId; } + + + /** + * 带参数的构造方法 需要用%s来占位 + * + * @param message 错误信息 + * @param args 参数 + */ + public SmsBlendException(String message, Object... args) { + super(message); + this.message = String.format(message, args); + } } diff --git a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/utils/SmsUtils.java b/sms4j-comm/src/main/java/org/dromara/sms4j/comm/utils/SmsUtils.java index b4f3de241514bb6643e9daf09eeae2408a1f7071..88338650eb60a55dba4fa8210361313acad690dc 100644 --- a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/utils/SmsUtils.java +++ b/sms4j-comm/src/main/java/org/dromara/sms4j/comm/utils/SmsUtils.java @@ -18,7 +18,8 @@ import java.util.Map; public class SmsUtils { private SmsUtils() { } //私有构造防止实例化 - + //测试环境标志的包头 + private final static String JUNIT_MAIN_CLASS = "org.junit"; /** *

说明:生成一个指定长度的随机字符串,包含大小写英文字母和数字但不包含符号 * @@ -172,4 +173,12 @@ public class SmsUtils { } } + public static boolean isTesting() { + for (StackTraceElement element : Thread.currentThread().getStackTrace()) { + if (element.getClassName().startsWith(JUNIT_MAIN_CLASS)) { + return true; + } + } + return false; + } } \ No newline at end of file diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/datainterface/SmsBlendsBeanConfig.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/datainterface/SmsBlendsBeanConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..e1a5bccec2a216076d918d4f1f16c8d36881374d --- /dev/null +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/datainterface/SmsBlendsBeanConfig.java @@ -0,0 +1,24 @@ +package org.dromara.sms4j.core.datainterface; + +import org.dromara.sms4j.provider.config.BaseConfig; + +import java.util.List; + +/** + * SmsBlendsBeanConfig + *

读取配置接口,实现该接口中的方法则可以按照自己的形式进行配置的读取 + *

这样只关注最终的配置数据而不关注配置的来源,用户可以自由的选择数据来源的方式

+ *

该种方式读取配置在启动阶段完成,无需再有其他操作

+ * @author :Wind + * 2023/8/1 12:06 + **/ +public interface SmsBlendsBeanConfig { + + /** + * getSupplierConfigList + *

获取多个厂商的配置,会同时加载进框架中 + * @author :Wind + */ + List getSupplierConfigList(); + +} diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/datainterface/SmsBlendsSelectedConfig.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/datainterface/SmsBlendsSelectedConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..0d653c20c9a81b012d53ecefdf349c8bc8fbcc02 --- /dev/null +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/datainterface/SmsBlendsSelectedConfig.java @@ -0,0 +1,25 @@ +package org.dromara.sms4j.core.datainterface; + +import org.dromara.sms4j.provider.config.BaseConfig; + +/** + * SmsBlendsSelectedConfig + *

读取配置接口,实现该接口中的方法则可以按照自己的形式进行配置的读取 + *

这样只关注最终的配置数据而不关注配置的来源,用户可以自由的选择数据来源的方式

+ *

该种方式读取配置并非在启动阶段完成,而是在方法第一次调用期间完成,需要配合使用 SmsFactory#createSmsBlend

+ *

eg. SmsFactory.createSmsBlend(config,"在配置中定义的configId"):

+ * @author :Wind + * 2023/8/1 12:06 + **/ +public interface SmsBlendsSelectedConfig { + + /** + * getSupplierConfig + *

通过配置ID获取一个厂商的配置 + * @param configId 配置id + * @author :Wind + */ + BaseConfig getSupplierConfig(String configId); + + +} diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/datainterface/SmsReadConfig.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/datainterface/SmsReadConfig.java index 3068f237ef3e6e335f51aae7179d656d8e381de3..c2b9c1cd84bf5a24b3d21283d9eb6911a7923130 100644 --- a/sms4j-core/src/main/java/org/dromara/sms4j/core/datainterface/SmsReadConfig.java +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/datainterface/SmsReadConfig.java @@ -1,32 +1,15 @@ package org.dromara.sms4j.core.datainterface; -import org.dromara.sms4j.provider.config.BaseConfig; -import java.util.List; /** * SmsReadConfig *

读取配置接口,实现该接口中的方法则可以按照自己的形式进行配置的读取 - *

这样只关注最终的配置数据而不关注配置的来源,用户可以自由的选择数据来源的方式

- *

该种方式读取配置并非在启动阶段完成,而是在方法第一次调用期间完成

+ *

这样只关注最终的配置数据而不关注配置的来源,用户可以自由的选择数据来源的方式

+ *

SmsBlendsSelectedConfig继承而来的取配置并非在启动阶段完成,而是在方法第一次调用期间完成

+ *

SmsBlendsBeanConfig继承而来的取配置在启动阶段完成

* @author :Wind * 2023/8/1 12:06 **/ -public interface SmsReadConfig { - - /** - * getSupplierConfig - *

通过配置ID获取一个厂商的配置 - * @param configId 配置id - * @author :Wind - */ - BaseConfig getSupplierConfig(String configId); - - /** - * getSupplierConfigList - *

获取多个厂商的配置,会同时加载进框架中 - * @author :Wind - */ - List getSupplierConfigList(); - +public interface SmsReadConfig extends SmsBlendsBeanConfig,SmsBlendsSelectedConfig{ } diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/factory/SmsFactory.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/factory/SmsFactory.java index 3489aa5689aeb5ee38b682935411366df692e171..76237181ef231d40d462ed5245830a5fe59cc353 100644 --- a/sms4j-core/src/main/java/org/dromara/sms4j/core/factory/SmsFactory.java +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/factory/SmsFactory.java @@ -4,7 +4,8 @@ import cn.hutool.core.util.StrUtil; import org.dromara.sms4j.api.SmsBlend; import org.dromara.sms4j.api.universal.SupplierConfig; import org.dromara.sms4j.comm.exception.SmsBlendException; -import org.dromara.sms4j.core.datainterface.SmsReadConfig; +import org.dromara.sms4j.comm.utils.SmsUtils; +import org.dromara.sms4j.core.datainterface.*; import org.dromara.sms4j.core.load.SmsLoad; import org.dromara.sms4j.core.proxy.SmsProxyFactory; import org.dromara.sms4j.provider.config.BaseConfig; @@ -46,6 +47,9 @@ public abstract class SmsFactory { * @author :Wind */ public static void createSmsBlend(SupplierConfig config) { + if(!SmsUtils.isTesting() && "local".equals(config.getConfigId())){ + throw new RuntimeException("非测试环境不能使用【LOCAL】"); + } SmsBlend smsBlend = create(config); register(smsBlend); } @@ -57,12 +61,15 @@ public abstract class SmsFactory { *

该方法创建的短信实例将会交给框架进行托管,后续可以通过getSmsBlend获取 *

该方法会直接调用接口实现 * - * @param smsReadConfig 读取额外配置接口 + * @param smsBlendsSelectedConfig 读取额外配置选择接口 * @param configId 配置ID * @author :Wind */ - public static void createSmsBlend(SmsReadConfig smsReadConfig, String configId) { - BaseConfig supplierConfig = smsReadConfig.getSupplierConfig(configId); + public static void createSmsBlend(SmsBlendsSelectedConfig smsBlendsSelectedConfig, String configId) { + BaseConfig supplierConfig = smsBlendsSelectedConfig.getSupplierConfig(configId); + if (null == supplierConfig) { + return; + } SmsBlend smsBlend = create(supplierConfig); register(smsBlend); } @@ -73,11 +80,14 @@ public abstract class SmsFactory { *

该方法创建的短信实例将会交给框架进行托管,后续可以通过getSmsBlend获取 *

该方法会直接调用接口实现 * - * @param smsReadConfig 读取额外配置接口 + * @param smsBlendsBeanConfig 读取额外配置接口 * @author :Wind */ - public static void createSmsBlend(SmsReadConfig smsReadConfig) { - List supplierConfigList = smsReadConfig.getSupplierConfigList(); + public static void createSmsBlend(SmsBlendsBeanConfig smsBlendsBeanConfig) { + List supplierConfigList = smsBlendsBeanConfig.getSupplierConfigList(); + if (null == supplierConfigList) { + return; + } supplierConfigList.forEach(supplierConfig -> { SmsBlend smsBlend = create(supplierConfig); register(smsBlend); @@ -103,13 +113,16 @@ public abstract class SmsFactory { *

该方法创建的短信实例将会交给框架进行托管,后续可以通过getSmsBlend获取 *

该方法会直接调用接口实现 * - * @param smsReadConfig 读取额外配置接口 + * @param smsBlendsSelectedConfig 读取额外配置选择接口 * @param configId 配置ID * @author :Wind */ @Deprecated - public static void createRestrictedSmsBlend(SmsReadConfig smsReadConfig, String configId) { - BaseConfig supplierConfig = smsReadConfig.getSupplierConfig(configId); + public static void createRestrictedSmsBlend(SmsBlendsSelectedConfig smsBlendsSelectedConfig, String configId) { + BaseConfig supplierConfig = smsBlendsSelectedConfig.getSupplierConfig(configId); + if (null == supplierConfig){ + return; + } SmsBlend smsBlend = create(supplierConfig); register(smsBlend); } @@ -120,12 +133,15 @@ public abstract class SmsFactory { *

该方法创建的短信实例将会交给框架进行托管,后续可以通过getSmsBlend获取 *

该方法会直接调用接口实现 * - * @param smsReadConfig 读取额外配置接口 + * @param smsBlendsBeanConfig 读取额外配置接口 * @author :Wind */ @Deprecated - public static void createRestrictedSmsBlend(SmsReadConfig smsReadConfig) { - List supplierConfigList = smsReadConfig.getSupplierConfigList(); + public static void createRestrictedSmsBlend(SmsBlendsBeanConfig smsBlendsBeanConfig) { + List supplierConfigList = smsBlendsBeanConfig.getSupplierConfigList(); + if (null == supplierConfigList){ + return; + } supplierConfigList.forEach(supplierConfig -> { SmsBlend smsBlend = create(supplierConfig); register(smsBlend); @@ -151,7 +167,7 @@ public abstract class SmsFactory { */ @Deprecated private static SmsBlend renderWithProxy(SmsBlend sms) { - return SmsProxyFactory.getProxySmsBlend(sms); + return SmsProxyFactory.getProxiedSmsBlend(sms); } /** @@ -302,25 +318,26 @@ public abstract class SmsFactory { *

重新读取并刷新缓存内短信实例 * * @param configId 配置标识 - * @param smsReadConfig 配置接口实现对象 + * @param smsBlendsSelectedConfig 额外配置选择接口实现对象 * @author :Wind */ - public static void reload(String configId, SmsReadConfig smsReadConfig) { + public static void reload(String configId, SmsBlendsSelectedConfig smsBlendsSelectedConfig) { SmsFactory.unregister(configId); - SmsFactory.createRestrictedSmsBlend(smsReadConfig, configId); + SmsFactory.createRestrictedSmsBlend(smsBlendsSelectedConfig, configId); } /** * reloadAll *

重新读取并刷新全部短信实例 - * @param smsReadConfig 配置接口实现对象 + * @param smsBlendsBeanConfig 配置接口实现对象 * @author :Wind */ - public static void reloadAll(SmsReadConfig smsReadConfig) { - List supplierConfigList = smsReadConfig.getSupplierConfigList(); + public static void reloadAll(SmsBlendsBeanConfig smsBlendsBeanConfig) { + List supplierConfigList = smsBlendsBeanConfig.getSupplierConfigList(); for (BaseConfig baseConfig : supplierConfigList) { - reload(baseConfig.getConfigId(),smsReadConfig); + SmsFactory.unregister(baseConfig.getConfigId()); } + createRestrictedSmsBlend(smsBlendsBeanConfig); } } diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/initalize/AbstractInitalizer.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/initalize/AbstractInitalizer.java new file mode 100644 index 0000000000000000000000000000000000000000..60c0408ca82f2c49208e4ee537de300f51f1457b --- /dev/null +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/initalize/AbstractInitalizer.java @@ -0,0 +1,174 @@ +package org.dromara.sms4j.core.initalize; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import org.dromara.sms4j.aliyun.config.AlibabaFactory; +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.dao.SmsDao; +import org.dromara.sms4j.api.dao.SmsDaoDefaultImpl; +import org.dromara.sms4j.api.manage.InterceptorStrategySmsManager; +import org.dromara.sms4j.api.proxy.SmsMethodInterceptor; +import org.dromara.sms4j.api.strategy.IInterceptorStrategy; +import org.dromara.sms4j.api.universal.SupplierConfig; +import org.dromara.sms4j.cloopen.config.CloopenFactory; +import org.dromara.sms4j.comm.constant.Constant; +import org.dromara.sms4j.comm.utils.SmsUtils; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.core.proxy.SmsProxyFactory; +import org.dromara.sms4j.core.proxy.interceptor.*; +import org.dromara.sms4j.core.proxy.strategy.impl.*; +import org.dromara.sms4j.ctyun.config.CtyunFactory; +import org.dromara.sms4j.dingzhong.config.DingZhongFactory; +import org.dromara.sms4j.emay.config.EmayFactory; +import org.dromara.sms4j.huawei.config.HuaweiFactory; +import org.dromara.sms4j.jdcloud.config.JdCloudFactory; +import org.dromara.sms4j.lianlu.config.LianLuFactory; +import org.dromara.sms4j.local.LocalFactory; +import org.dromara.sms4j.netease.config.NeteaseFactory; +import org.dromara.sms4j.provider.config.SmsConfig; +import org.dromara.sms4j.provider.factory.BaseProviderFactory; +import org.dromara.sms4j.provider.factory.ProviderFactoryHolder; +import org.dromara.sms4j.qiniu.config.QiNiuFactory; +import org.dromara.sms4j.tencent.config.TencentFactory; +import org.dromara.sms4j.unisms.config.UniFactory; +import org.dromara.sms4j.yunpian.config.YunPianFactory; +import org.dromara.sms4j.zhutong.config.ZhutongFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * AbstractInitalizer + *

抽象初始化器 + * + * @author :Wind + * 2023/4/8 15:55 + **/ +@Slf4j +public abstract class AbstractInitalizer { + + //Dao的实现 + private SmsDao smsDao = SmsDaoDefaultImpl.getInstance(); + + //所有注册进来的拦截器 + private List smsMethodInterceptors = new ArrayList<>(); + + //所有注册进来的拦截器策略 + private List interceptorStrategies = new ArrayList<>(); + + /** + * 注册拦截器 + * + * @param interceptor 拦截器 + */ + public void doRegisterSmsMethodInterceptor(SmsMethodInterceptor interceptor) { + smsMethodInterceptors.add(interceptor); + } + + /** + * 注册拦截器执行策略 + * + * @param interceptorStrategy 拦截器执行策略 + */ + public void doRegisterIInterceptorStrategy(IInterceptorStrategy interceptorStrategy) { + this.interceptorStrategies.add(interceptorStrategy); + } + + /** + * 注册DAO实例 + * + * @param smsDao DAO实例 + */ + public void doRegisterSmsDao(SmsDao smsDao) { + if (smsDao == null) { + smsDao = SmsDaoDefaultImpl.getInstance(); + } + this.smsDao = smsDao; + } + + /** + * 装载拦截器以及拦截器策略 + * + * @param blends 渠道配置 + * @param smsConfig sms4j公共基础配置 + */ + protected void initInterceptor(Map> blends, SmsConfig smsConfig) { + InterceptorStrategySmsManager.setBlends(blends); + InterceptorStrategySmsManager.setSmsConfig(smsConfig); + InterceptorStrategySmsManager.setSmsDao(this.smsDao); + DefaultAcctMaxRestrictedMethodStrategy defaultAcctMaxRestrictedMethodStrategy = new DefaultAcctMaxRestrictedMethodStrategy(); + InterceptorStrategySmsManager.setInterceptorStrategyMapping( defaultAcctMaxRestrictedMethodStrategy); + DefaultBlackListCheckStrategy defaultBlackListCheckStrategy = new DefaultBlackListCheckStrategy(); + InterceptorStrategySmsManager.setInterceptorStrategyMapping( defaultBlackListCheckStrategy); + DefaultBlackListManageStrategy defaultBlackListManageStrategy = new DefaultBlackListManageStrategy(); + InterceptorStrategySmsManager.setInterceptorStrategyMapping( defaultBlackListManageStrategy); + DefaultChannelMaxRestrictedMethodStrategy defaultChannelMaxRestrictedMethodStrategy = new DefaultChannelMaxRestrictedMethodStrategy(); + InterceptorStrategySmsManager.setInterceptorStrategyMapping( defaultChannelMaxRestrictedMethodStrategy); + DefaultSpanMaxRestrictedMethodStrategy defaultSpanMaxRestrictedMethodStrategy = new DefaultSpanMaxRestrictedMethodStrategy(); + InterceptorStrategySmsManager.setInterceptorStrategyMapping( defaultSpanMaxRestrictedMethodStrategy); + DefaultSyncMethodParamValidateStrategy defaultSyncMethodParamValidateStrategy = new DefaultSyncMethodParamValidateStrategy(); + InterceptorStrategySmsManager.setInterceptorStrategyMapping( defaultSyncMethodParamValidateStrategy); + for (IInterceptorStrategy interceptorStrategy : this.interceptorStrategies) { + InterceptorStrategySmsManager.setInterceptorStrategyMapping( interceptorStrategy); + } + InterceptorStrategySmsManager.freezes(); + SmsProxyFactory.addInterceptor(new AcctMaxRestrictedMethodInterceptor()); + SmsProxyFactory.addInterceptor(new BlackListMethodInterceptor()); + SmsProxyFactory.addInterceptor(new BlackListRecordingProxyInterceptor()); + SmsProxyFactory.addInterceptor(new ChannelMaxRestrictedMethodInterceptor()); + SmsProxyFactory.addInterceptor(new SpanMaxRestrictedMethodInterceptor()); + SmsProxyFactory.addInterceptor(new SyncMethodParamValidateMethodInterceptor()); + for (SmsMethodInterceptor smsMethodInterceptor : this.smsMethodInterceptors) { + SmsProxyFactory.addInterceptor(smsMethodInterceptor); + } + } + + /** + * 解析各渠道配置并创建对应实现 + * + * @param blends 渠道配置 + */ + protected void doParseChannelConfigWithCreate(Map> blends){ + blends.forEach((configId, configMap) -> { + Object supplierObj = configMap.get(Constant.SUPPLIER_KEY); + String supplier = supplierObj == null ? "" : String.valueOf(supplierObj); + supplier = StrUtil.isEmpty(supplier) ? configId : supplier; + BaseProviderFactory providerFactory = (BaseProviderFactory) ProviderFactoryHolder.requireForSupplier(supplier); + if (providerFactory == null) { + log.warn("创建'{}'的短信服务失败,未找到服务商为'{}'的服务", configId, supplier); + return; + } + configMap.put("config-id", configId); + SmsUtils.replaceKeysSeperator(configMap, "-", "_"); + JSONObject configJson = new JSONObject(configMap); + SupplierConfig supplierConfig = JSONUtil.toBean(configJson, providerFactory.getConfigClass()); + SmsFactory.createSmsBlend(supplierConfig); + }); + } + + /** + * 注册预置工厂实例 + */ + protected void registerDefaultFactory() { + ProviderFactoryHolder.registerFactory(LocalFactory.instance()); + ProviderFactoryHolder.registerFactory(AlibabaFactory.instance()); + ProviderFactoryHolder.registerFactory(CloopenFactory.instance()); + ProviderFactoryHolder.registerFactory(CtyunFactory.instance()); + ProviderFactoryHolder.registerFactory(EmayFactory.instance()); + ProviderFactoryHolder.registerFactory(HuaweiFactory.instance()); + ProviderFactoryHolder.registerFactory(NeteaseFactory.instance()); + ProviderFactoryHolder.registerFactory(TencentFactory.instance()); + ProviderFactoryHolder.registerFactory(UniFactory.instance()); + ProviderFactoryHolder.registerFactory(YunPianFactory.instance()); + ProviderFactoryHolder.registerFactory(ZhutongFactory.instance()); + ProviderFactoryHolder.registerFactory(LianLuFactory.instance()); + ProviderFactoryHolder.registerFactory(DingZhongFactory.instance()); + ProviderFactoryHolder.registerFactory(QiNiuFactory.instance()); + if(SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) { + ProviderFactoryHolder.registerFactory(JdCloudFactory.instance()); + } + } +} diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/EnvirmentHolder.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/EnvirmentHolder.java deleted file mode 100644 index 57a19d1df12876275bed18604939a13f31399e53..0000000000000000000000000000000000000000 --- a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/EnvirmentHolder.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.dromara.sms4j.core.proxy; - -import org.dromara.sms4j.provider.config.SmsConfig; - -import java.util.Map; - -/** - * 环境信息持有 - * - * @author sh1yu - * @since 2023/10/27 13:03 - */ -public class EnvirmentHolder { - private static SmsConfig smsConfig = null; - private static Map> blends = null; - - public static void frozenEnvirmet(SmsConfig smsConfig, Map> blends) { - if (null!=EnvirmentHolder.smsConfig||null!=EnvirmentHolder.blends){ - return; - } - EnvirmentHolder.smsConfig = smsConfig; - EnvirmentHolder.blends = blends; - } - - //只有核心包执行器部分才能获取 - static SmsConfig getSmsConfig() { - return smsConfig; - } - - //只有核心包执行器部分才能获取 - static Map> getBlends() { - return blends; - } -} diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/SmsInvocationHandler.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/SmsInvocationHandler.java index dde9bda3aa2bcac73da8c41ab0e0c0a657368304..640a852129df43ee1e9a71ded9e043f2dbc8c674 100644 --- a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/SmsInvocationHandler.java +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/SmsInvocationHandler.java @@ -1,66 +1,55 @@ package org.dromara.sms4j.core.proxy; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.dromara.sms4j.api.SmsBlend; -import org.dromara.sms4j.api.proxy.SmsProcessor; +import org.dromara.sms4j.api.proxy.SmsMethodType; +import org.dromara.sms4j.api.proxy.SmsMethodInterceptor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; -import java.util.LinkedList; - +import java.util.List; /** - * SmsBlend增强,封装smsblend和执行器 + * {@link SmsBlend}代理,用于织入{@link SmsMethodInterceptor}实现前置和后置拦截 * * @author sh1yu * @since 2023/10/27 13:03 */ @Slf4j +@RequiredArgsConstructor public class SmsInvocationHandler implements InvocationHandler { - private final SmsBlend smsBlend; - private final LinkedList processors; - - public SmsInvocationHandler(SmsBlend smsBlend, LinkedList processors) { - this.smsBlend = smsBlend; - this.processors = processors; - } + private final SmsBlend delegate; + private final List interceptors; @Override - public Object invoke(Object o, Method method, Object[] objects) { + public Object invoke(Object target, Method method, Object[] params) { + SmsMethodType methodType = SmsMethodType.of(method); Object result = null; - //前置执行器 - objects = doPreProcess(smsBlend, method, objects); + // 前置拦截 + params = invokePreHandle(methodType, delegate, method, params); + Exception ex = null; try { - result = method.invoke(smsBlend, objects); + result = method.invoke(delegate, params); } catch (Exception e) { - //错误执行器 - doErrorHandleProcess(smsBlend, method, objects,e); + ex = e; } - //后置执行器 - doPostrocess(smsBlend, method, objects, result); - return result; + // 后置拦截 + return invokeAfterCompletion(methodType,delegate,method, params, result, ex); } - public Object[] doPreProcess(Object o, Method method, Object[] objects) { - for (SmsProcessor processor : processors) { - objects = processor.preProcessor(method, o, objects); + private Object[] invokePreHandle(SmsMethodType methodType, Object o, Method method, Object[] objects) { + for (SmsMethodInterceptor interceptor : interceptors) { + objects = interceptor.beforeInvoke(methodType, method, o, objects); } return objects; } - public void doErrorHandleProcess(Object o, Method method, Object[] objects,Exception e) { - for (SmsProcessor processor : processors) { - processor.exceptionHandleProcessor(method, o, objects,e); - } - } - - public Object doPostrocess(Object o, Method method, Object[] objects, Object result) { - for (SmsProcessor processor : processors) { - Object overrideResult = processor.postProcessor(result, objects); - if (overrideResult != null) { - return overrideResult; - } + private Object invokeAfterCompletion(SmsMethodType methodType, Object o, Method method, Object[] params, Object result, Exception ex) { + // TODO 后续把错误SmsBlendException 分等级,如果影响运行的就直接程序停止,如果不影响程序运行是发送中的小问题就把错误吞掉,封装成SmsResponse,然后正常返回,这个拦截器要加到最前面,前置最先执行后置最后执行 + for (int index = interceptors.size() - 1; index >= 0; index--) { + result = interceptors.get(index).afterCompletion(methodType, method, o,params, result, ex); } return result; } diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/SmsProxyFactory.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/SmsProxyFactory.java index 064d44b7fa5baae7b22e61b9ae119d9c9846cedd..4711ac2b06d7b6d042ecf76f735f56d4d461a903 100644 --- a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/SmsProxyFactory.java +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/SmsProxyFactory.java @@ -1,22 +1,18 @@ package org.dromara.sms4j.core.proxy; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.dromara.sms4j.api.SmsBlend; -import org.dromara.sms4j.api.dao.SmsDao; -import org.dromara.sms4j.api.dao.SmsDaoDefaultImpl; +import org.dromara.sms4j.api.manage.InterceptorStrategySmsManager; import org.dromara.sms4j.api.proxy.Order; -import org.dromara.sms4j.api.proxy.SmsProcessor; -import org.dromara.sms4j.api.proxy.SuppotFilter; -import org.dromara.sms4j.api.proxy.aware.SmsBlendConfigAware; -import org.dromara.sms4j.api.proxy.aware.SmsConfigAware; -import org.dromara.sms4j.api.proxy.aware.SmsDaoAware; +import org.dromara.sms4j.api.proxy.Restricted; +import org.dromara.sms4j.api.proxy.SmsMethodInterceptor; +import org.dromara.sms4j.api.proxy.SupplierSupportedMethodInterceptor; +import org.dromara.sms4j.provider.config.SmsConfig; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.lang.reflect.Proxy; -import java.util.Comparator; -import java.util.LinkedList; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; /** @@ -24,89 +20,73 @@ import java.util.stream.Collectors; * * @author sh1yu * @since 2023/10/27 13:03 + * @see SmsMethodInterceptor + * @see SmsInvocationHandler */ @Slf4j -public abstract class SmsProxyFactory { - private static final LinkedList processors = new LinkedList<>(); +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class SmsProxyFactory { - public static SmsBlend getProxySmsBlend(SmsBlend smsBlend) { - LinkedList ownerProcessors = processors.stream().filter(processor -> !shouldSkipProcess(processor,smsBlend)).collect(Collectors.toCollection(LinkedList::new)); - return (SmsBlend) Proxy.newProxyInstance(smsBlend.getClass().getClassLoader(), new Class[]{SmsBlend.class}, new SmsInvocationHandler(smsBlend, ownerProcessors)); - } + public static final int BLACK_LIST_RECORDING_INTERCEPTOR_ORDER = -2; + public static final int CORE_PARAM_VALIDATE_METHOD_INTERCEPTOR_ORDER = -1; + public static final int BLACK_LIST_METHOD_INTERCEPTOR_ORDER = 0; + public static final int ACCT_RESTRICTED_METHOD_INTERCEPTOR = 3; + public static final int SPAN_RESTRICTED_METHOD_INTERCEPTOR = 4; + public static final int SINGLE_BLEND_RESTRICTED_METHOD_INTERCEPTOR_ORDER = 2; + private static final List INTERCEPTORS = new ArrayList<>(); - /** - * 增加拦截器 - */ - public static void addProcessor(SmsProcessor processor) { - //校验拦截器是否正确 - processorValidate(processor); - awareTransfer(processor); - processors.add(processor); - processors.sort(Comparator.comparingInt(Order::getOrder)); - } - - /* - * @see SuppotFilter - */ - public static boolean shouldSkipProcess(SmsProcessor processor, SmsBlend smsBlend) { - //判断当前的执行器有没有开厂商过滤,支不支持当前厂商 - if (processor instanceof SuppotFilter) { - List supports = ((SuppotFilter) processor).getSupports(); - boolean exsit = supports.stream().anyMatch(support -> support.equals(smsBlend.getSupplier())); - return !exsit; + public static SmsBlend getProxiedSmsBlend(SmsBlend smsBlend) { + //获取当前渠道的拦截开关是否开启 + Objects.requireNonNull(smsBlend); + // 若已被代理则直接返回,避免重复代理 + if (smsBlend instanceof Proxied) { + return smsBlend; } - return false; + List appliedInterceptors = INTERCEPTORS.stream() + .filter(interceptor -> canApply(interceptor, smsBlend)) + .filter(interceptor -> isRestricted(interceptor.getClass().getInterfaces(),((SmsConfig)InterceptorStrategySmsManager.getSmsConfig()).getRestricted())) + .collect(Collectors.toList()); + return (SmsBlend) Proxy.newProxyInstance( + smsBlend.getClass().getClassLoader(), + new Class[]{SmsBlend.class, Proxied.class}, + new SmsInvocationHandler(smsBlend, appliedInterceptors) + ); } - //所有处理器需要的各个参数可以通过这种aware接口形式传给对象 - private static void awareTransfer(SmsProcessor processor) { - if (processor instanceof SmsDaoAware){ - ((SmsDaoAware) processor).setSmsDao(getSmsDaoFromFramework()); + private static boolean isRestricted( Class[] interfaces,boolean restricted) { + if (restricted){ + return true; } - if (processor instanceof SmsConfigAware){ - ((SmsConfigAware) processor).setSmsConfig(EnvirmentHolder.getSmsConfig()); - } - if (processor instanceof SmsBlendConfigAware){ - ((SmsBlendConfigAware) processor).setSmsBlendsConfig(EnvirmentHolder.getBlends()); + for (Class anInterface : interfaces) { + if (anInterface.equals(Restricted.class)){ + return false; + } + for (Class anInterfaceInterface : anInterface.getInterfaces()) { + if (!isRestricted(anInterfaceInterface.getInterfaces(),restricted)){ + return false; + } + } } + return true; } - //校验拦截器是否正确 - private static void processorValidate(SmsProcessor processor) { - + /** + * 增加拦截器 + */ + public static void addInterceptor(SmsMethodInterceptor interceptor) { + Objects.requireNonNull(interceptor); + // 尝试移除旧拦截器避免重复添加 + INTERCEPTORS.remove(interceptor); + INTERCEPTORS.add(interceptor); + INTERCEPTORS.sort(Comparator.comparingInt(Order::getOrder)); } - //获取Sms的实现 - private static SmsDao getSmsDaoFromFramework() { - SmsDao smsDao; - smsDao = getSmsDaoFromFramework("org.dromara.sms4j.javase.config.SESmsDaoHolder", "JavaSE"); - if (null != smsDao) { - return smsDao; - } - smsDao = getSmsDaoFromFramework("org.dromara.sms4j.starter.holder.SpringSmsDaoHolder", "SpringBoot"); - if (null != smsDao) { - return smsDao; - } - smsDao = getSmsDaoFromFramework("org.dromara.sms4j.solon.holder.SolonSmsDaoHolder", "Solon"); - if (null != smsDao) { - return smsDao; - } - log.debug("未找到合适框架加载,最终使用默认SmsDao!如无自实现SmsDao请忽略本消息!"); - return SmsDaoDefaultImpl.getInstance(); + private static boolean canApply(SmsMethodInterceptor interceptor, SmsBlend smsBlend) { + // 判断当前的执行器有没有开厂商过滤,支不支持当前厂商 + return !(interceptor instanceof SupplierSupportedMethodInterceptor) + || ((SupplierSupportedMethodInterceptor) interceptor).getSupportedSuppliers().contains(smsBlend.getSupplier()); } - //获取Sms的实现 - private static SmsDao getSmsDaoFromFramework(String className, String frameworkName) { - try { - Class clazz = Class.forName(className); - Method getSmsDao = clazz.getMethod("getSmsDao", null); - SmsDao smsDao = (SmsDao) getSmsDao.invoke(null, null); - log.info("{}:加载SmsDao成功,使用{}", frameworkName,smsDao.getClass().getName()); - return smsDao; - } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { - log.debug("{}:尝试其他框架加载......", frameworkName); - } - return null; + public interface Proxied { } - } diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/interceptor/AcctMaxRestrictedMethodInterceptor.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/interceptor/AcctMaxRestrictedMethodInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..07b8f5c64e483c396346509c3b1fc55828c48462 --- /dev/null +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/interceptor/AcctMaxRestrictedMethodInterceptor.java @@ -0,0 +1,77 @@ +package org.dromara.sms4j.core.proxy.interceptor; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.sms4j.api.proxy.AbstractGenericMethodInterceptor; +import org.dromara.sms4j.api.proxy.Restricted; +import org.dromara.sms4j.core.proxy.SmsProxyFactory; +import org.dromara.sms4j.core.proxy.strategy.IRestrictedMethodStrategy; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; + + +/** + * 短信发送账号级上限拦截器 + * + * @author sh1yu + * @since 2023/10/27 13:03 + */ +@Slf4j +public class AcctMaxRestrictedMethodInterceptor extends AbstractGenericMethodInterceptor implements Restricted { + + @Override + public int getOrder() { + return SmsProxyFactory.ACCT_RESTRICTED_METHOD_INTERCEPTOR; + } + + @Override + public void beforeSendMessage(String phone, String message) { + getStrategy().restricted(Collections.singletonList(phone)); + } + + @Override + protected void afterSendMessage(String phone, String message, Object result, Exception ex) { + getStrategy().flushRecord(Collections.singletonList(phone)); + } + + @Override + protected void beforeSendMessageWithTemplate(String phone, LinkedHashMap messages) { + getStrategy().restricted(Collections.singletonList(phone)); + } + + @Override + protected void afterSendMessageWithTemplate(String phone, LinkedHashMap messages, Object result, Exception ex) { + getStrategy().flushRecord(Collections.singletonList(phone)); + } + + @Override + public void beforeSendMessageWithCustomTemplate(String phone, String templateId, LinkedHashMap messages) { + getStrategy().restricted(Collections.singletonList(phone)); + } + + @Override + protected void afterSendMessageWithCustomTemplate(String phone, String templateId, LinkedHashMap messages, Object result, Exception ex) { + getStrategy().flushRecord(Collections.singletonList(phone)); + } + + @Override + public void beforeMassTexting(List phones, String message) { + getStrategy().restricted(phones); + } + + @Override + protected void afterMassTexting(List phones, String message, Object result, Exception ex) { + getStrategy().flushRecord(phones); + } + + @Override + public void beforeMassTextingWithTemplate(List phones, String templateId, LinkedHashMap messages) { + getStrategy().restricted(phones); + } + + @Override + protected void afterMassTextingWithTemplate(List phones, String templateId, LinkedHashMap messages, Object result, Exception ex) { + getStrategy().flushRecord(phones); + } +} diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/interceptor/BlackListMethodInterceptor.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/interceptor/BlackListMethodInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..81e3a9441867129521831366f70c02069578ffb3 --- /dev/null +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/interceptor/BlackListMethodInterceptor.java @@ -0,0 +1,50 @@ +package org.dromara.sms4j.core.proxy.interceptor; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.sms4j.api.proxy.AbstractGenericMethodInterceptor; +import org.dromara.sms4j.api.proxy.Restricted; +import org.dromara.sms4j.core.proxy.SmsProxyFactory; +import org.dromara.sms4j.core.proxy.strategy.IListCheckMethodStrategy; + +import java.util.*; + +/** + * 黑名单前置拦截器 + * + * @author sh1yu + * @since 2023/10/27 13:03 + */ +@Slf4j +public class BlackListMethodInterceptor extends AbstractGenericMethodInterceptor implements Restricted { + + + @Override + public int getOrder() { + return SmsProxyFactory.BLACK_LIST_METHOD_INTERCEPTOR_ORDER; + } + + @Override + protected void beforeSendMessage(String phone, String message) { + getStrategy().checkListWithRecord(Collections.singletonList(phone)); + } + + @Override + protected void beforeSendMessageWithTemplate(String phone, LinkedHashMap messages) { + getStrategy().checkListWithRecord(Collections.singletonList(phone)); + } + + @Override + protected void beforeSendMessageWithCustomTemplate(String phone, String templateId, LinkedHashMap messages) { + getStrategy().checkListWithRecord(Collections.singletonList(phone)); + } + + @Override + protected void beforeMassTexting(List phones, String message) { + getStrategy().checkListWithRecord(phones); + } + + @Override + protected void beforeMassTextingWithTemplate(List phones, String templateId, LinkedHashMap messages) { + getStrategy().checkListWithRecord(phones); + } +} diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/interceptor/BlackListRecordingProxyInterceptor.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/interceptor/BlackListRecordingProxyInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..e18e0c4f0523d82b5244d18cd125d222ea0ca1ff --- /dev/null +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/interceptor/BlackListRecordingProxyInterceptor.java @@ -0,0 +1,83 @@ +package org.dromara.sms4j.core.proxy.interceptor; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.sms4j.api.proxy.SmsMethodInterceptor; +import org.dromara.sms4j.api.proxy.SmsMethodType; +import org.dromara.sms4j.core.proxy.strategy.IBlackListManageStrategy; +import org.dromara.sms4j.core.proxy.SmsProxyFactory; + +import java.lang.reflect.Method; +import java.util.List; +import java.util.Objects; + + +/** + * 黑名单记录代理拦截器,仅 + * + * @author sh1yu + * @since 2023/10/27 13:03 + */ +@Slf4j +public class BlackListRecordingProxyInterceptor implements SmsMethodInterceptor { + + @Override + public int getOrder() { + return SmsProxyFactory.BLACK_LIST_RECORDING_INTERCEPTOR_ORDER; + } + + /** + * 前置拦截,在方法执行前调用 + * + * @param methodType 方法类型,若不是{@link SmsMethodType}则可能为{@code null} + * @param method 方法 + * @param target 调用对象 + * @param params 调用参数 + * @return 调用参数 + * @implNote 若重写此方法,则务必调用{@link #doBeforeInvoke}方法实现调用分发 + */ + @Override + public Object[] beforeInvoke(SmsMethodType methodType, Method method, Object target, Object[] params) { + if (Objects.nonNull(methodType)) { + // 将方法分发到具体的调用 + doBeforeInvoke(params, methodType); + } + return params; + } + + @SuppressWarnings("unchecked") + protected final void doBeforeInvoke(Object[] params, SmsMethodType methodType) { + switch (methodType) { + case ADD_BLACK_LIST_ITEM: + getStrategy().addBlackListItem((String) params[0]); + break; + case REMOVE_BLACK_LIST_ITEM: + getStrategy().removeBlackListItem((String) params[0]); + break; + case ADD_BLACK_LIST_ITEMS: + getStrategy().addBlackListItems((List) params[0]); + break; + case REMOVE_BLACK_LIST_ITEMS: + getStrategy().removeBlackListItems((List) params[0]); + break; + case GET_TRIGGER_RECORD: + getStrategy().getTriggerRecord(); + break; + case CLEAR_TRIGGER_RECORD: + getStrategy().clearTriggerRecord(); + break; + default: // do nothing + } + } + + public Object afterCompletion( + SmsMethodType methodType, Method method, Object target,Object[] params, Object result, Exception ex) { + if (Objects.nonNull(methodType)) { + switch (methodType) { + case GET_TRIGGER_RECORD: + return getStrategy().getTriggerRecord(); + } + } + return result; + } + +} diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/interceptor/ChannelMaxRestrictedMethodInterceptor.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/interceptor/ChannelMaxRestrictedMethodInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..55a733d5983825806897fdf1d5fee11975955f3b --- /dev/null +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/interceptor/ChannelMaxRestrictedMethodInterceptor.java @@ -0,0 +1,41 @@ +package org.dromara.sms4j.core.proxy.interceptor; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.proxy.AbstractGenericMethodInterceptor; +import org.dromara.sms4j.api.proxy.Restricted; +import org.dromara.sms4j.api.proxy.SmsMethodType; +import org.dromara.sms4j.core.proxy.SmsProxyFactory; +import org.dromara.sms4j.core.proxy.strategy.IChannelRestrictedStrategy; + +import java.lang.reflect.Method; + + +/** + * 短信发送渠道级上限拦截器 + * + * @author sh1yu + * @since 2023/12/22 13:03 + */ +@Slf4j +public class ChannelMaxRestrictedMethodInterceptor extends AbstractGenericMethodInterceptor implements Restricted { + + @Override + public int getOrder() { + return SmsProxyFactory.SINGLE_BLEND_RESTRICTED_METHOD_INTERCEPTOR_ORDER; + } + + @Override + public Object[] beforeInvoke(SmsMethodType methodType, Method method, Object target, Object[] params) { + getStrategy().restricted(methodType, (SmsBlend) target); + return params; + } + + @Override + public Object afterCompletion(SmsMethodType methodType, Method method,Object target, Object[] params, Object result, Exception ex) { + getStrategy().flushRecord(methodType, (SmsBlend) target); + return result; + } + + +} diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/interceptor/SpanMaxRestrictedMethodInterceptor.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/interceptor/SpanMaxRestrictedMethodInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..59d6d548f4721e4071ebe641ff488ffd5831a45c --- /dev/null +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/interceptor/SpanMaxRestrictedMethodInterceptor.java @@ -0,0 +1,20 @@ +package org.dromara.sms4j.core.proxy.interceptor; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.sms4j.api.proxy.Restricted; +import org.dromara.sms4j.core.proxy.SmsProxyFactory; + +/** + * 短信发送时间级上限拦截器 + * + * @author sh1yu + * @since 2023/10/27 13:03 + */ +@Slf4j +public class SpanMaxRestrictedMethodInterceptor extends AcctMaxRestrictedMethodInterceptor implements Restricted { + @Override + public int getOrder() { + return SmsProxyFactory.SPAN_RESTRICTED_METHOD_INTERCEPTOR; + } + +} diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/interceptor/SyncMethodParamValidateMethodInterceptor.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/interceptor/SyncMethodParamValidateMethodInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..876ca62024b7940e2c941e481aa661317d58e254 --- /dev/null +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/interceptor/SyncMethodParamValidateMethodInterceptor.java @@ -0,0 +1,60 @@ +package org.dromara.sms4j.core.proxy.interceptor; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.sms4j.api.proxy.AbstractGenericMethodInterceptor; +import org.dromara.sms4j.core.proxy.SmsProxyFactory; +import org.dromara.sms4j.core.proxy.strategy.ISyncMethodParamValidateStrategy; + +import java.util.*; + + + +/** + * 同步调用方法参数校验前置拦截器 + * + * @author sh1yu + * @since 2023/10/27 13:03 + */ +@Slf4j +public class SyncMethodParamValidateMethodInterceptor extends AbstractGenericMethodInterceptor { + + @Override + public int getOrder() { + return SmsProxyFactory.CORE_PARAM_VALIDATE_METHOD_INTERCEPTOR_ORDER; + } + + @Override + public void beforeSendMessage(String phone, String message) { + ISyncMethodParamValidateStrategy strategy = getStrategy(); + strategy.validatePhone(phone); + strategy.validateMessage(message); + } + + @Override + protected void beforeSendMessageWithTemplate(String phone, LinkedHashMap messages) { + ISyncMethodParamValidateStrategy strategy = getStrategy(); + strategy.validatePhone(phone); + strategy.validateMessage(messages); + } + + @Override + public void beforeSendMessageWithCustomTemplate(String phone, String templateId, LinkedHashMap messages) { + ISyncMethodParamValidateStrategy strategy = getStrategy(); + strategy.validatePhone(phone); + strategy.validateMessages(templateId, messages); + } + + @Override + public void beforeMassTexting(List phones, String message) { + ISyncMethodParamValidateStrategy strategy = getStrategy(); + strategy.validateMessage(message); + strategy.validatePhones(phones); + } + + @Override + public void beforeMassTextingWithTemplate(List phones, String templateId, LinkedHashMap messages) { + ISyncMethodParamValidateStrategy strategy = getStrategy(); + strategy.validatePhones(phones); + strategy.validateMessages(templateId, messages); + } +} diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/processor/BlackListRecordingProcessor.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/processor/BlackListRecordingProcessor.java deleted file mode 100644 index dd3c370138a42349497cad801a8b9a5360387250..0000000000000000000000000000000000000000 --- a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/processor/BlackListRecordingProcessor.java +++ /dev/null @@ -1,101 +0,0 @@ -package org.dromara.sms4j.core.proxy.processor; - -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; -import org.dromara.sms4j.api.dao.SmsDao; -import org.dromara.sms4j.api.proxy.SmsProcessor; -import org.dromara.sms4j.api.proxy.aware.SmsConfigAware; -import org.dromara.sms4j.api.proxy.aware.SmsDaoAware; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; - -/** - * 黑名单前置拦截执行器 - * - * @author sh1yu - * @since 2023/10/27 13:03 - */ -@Setter -@Slf4j -public class BlackListRecordingProcessor implements SmsProcessor, SmsDaoAware, SmsConfigAware { - SmsDao smsDao; - - Object smsConfig; - - @Override - public int getOrder(){ - return 1; - } - - @Override - public Object[] preProcessor(Method method, Object source, Object[] param) { - //添加到黑名单 - if ("joinInBlacklist".equals(method.getName())) { - String cacheKey = getCacheKey(); - ArrayList blackList = getBlackList(cacheKey); - blackList.add((String) param[0]); - flushBlackList(cacheKey,blackList); - } - //从黑名单移除 - if ("removeFromBlacklist".equals(method.getName())) { - String cacheKey = getCacheKey(); - ArrayList blackList = getBlackList(cacheKey); - blackList.remove((String) param[0]); - flushBlackList(cacheKey,blackList); - } - //批量添加到黑名单 - if ("batchJoinBlacklist".equals(method.getName())) { - String cacheKey = getCacheKey(); - ArrayList blackList = getBlackList(cacheKey); - blackList.addAll((List) param[0]); - flushBlackList(cacheKey,blackList); - } - //批量从黑名单移除 - if ("batchRemovalFromBlacklist".equals(method.getName())) { - String cacheKey = getCacheKey(); - ArrayList blackList = getBlackList(cacheKey); - blackList.removeAll((List) param[0]); - flushBlackList(cacheKey,blackList); - } - return param; - } - - /** - * 构建CacheKey - * - * @return CacheKey - */ - public String getCacheKey(){ - return "sms:blacklist:global"; - } - - /** - * 获取黑名单,没有就新建 - * - * @param cacheKey 缓存key - * @return 黑名单 - */ - public ArrayList getBlackList(String cacheKey) { - ArrayList blackList; - Object cache = smsDao.get(cacheKey); - if (null != cache) { - blackList = (ArrayList) cache; - return blackList; - } - blackList = new ArrayList<>(); - smsDao.set("sms:blacklist:global", blackList); - return blackList; - } - - /** - * 让黑名单生效 - * - * @param cacheKey 缓存key - * @param blackList 黑命令 - */ - public void flushBlackList(String cacheKey ,ArrayList blackList) { - smsDao.set(cacheKey, blackList); - } -} diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/processor/CoreMethodParamValidateProcessor.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/processor/CoreMethodParamValidateProcessor.java deleted file mode 100644 index 64ec8447e45d1bbb466cc83c6f33869a4e3847b5..0000000000000000000000000000000000000000 --- a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/processor/CoreMethodParamValidateProcessor.java +++ /dev/null @@ -1,85 +0,0 @@ -package org.dromara.sms4j.core.proxy.processor; - -import cn.hutool.core.util.StrUtil; -import lombok.extern.slf4j.Slf4j; -import org.dromara.sms4j.api.proxy.CoreMethodProcessor; -import org.dromara.sms4j.comm.exception.SmsBlendException; - -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Objects; - - -/** - * 核心方法参数校验前置拦截执行器 - * - * @author sh1yu - * @since 2023/10/27 13:03 - */ -@Slf4j -public class CoreMethodParamValidateProcessor implements CoreMethodProcessor { - @Override - public int getOrder() { - return -1; - } - - @Override - public void sendMessagePreProcess(String phone, Object message) { - validatePhone(phone); - validateMessage(message); - } - - @Override - public void sendMessageByTemplatePreProcess(String phone, String templateId, LinkedHashMap messages) { - validatePhone(phone); - validateMessages(templateId, messages); - } - - @Override - public void massTextingPreProcess(List phones, String message) { - validateMessage(message); - validatePhones(phones); - } - - @Override - public void massTextingByTemplatePreProcess(List phones, String templateId, LinkedHashMap messages) { - validatePhones(phones); - validateMessages(templateId, messages); - } - - public void validateMessage(Object messageObj) { - if(Objects.isNull(messageObj)){ - throw new SmsBlendException("cant send a null message!"); - } - if (messageObj instanceof String){ - String message = (String) messageObj; - if (StrUtil.isBlank(message)) { - throw new SmsBlendException("cant send a null message!"); - } - } - } - - public void validatePhone(String phone) { - if (StrUtil.isBlank(phone)) { - throw new SmsBlendException("cant send message to null!"); - } - } - - public void validatePhones(List phones) { - if (null == phones) { - throw new SmsBlendException("cant send message to null!"); - } - for (String phone : phones) { - if (StrUtil.isNotBlank(phone)) { - return; - } - } - throw new SmsBlendException("cant send message to null!"); - } - - public void validateMessages(String templateId, LinkedHashMap messages) { - if (StrUtil.isEmpty(templateId)) { - throw new SmsBlendException("cant use template without template param"); - } - } -} diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/processor/RestrictedProcessor.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/processor/RestrictedProcessor.java deleted file mode 100644 index d7eb50e26a85466b919e7596f5a3e0f74a85f6ba..0000000000000000000000000000000000000000 --- a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/processor/RestrictedProcessor.java +++ /dev/null @@ -1,104 +0,0 @@ -package org.dromara.sms4j.core.proxy.processor; - -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; -import org.dromara.sms4j.api.dao.SmsDao; -import org.dromara.sms4j.api.proxy.CoreMethodProcessor; -import org.dromara.sms4j.api.proxy.aware.SmsDaoAware; -import org.dromara.sms4j.comm.exception.SmsBlendException; -import org.dromara.sms4j.comm.utils.SmsUtils; -import org.dromara.sms4j.provider.config.SmsConfig; -import org.dromara.sms4j.provider.factory.BeanFactory; - -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Objects; - - -/** - * 短信发送账号级上限前置拦截执行器 - * - * @author sh1yu - * @since 2023/10/27 13:03 - */ -@Setter -@Slf4j -public class RestrictedProcessor implements CoreMethodProcessor, SmsDaoAware { - static Long minTimer = 60 * 1000L; - static Long accTimer = 24 * 60 * 60 * 1000L; - private static final String REDIS_KEY = "sms:restricted:"; - - /** - * 缓存实例 - */ - private SmsDao smsDao; - - @Override - public int getOrder() { - return 3; - } - - @Override - public void sendMessagePreProcess(String phone, Object message) { - doRestricted(Collections.singletonList(phone)); - } - - @Override - public void sendMessageByTemplatePreProcess(String phone, String templateId, LinkedHashMap messages) { - doRestricted(Collections.singletonList(phone)); - } - - @Override - public void massTextingPreProcess(List phones, String message) { - doRestricted(phones); - } - - @Override - public void massTextingByTemplatePreProcess(List phones, String templateId, LinkedHashMap messages) { - doRestricted(phones); - } - - public void doRestricted(List phones) { - if (Objects.isNull(smsDao)) { - throw new SmsBlendException("The smsDao tool could not be found"); - } - SmsConfig config = BeanFactory.getSmsConfig(); - // 如果未开始限制则不做处理 - if (!config.getRestricted()){ - return; - } - // 每日最大发送量 - Integer accountMax = config.getAccountMax(); - // 每分钟最大发送量 - Integer minuteMax = config.getMinuteMax(); - for (String phone : phones) { - // 是否配置了每日限制 - if (SmsUtils.isNotEmpty(accountMax)) { - Integer i = (Integer) smsDao.get(REDIS_KEY + phone + "max"); - if (SmsUtils.isEmpty(i)) { - smsDao.set(REDIS_KEY + phone + "max", 1, accTimer / 1000); - } else if (i >= accountMax) { - log.info("The phone: {},number of short messages reached the maximum today", phone); - throw new SmsBlendException("The phone: {},number of short messages reached the maximum today", phone); - } else { - smsDao.set(REDIS_KEY + phone + "max", i + 1, accTimer / 1000); - } - } - // 是否配置了每分钟最大限制 - if (SmsUtils.isNotEmpty(minuteMax)) { - Integer o = (Integer) smsDao.get(REDIS_KEY + phone); - if (SmsUtils.isNotEmpty(o)) { - if (o < minuteMax) { - smsDao.set(REDIS_KEY + phone, o + 1, minTimer / 1000); - } else { - log.info("The phone: {},number of short messages reached the maximum today", phone); - throw new SmsBlendException("The phone: {} Text messages are sent too often!", phone); - } - } else { - smsDao.set(REDIS_KEY + phone, 1, minTimer / 1000); - } - } - } - } -} diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/processor/SingleBlendRestrictedProcessor.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/processor/SingleBlendRestrictedProcessor.java deleted file mode 100644 index 445e1f46108cfb4fac947e4bfd1318666a1cb484..0000000000000000000000000000000000000000 --- a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/processor/SingleBlendRestrictedProcessor.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.dromara.sms4j.core.proxy.processor; - -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; -import org.dromara.sms4j.api.SmsBlend; -import org.dromara.sms4j.api.dao.SmsDao; -import org.dromara.sms4j.api.proxy.SmsProcessor; -import org.dromara.sms4j.api.proxy.aware.SmsBlendConfigAware; -import org.dromara.sms4j.api.proxy.aware.SmsDaoAware; -import org.dromara.sms4j.comm.exception.SmsBlendException; -import org.dromara.sms4j.comm.utils.SmsUtils; - -import java.lang.reflect.Method; -import java.util.Map; - - -/** - * 短信发送渠道级上限前置拦截执行器 - * - * @author sh1yu - * @since 2023/10/27 13:03 - */ -@Setter -@Slf4j -public class SingleBlendRestrictedProcessor implements SmsProcessor, SmsDaoAware, SmsBlendConfigAware { - - private static final String REDIS_KEY = "sms:restricted:"; - - /** - * 缓存实例 - */ - private SmsDao smsDao; - - Map smsBlendsConfig; - - @Override - public int getOrder() { - return 2; - } - - @Override - public Object[] preProcessor(Method method, Object source, Object[] param) { - String name = method.getName(); - if (!"sendMessage".equals(name) && !"massText".equals(name)) { - return param; - } - SmsBlend smsBlend = (SmsBlend) source; - String configId = smsBlend.getConfigId(); - Map targetConfig = (Map) smsBlendsConfig.get(configId); - Object maximumObj = targetConfig.get("maximum"); - if (SmsUtils.isEmpty(maximumObj)) { - return param; - } - int maximum = 0; - try{ - maximum = Integer.parseInt(String.valueOf(maximumObj)) ; - }catch (Exception e){ - log.error("获取厂商级发送上限参数错误!请检查!"); - throw new IllegalArgumentException("获取厂商级发送上限参数错误"); - } - Integer i = (Integer) smsDao.get(REDIS_KEY + configId + "maximum"); - if (SmsUtils.isEmpty(i)) { - smsDao.set(REDIS_KEY + configId + "maximum", 1); - } else if (i >= maximum) { - log.info("The channel: {},messages reached the maximum", configId); - throw new SmsBlendException("The channel: {},messages reached the maximum", configId); - } else { - smsDao.set(REDIS_KEY + configId + "maximum", i + 1); - } - return param; - } -} diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/IBlackListManageStrategy.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/IBlackListManageStrategy.java new file mode 100644 index 0000000000000000000000000000000000000000..27039eebe880ee3fefd567999221d4f915d34b6a --- /dev/null +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/IBlackListManageStrategy.java @@ -0,0 +1,64 @@ +package org.dromara.sms4j.core.proxy.strategy; + +import org.dromara.sms4j.api.proxy.aware.InterceptorStrategySmsDaoAware; +import org.dromara.sms4j.api.strategy.IInterceptorStrategy; + +import java.util.List; + +/** + *

说明:黑名单管理策略接口 + * + * @author :sh1yu + */ +public interface IBlackListManageStrategy extends InterceptorStrategySmsDaoAware, IInterceptorStrategy { + + /** + *

说明:加入黑名单 + * addBlackListItem + * + * @param phone 需要加入黑名单的手机号 + * @author :sh1yu + */ + void addBlackListItem(String phone); + + /** + *

说明:批量加入黑名单 + * addBlackListItems + * + * @param phones 需要加入黑名单的手机号 + * @author :sh1yu + */ + void addBlackListItems(List phones); + + /** + *

说明:从黑名单移除 + * removeBlackListItem + * + * @param phone 需要加入黑名单的手机号 + * @author :sh1yu + */ + void removeBlackListItem(String phone); + + /** + *

说明:批量从黑名单移除 + * removeBlackListItems + * + * @param phones 需要移除黑名单的手机号数组 + * @author :sh1yu + */ + void removeBlackListItems(List phones); + + /** + *

说明:获取黑名单触发记录 + * + * @author :sh1yu + */ + List getTriggerRecord(); + + /** + *

说明:清理黑名单触发记录 + * + * @author :sh1yu + */ + void clearTriggerRecord(); +} diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/IChannelRestrictedStrategy.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/IChannelRestrictedStrategy.java new file mode 100644 index 0000000000000000000000000000000000000000..7219076e762506fe8d8a0ee73128738fae60d91e --- /dev/null +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/IChannelRestrictedStrategy.java @@ -0,0 +1,18 @@ +package org.dromara.sms4j.core.proxy.strategy; + +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.proxy.SmsMethodType; +import org.dromara.sms4j.api.proxy.aware.InterceptorStrategySmsBlendConfigAware; +import org.dromara.sms4j.api.proxy.aware.InterceptorStrategySmsDaoAware; +import org.dromara.sms4j.api.strategy.IInterceptorStrategy; + +/** + * 短信发送渠道级上限拦截策略 + * + * @author sh1yu + * @since 2023/12/22 13:03 + */ +public interface IChannelRestrictedStrategy extends IInterceptorStrategy, InterceptorStrategySmsDaoAware, InterceptorStrategySmsBlendConfigAware { + void restricted(SmsMethodType methodType, SmsBlend smsBlend); + void flushRecord(SmsMethodType methodType, SmsBlend smsBlend); +} \ No newline at end of file diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/IListCheckMethodStrategy.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/IListCheckMethodStrategy.java new file mode 100644 index 0000000000000000000000000000000000000000..7018b53dbdd96a99b3f3869ff39b13dca7b1aed3 --- /dev/null +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/IListCheckMethodStrategy.java @@ -0,0 +1,17 @@ +package org.dromara.sms4j.core.proxy.strategy; + +import org.dromara.sms4j.api.proxy.aware.InterceptorStrategySmsDaoAware; +import org.dromara.sms4j.api.strategy.IInterceptorStrategy; + +import java.util.List; + +/** + * 黑名单前置拦截执行器 + * + * @author sh1yu + * @since 2023/10/27 13:03 + */ +public interface IListCheckMethodStrategy extends IInterceptorStrategy, InterceptorStrategySmsDaoAware { + + void checkListWithRecord(List phones); +} diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/IRestrictedMethodStrategy.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/IRestrictedMethodStrategy.java new file mode 100644 index 0000000000000000000000000000000000000000..911083f65a666aac5726bf4b9d914e1a4512e06b --- /dev/null +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/IRestrictedMethodStrategy.java @@ -0,0 +1,19 @@ +package org.dromara.sms4j.core.proxy.strategy; + +import org.dromara.sms4j.api.strategy.IInterceptorStrategy; + +import java.util.List; + + +/** + * 短信发送基础上限前置拦截执行器 + * + * @author sh1yu + * @since 2023/10/27 13:03 + */ +public interface IRestrictedMethodStrategy extends IInterceptorStrategy { + + void restricted(List phones); + + void flushRecord(List phones); +} diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/ISyncMethodParamValidateStrategy.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/ISyncMethodParamValidateStrategy.java new file mode 100644 index 0000000000000000000000000000000000000000..2f089f2366c66091f817f725da3dae9e80995567 --- /dev/null +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/ISyncMethodParamValidateStrategy.java @@ -0,0 +1,28 @@ +package org.dromara.sms4j.core.proxy.strategy; + + +import org.dromara.sms4j.api.strategy.IInterceptorStrategy; + +import java.util.LinkedHashMap; +import java.util.List; + + +/** + * 同步调用方法参数校验前置拦截执行器 + * + * @author sh1yu + * @since 2023/10/27 13:03 + * TODO 异步调用和延迟调用的参数是否需要校验? + */ +public interface ISyncMethodParamValidateStrategy extends IInterceptorStrategy { + + void validateMessage(Object messageObj); + + void validatePhone(String phone); + + void validatePhones(List phones); + + void validateMessages(String templateId, LinkedHashMap messages); + + +} diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/impl/DefaultAcctMaxRestrictedMethodStrategy.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/impl/DefaultAcctMaxRestrictedMethodStrategy.java new file mode 100644 index 0000000000000000000000000000000000000000..16bea11a07ae4e2159311953a47535c122b68d46 --- /dev/null +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/impl/DefaultAcctMaxRestrictedMethodStrategy.java @@ -0,0 +1,87 @@ +package org.dromara.sms4j.core.proxy.strategy.impl; + +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.dromara.sms4j.api.dao.SmsDao; +import org.dromara.sms4j.api.proxy.aware.InterceptorStrategySmsDaoAware; +import org.dromara.sms4j.comm.exception.SmsBlendException; +import org.dromara.sms4j.comm.utils.SmsUtils; +import org.dromara.sms4j.core.proxy.interceptor.AcctMaxRestrictedMethodInterceptor; +import org.dromara.sms4j.core.proxy.strategy.IRestrictedMethodStrategy; +import org.dromara.sms4j.provider.config.SmsConfig; +import org.dromara.sms4j.provider.factory.BeanFactory; + +import java.util.List; +import java.util.Objects; + + +/** + * 默认短信发送账号级上限拦截策略 + * + * @author sh1yu + * @since 2023/12/22 13:03 + */ +@Slf4j +public class DefaultAcctMaxRestrictedMethodStrategy implements IRestrictedMethodStrategy, InterceptorStrategySmsDaoAware { + + @Setter + SmsDao smsDao; + /** + * 每个账号最多可发送条数 + * TODO 每个账号最多可发送条数应当可配置 + */ + private static final Long ACCOUNT_MAXIMUM_COUNT = 24 * 60 * 60 * 1000L; + /** + * redis缓存前缀 + * TODO redis缓存前缀应当可配置 + */ + private static final String REDIS_KEY = "sms:restricted:"; + private static final String REDIS_KEY_FIX = "max"; + + public void restricted(List phones) { + if (Objects.isNull(smsDao)) { + throw new SmsBlendException("The dao tool could not be found"); + } + SmsConfig config = BeanFactory.getSmsConfig(); + // 每日最大发送量 + Integer accountMax = config.getAccountMax(); + for (String phone : phones) { + doRestricted(accountMax, phone); + } + } + + public void doRestricted(Integer accountMax, String phone) { + // 是否配置了每日限制 + if (SmsUtils.isNotEmpty(accountMax)) { + Integer count = (Integer) smsDao.get(REDIS_KEY + phone + REDIS_KEY_FIX); + if (SmsUtils.isNotEmpty(count) && count >= accountMax) { + log.info("The phone: {}, number of short messages reached the maximum today", phone); + throw new SmsBlendException("The phone:" + phone + ",number of short messages reached the maximum today"); + } + } + } + + public void flushRecord(List phones) { + SmsConfig config = BeanFactory.getSmsConfig(); + // 每日最大发送量 + Integer accountMax = config.getAccountMax(); + for (String phone : phones) { + doFlushRecord(accountMax, phone); + } + } + + public void doFlushRecord(Integer accountMax, String phone) { + if (SmsUtils.isNotEmpty(accountMax)) { + Integer count = (Integer) smsDao.get(REDIS_KEY + phone + REDIS_KEY_FIX); + if (SmsUtils.isEmpty(count)) { + count = 0; + } + smsDao.set(REDIS_KEY + phone + REDIS_KEY_FIX, count + 1, ACCOUNT_MAXIMUM_COUNT / 1000); + } + } + + @Override + public Class aPendingProblemWith() { + return AcctMaxRestrictedMethodInterceptor.class; + } +} diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/processor/BlackListProcessor.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/impl/DefaultBlackListCheckStrategy.java similarity index 30% rename from sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/processor/BlackListProcessor.java rename to sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/impl/DefaultBlackListCheckStrategy.java index 82a692d338c15e9313fa61f15588be350a4fcbdf..a00213fdde6044abefe87acefbb09cacd82cb444 100644 --- a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/processor/BlackListProcessor.java +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/impl/DefaultBlackListCheckStrategy.java @@ -1,60 +1,53 @@ -package org.dromara.sms4j.core.proxy.processor; +package org.dromara.sms4j.core.proxy.strategy.impl; +import cn.hutool.core.collection.CollUtil; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.dromara.sms4j.api.dao.SmsDao; -import org.dromara.sms4j.api.proxy.CoreMethodProcessor; -import org.dromara.sms4j.api.proxy.aware.SmsDaoAware; +import org.dromara.sms4j.api.proxy.aware.InterceptorStrategySmsDaoAware; import org.dromara.sms4j.comm.exception.SmsBlendException; +import org.dromara.sms4j.core.proxy.interceptor.BlackListMethodInterceptor; +import org.dromara.sms4j.core.proxy.strategy.IListCheckMethodStrategy; import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedHashMap; +import java.util.Date; import java.util.List; /** - * 黑名单前置拦截执行器 + * 默认黑名单前置拦截策略 * * @author sh1yu * @since 2023/10/27 13:03 */ -@Setter @Slf4j -public class BlackListProcessor implements CoreMethodProcessor, SmsDaoAware { - SmsDao smsDao; +public class DefaultBlackListCheckStrategy implements InterceptorStrategySmsDaoAware, IListCheckMethodStrategy { - @Override - public int getOrder() { - return 0; - } + private static final String CONFIG_PROPERTIES_PREFIX = "sms:blacklist:global"; + private static final String TRIGGER_RECORDING_PREFIX = "sms:blacklist:trigger"; - @Override - public void sendMessagePreProcess(String phone, Object message) { - doRestricted(Collections.singletonList(phone)); - } + @Setter + private SmsDao smsDao; @Override - public void sendMessageByTemplatePreProcess(String phone, String templateId, LinkedHashMap messages) { - doRestricted(Collections.singletonList(phone)); + public Class aPendingProblemWith() { + return BlackListMethodInterceptor.class; } @Override - public void massTextingPreProcess(List phones, String message) { - doRestricted(phones); - } - - @Override - public void massTextingByTemplatePreProcess(List phones, String templateId, LinkedHashMap messages) { - doRestricted(phones); - } - - public void doRestricted(List phones) { - ArrayList blackList = (ArrayList) smsDao.get("sms:blacklist:global"); - if(null==blackList){ + @SuppressWarnings("unchecked") + public void checkListWithRecord(List phones) { + List blackList = (List) smsDao.get(CONFIG_PROPERTIES_PREFIX); + if (CollUtil.isEmpty(blackList)) { return; } for (String phone : phones) { if (blackList.stream().anyMatch(black -> black.replace("-","").equals(phone))) { + List triggerList = (List) smsDao.get(TRIGGER_RECORDING_PREFIX); + if (CollUtil.isEmpty(triggerList)){ + triggerList = new ArrayList<>(); + } + triggerList.add(phone+": has trigger the blackList Check at - "+new Date()); + smsDao.set(TRIGGER_RECORDING_PREFIX,triggerList); throw new SmsBlendException("The phone:", phone + " hit global blacklist!"); } } diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/impl/DefaultBlackListManageStrategy.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/impl/DefaultBlackListManageStrategy.java new file mode 100644 index 0000000000000000000000000000000000000000..2070dacc0fc7abe6c1c841b2e4087aa6cd64c759 --- /dev/null +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/impl/DefaultBlackListManageStrategy.java @@ -0,0 +1,83 @@ +package org.dromara.sms4j.core.proxy.strategy.impl; + +import cn.hutool.core.collection.CollUtil; +import lombok.Setter; +import org.dromara.sms4j.api.dao.SmsDao; +import org.dromara.sms4j.core.proxy.strategy.IBlackListManageStrategy; +import org.dromara.sms4j.core.proxy.interceptor.BlackListRecordingProxyInterceptor; + +import java.util.ArrayList; +import java.util.List; + +public class DefaultBlackListManageStrategy implements IBlackListManageStrategy { + private static final String REDIS_KEY_PREFIX = "sms:blacklist:global"; + private static final String TRIGGER_RECORDING_PREFIX = "sms:blacklist:trigger"; + + + @Setter + private SmsDao smsDao; + + public List getTriggerRecord(){ + List triggerList = (List) smsDao.get(TRIGGER_RECORDING_PREFIX); + if (CollUtil.isEmpty(triggerList)){ + triggerList = new ArrayList<>(); + } + return triggerList; + } + + public void clearTriggerRecord(){ + smsDao.set(TRIGGER_RECORDING_PREFIX,new ArrayList()); + } + + public void addBlackListItem(String phone) { + List blackList = getBlackList(); + blackList.add(phone); + flushBlackList(blackList); + } + + public void addBlackListItems(List phones) { + List blackList = getBlackList(); + blackList.addAll(phones); + flushBlackList(blackList); + } + + public void removeBlackListItem(String phone) { + List blackList = getBlackList(); + blackList.remove(phone); + flushBlackList(blackList); + } + + public void removeBlackListItems(List phones) { + List blackList = getBlackList(); + blackList.removeAll(phones); + flushBlackList(blackList); + } + + + @SuppressWarnings("unchecked") + private List getBlackList() { + List blackList; + Object cache = smsDao.get(REDIS_KEY_PREFIX); + if (null != cache) { + blackList = (List) cache; + return blackList; + } + blackList = new ArrayList<>(); + smsDao.set(REDIS_KEY_PREFIX, blackList); + return blackList; + } + + /** + * 刷新黑名单 + * + * @param blackList 新的黑名单列表 + */ + private void flushBlackList(List blackList) { + smsDao.set(REDIS_KEY_PREFIX, blackList); + } + + @Override + public Class aPendingProblemWith() { + return BlackListRecordingProxyInterceptor.class; + } +} diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/impl/DefaultChannelMaxRestrictedMethodStrategy.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/impl/DefaultChannelMaxRestrictedMethodStrategy.java new file mode 100644 index 0000000000000000000000000000000000000000..50fb0b04f2822a94db5ca100b1e66c5abe43bb9a --- /dev/null +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/impl/DefaultChannelMaxRestrictedMethodStrategy.java @@ -0,0 +1,100 @@ +package org.dromara.sms4j.core.proxy.strategy.impl; + +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.dao.SmsDao; +import org.dromara.sms4j.api.proxy.SmsMethodType; +import org.dromara.sms4j.api.proxy.aware.InterceptorStrategySmsBlendConfigAware; +import org.dromara.sms4j.api.proxy.aware.InterceptorStrategySmsDaoAware; +import org.dromara.sms4j.comm.exception.SmsBlendException; +import org.dromara.sms4j.comm.utils.SmsUtils; +import org.dromara.sms4j.core.proxy.interceptor.ChannelMaxRestrictedMethodInterceptor; +import org.dromara.sms4j.core.proxy.strategy.IChannelRestrictedStrategy; + +import java.util.Map; +import java.util.Objects; + +/** + * 短信发送时间级上限拦截策略 + * + * @author sh1yu + * @since 2023/12/22 13:03 + */ +@Slf4j +public class DefaultChannelMaxRestrictedMethodStrategy implements IChannelRestrictedStrategy, InterceptorStrategySmsDaoAware, InterceptorStrategySmsBlendConfigAware { + + + private static final String REDIS_KEY = "sms:restricted:"; + private static final String REDIS_KEY_FIX = "maximum"; + private static final String SEND_MESSAGE_METHOD = "sendMessage"; + private static final String MASS_TEXT_METHOD = "massText"; + + /** + * 缓存实例 + */ + @Setter + private SmsDao smsDao; + + @Setter + private Map> smsBlendsConfig; + + public void restricted(SmsMethodType methodType, SmsBlend smsBlend) { + if (shouldSkip(methodType)) { + return; + } + String configId = smsBlend.getConfigId(); + Map targetConfig = smsBlendsConfig.get(configId); + Object maximumObj = targetConfig.get(REDIS_KEY_FIX); + if (SmsUtils.isEmpty(maximumObj)) { + return; + } + int maximum; + if (maximumObj instanceof String){ + maximum = Integer.parseInt((String) maximumObj); + }else{ + try { + maximum = (int) maximumObj; + } catch (Exception e) { + log.error("获取厂商级发送上限参数错误!请检查!"); + throw new IllegalArgumentException("获取厂商级发送上限参数错误"); + } + } + Integer i = (Integer) smsDao.get(REDIS_KEY + configId + REDIS_KEY_FIX); + if (SmsUtils.isNotEmpty(i) && i >= maximum) { + log.info("The channel: {}, messages reached the maximum", configId); + throw new SmsBlendException("The channel: " + configId + ", messages reached the maximum", configId); + } + } + + + public void flushRecord(SmsMethodType methodType, SmsBlend smsBlend) { + if (shouldSkip(methodType)) { + return; + } + String configId = smsBlend.getConfigId(); + Map targetConfig = smsBlendsConfig.get(configId); + Object maximumObj = targetConfig.get(REDIS_KEY_FIX); + if (SmsUtils.isEmpty(maximumObj)) { + return; + } + Integer i = (Integer) smsDao.get(REDIS_KEY + configId + REDIS_KEY_FIX); + if (SmsUtils.isEmpty(i)) { + smsDao.set(REDIS_KEY + configId + REDIS_KEY_FIX, 1); + } else { + smsDao.set(REDIS_KEY + configId + REDIS_KEY_FIX, i + 1); + } + } + + + public boolean shouldSkip(SmsMethodType methodType) { + return Objects.isNull(methodType) + || !(Objects.equals(methodType.getName(), SEND_MESSAGE_METHOD) + || Objects.equals(methodType.getName(), MASS_TEXT_METHOD)); + } + + @Override + public Class aPendingProblemWith() { + return ChannelMaxRestrictedMethodInterceptor.class; + } +} \ No newline at end of file diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/impl/DefaultSpanMaxRestrictedMethodStrategy.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/impl/DefaultSpanMaxRestrictedMethodStrategy.java new file mode 100644 index 0000000000000000000000000000000000000000..469369c34e3e756326da0547e32fdf599ce3c77b --- /dev/null +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/impl/DefaultSpanMaxRestrictedMethodStrategy.java @@ -0,0 +1,87 @@ +package org.dromara.sms4j.core.proxy.strategy.impl; + +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.dromara.sms4j.api.dao.SmsDao; +import org.dromara.sms4j.api.proxy.aware.InterceptorStrategySmsDaoAware; +import org.dromara.sms4j.comm.exception.SmsBlendException; +import org.dromara.sms4j.comm.utils.SmsUtils; +import org.dromara.sms4j.core.proxy.interceptor.SpanMaxRestrictedMethodInterceptor; +import org.dromara.sms4j.core.proxy.strategy.IRestrictedMethodStrategy; +import org.dromara.sms4j.provider.config.SmsConfig; +import org.dromara.sms4j.provider.factory.BeanFactory; + +import java.util.List; +import java.util.Objects; + +/** + * 短信发送时间级上限拦截策略 + * + * @author sh1yu + * @since 2023/12/22 13:03 + */ +@Slf4j +public class DefaultSpanMaxRestrictedMethodStrategy implements IRestrictedMethodStrategy, InterceptorStrategySmsDaoAware { + + @Setter + SmsDao smsDao; + + /** + * 每分钟最多可发送条数 + * TODO 每分钟最多可发送条数应当可配置 + */ + private static final Long MINUTE_MAXIMUM_COUNT = 60 * 1000L; + /** + * redis缓存前缀 + * TODO redis缓存前缀应当可配置 + */ + private static final String REDIS_KEY = "sms:restricted:"; + private static final String REDIS_KEY_FIX = "span:"; + + public void restricted(List phones) { + if (Objects.isNull(smsDao)) { + throw new SmsBlendException("The dao tool could not be found"); + } + SmsConfig config = BeanFactory.getSmsConfig(); + // 每分钟最大发送量 + Integer minuteMax = config.getMinuteMax(); + for (String phone : phones) { + doRestricted(minuteMax, phone); + } + } + + public void doRestricted(Integer minuteMax, String phone) { + // 是否配置了每分钟最大限制 + if (SmsUtils.isNotEmpty(minuteMax)) { + Integer count = (Integer) smsDao.get(REDIS_KEY + phone + REDIS_KEY_FIX); + if (SmsUtils.isNotEmpty(count) && minuteMax <= count) { + log.info("The phone: {}, number of short messages reached the maximum today", phone); + throw new SmsBlendException("The phone:", phone + " Text messages are sent too often!"); + } + } + } + + public void flushRecord(List phones) { + SmsConfig config = BeanFactory.getSmsConfig(); + // 每分钟最大发送量 + Integer minuteMax = config.getMinuteMax(); + for (String phone : phones) { + doFlushRecord(minuteMax, phone); + } + } + + public void doFlushRecord(Integer minuteMax, String phone) { + if (SmsUtils.isNotEmpty(minuteMax)) { + Integer count = (Integer) smsDao.get(REDIS_KEY + phone+ REDIS_KEY_FIX); + if (SmsUtils.isEmpty(count)) { + count = 0; + } + smsDao.set(REDIS_KEY + phone + REDIS_KEY_FIX, count + 1, MINUTE_MAXIMUM_COUNT / 1000); + } + } + + @Override + public Class aPendingProblemWith() { + return SpanMaxRestrictedMethodInterceptor.class; + } +} diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/impl/DefaultSyncMethodParamValidateStrategy.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/impl/DefaultSyncMethodParamValidateStrategy.java new file mode 100644 index 0000000000000000000000000000000000000000..62f94c20f25840cfa020bb65ed33202752453491 --- /dev/null +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/proxy/strategy/impl/DefaultSyncMethodParamValidateStrategy.java @@ -0,0 +1,51 @@ +package org.dromara.sms4j.core.proxy.strategy.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.text.CharSequenceUtil; +import lombok.extern.slf4j.Slf4j; +import org.dromara.sms4j.comm.exception.SmsBlendException; +import org.dromara.sms4j.core.proxy.interceptor.SyncMethodParamValidateMethodInterceptor; +import org.dromara.sms4j.core.proxy.strategy.ISyncMethodParamValidateStrategy; + +import java.util.LinkedHashMap; +import java.util.List; + + +/** + * 同步调用方法参数校验策略 + * + * @author sh1yu + * @since 2023/10/27 13:03 + */ +@Slf4j +public class DefaultSyncMethodParamValidateStrategy implements ISyncMethodParamValidateStrategy { + + public void validateMessage(Object messageObj) { + /*if (null == messageObj) + throw new SmsBlendException("can't send a null message!");*/ + } + + public void validatePhone(String phone) { + if (CharSequenceUtil.isEmpty(phone)) { + throw new SmsBlendException("can't send message to null!"); + } + } + + public void validatePhones(List phones) { + if (CollUtil.isEmpty(phones)) { + throw new SmsBlendException("can't send message to null!"); + } + phones.forEach(this::validatePhone); + } + + public void validateMessages(String templateId, LinkedHashMap messages) { + if (CharSequenceUtil.isEmpty(templateId)){ + throw new SmsBlendException("can't use a null template"); + } + validateMessage(messages); + } + + public Class aPendingProblemWith() { + return SyncMethodParamValidateMethodInterceptor.class; + } +} diff --git a/sms4j-example/Component/Customize/src/main/java/sms4j/dao/MySmsDao.java b/sms4j-example/Component/Customize/src/main/java/sms4j/dao/MySmsDao.java new file mode 100644 index 0000000000000000000000000000000000000000..301aa672be236f7a40144dcbb00d21a8cbc18454 --- /dev/null +++ b/sms4j-example/Component/Customize/src/main/java/sms4j/dao/MySmsDao.java @@ -0,0 +1,178 @@ +package sms4j.dao; + +import org.dromara.sms4j.api.dao.SmsDao; +import org.dromara.sms4j.api.dao.SmsDaoDefaultImpl; +import org.dromara.sms4j.comm.exception.SmsBlendException; + +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.ConcurrentHashMap; + +import lombok.Data; + + +//最简单的SmsDao实现 +public class MySmsDao implements SmsDao { + { + System.out.println("加载了自定义实现的SmsDao"); + } + private static volatile MySmsDao INSTANCE; + private static final Timer TIMER = new Timer(); + private static final ConcurrentHashMap DATA_MAP = new ConcurrentHashMap<>(); + + /** + * 缓存时间(单位:毫秒,默认 24 小时) + */ + private static final long DEFAULT_CACHE_TIME = 24 * 60 * 60 * 1000L; + + /** + * 定时器执行频率(单位:毫秒,默认 30 秒) + */ + private static final long TIMER_INTERVAL = 30 * 1000L; + + private MySmsDao() {} + + /** + * 获取唯一实例 + * + * @return 唯一实例 + */ + public static MySmsDao getInstance() { + if (null == INSTANCE) { + synchronized (MySmsDao.class) { + if (null == INSTANCE) { + INSTANCE = new MySmsDao(); + // 初始化定时器 + initTimer(); + } + } + } + return INSTANCE; + } + + @Override + public void set(String key, Object value, long cacheTime) { + System.out.println("存入:"+key+" - "+value); + + cacheTime = cacheTime * 1000L; + DataWrapper dataWrapper = DATA_MAP.get(key); + if (null != dataWrapper) { + dataWrapper.update(value, cacheTime); + } else { + dataWrapper = new DataWrapper(value, cacheTime); + DATA_MAP.put(key, dataWrapper); + } + } + + @Override + public void set(String key, Object value) { + this.set(key, value, DEFAULT_CACHE_TIME); + } + + @Override + public Object get(String key) { + System.out.println("获取:"+key); + + DataWrapper dataWrapper = DATA_MAP.get(key); + if (dataWrapper != null && !dataWrapper.isExpired()) { + Object data = dataWrapper.data; + System.out.println(data); + return data; + } + return null; + } + + @Override + public Object remove(String key) { + return DATA_MAP.remove(key); + } + + @Override + public void clean() { + DATA_MAP.clear(); + } + + /** + * 初始化定时器 + */ + private static void initTimer() { + TIMER.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + try { + clearExpiredData(); + } catch (Exception e) { + throw new SmsBlendException(e.getMessage()); + } + } + }, TIMER_INTERVAL, TIMER_INTERVAL); + } + + /** + * 清除过期数据 + */ + private static void clearExpiredData() { + List expiredKeyList = new LinkedList<>(); + for (Map.Entry entry : DATA_MAP.entrySet()) { + if (entry.getValue().isExpired()) { + expiredKeyList.add(entry.getKey()); + } + } + for (String key : expiredKeyList) { + DATA_MAP.remove(key); + } + } + + /** + * 数据封装 + */ + @Data + private static class DataWrapper { + + /** + * 数据 + */ + private Object data; + + /** + * 过期时间 + */ + private long expiredTime; + + /** + * 缓存时间 + */ + private long cacheTime; + + private DataWrapper(Object data, long cacheTime) { + this.update(data, cacheTime); + } + + /** + * 更新数据及缓存时间 + * + * @param data 数据 + * @param cacheTime 缓存时间 + */ + public void update(Object data, long cacheTime) { + this.data = data; + this.cacheTime = cacheTime; + this.expiredTime = System.currentTimeMillis() + cacheTime; + } + + /** + * 数据是否过期 + * + * @return true:过期,false:未过期 + */ + public boolean isExpired() { + if (this.expiredTime > 0) { + return System.currentTimeMillis() > this.expiredTime; + } + return true; + } + } +} diff --git a/sms4j-example/Component/Customize/src/main/java/sms4j/interceptor/IMyIntercepterStrategy.java b/sms4j-example/Component/Customize/src/main/java/sms4j/interceptor/IMyIntercepterStrategy.java new file mode 100644 index 0000000000000000000000000000000000000000..2e8013fe4e93e0d1ba848c52937f67da0efe85b6 --- /dev/null +++ b/sms4j-example/Component/Customize/src/main/java/sms4j/interceptor/IMyIntercepterStrategy.java @@ -0,0 +1,10 @@ +package sms4j.interceptor; + +import org.dromara.sms4j.api.strategy.IInterceptorStrategy; + + +public interface IMyIntercepterStrategy extends IInterceptorStrategy { + + public void doSomeThing(); + +} diff --git a/sms4j-example/Component/Customize/src/main/java/sms4j/interceptor/MyIntercepterStrategy.java b/sms4j-example/Component/Customize/src/main/java/sms4j/interceptor/MyIntercepterStrategy.java new file mode 100644 index 0000000000000000000000000000000000000000..55e267e978741111fb94cf4f221cf2bda111bc14 --- /dev/null +++ b/sms4j-example/Component/Customize/src/main/java/sms4j/interceptor/MyIntercepterStrategy.java @@ -0,0 +1,16 @@ +package sms4j.interceptor; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MyIntercepterStrategy implements IMyIntercepterStrategy { + + public void doSomeThing(){ + System.out.println("自定义拦截器一顿处理"); + } + + @Override + public Class aPendingProblemWith() { + return MyInterceptor.class; + } +} diff --git a/sms4j-example/Component/Customize/src/main/java/sms4j/interceptor/MyInterceptor.java b/sms4j-example/Component/Customize/src/main/java/sms4j/interceptor/MyInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..c71c25d82d2511edee78672f890ee7de45de3e86 --- /dev/null +++ b/sms4j-example/Component/Customize/src/main/java/sms4j/interceptor/MyInterceptor.java @@ -0,0 +1,30 @@ +package sms4j.interceptor; + +import org.dromara.sms4j.api.proxy.SmsMethodInterceptor; +import org.dromara.sms4j.api.proxy.SmsMethodType; + +import java.lang.reflect.Method; +import java.util.Objects; + +public class MyInterceptor implements SmsMethodInterceptor { + + public Object afterCompletion( + SmsMethodType methodType, Method method, Object target, Object[] params, Object result, Exception ex) { + if (Objects.nonNull(methodType)) { + switch (methodType) { + case MASS_TEXTING: + case SEND_MESSAGE: + System.out.println("自定义拦截器被触发,触发顺序为"+getOrder()); + getStrategy().doSomeThing(); + break; + } + } + + return result; + } + + public int getOrder() { + return Integer.MAX_VALUE - 1; + } + +} diff --git a/sms4j-example/Component/Customize/src/main/java/sms4j/interceptor/MySecIntercepterStrategy.java b/sms4j-example/Component/Customize/src/main/java/sms4j/interceptor/MySecIntercepterStrategy.java new file mode 100644 index 0000000000000000000000000000000000000000..c99bf1c871e6170184d414bd0e54680eab47135f --- /dev/null +++ b/sms4j-example/Component/Customize/src/main/java/sms4j/interceptor/MySecIntercepterStrategy.java @@ -0,0 +1,16 @@ +package sms4j.interceptor; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MySecIntercepterStrategy implements IMyIntercepterStrategy { + + public void doSomeThing(){ + System.out.println("替换过的自定义拦截器一顿处理"); + } + + @Override + public Class aPendingProblemWith() { + return MyInterceptor.class; + } +} diff --git a/sms4j-example/Component/Customize/src/main/java/sms4j/local/a/AConfig.java b/sms4j-example/Component/Customize/src/main/java/sms4j/local/a/AConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..e0fb6bfe88d93d12c75e924ec1a46f419fc6fd26 --- /dev/null +++ b/sms4j-example/Component/Customize/src/main/java/sms4j/local/a/AConfig.java @@ -0,0 +1,29 @@ +package sms4j.local.a; + + +import lombok.Data; +import org.dromara.sms4j.api.universal.SupplierConfig; +import org.dromara.sms4j.provider.config.BaseConfig; + +/** + * 新增厂商的配置实现{@link SupplierConfig} + * 这个类中还可以添加厂商携带的其他属性 + * + * @author huangchengxing + */ + +@Data +public class AConfig extends BaseConfig { + + + private String supplier = "a"; + //其他属性 + private String qi2Ta1Shu3Xing4; + + + + @Override + public String getSupplier() { + return supplier; + } +} diff --git a/sms4j-example/Component/Customize/src/main/java/sms4j/local/a/AFactory.java b/sms4j-example/Component/Customize/src/main/java/sms4j/local/a/AFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..de191a1b98787020e06051c7d00cf800626e58c7 --- /dev/null +++ b/sms4j-example/Component/Customize/src/main/java/sms4j/local/a/AFactory.java @@ -0,0 +1,37 @@ +package sms4j.local.a; + +import org.dromara.sms4j.provider.factory.BaseProviderFactory; + +/** + * 新增厂商的工厂实现{@link ASmsImpl} + * 这个类就是获取LocalSmsImpl的工厂 + * + * @author huangchengxing + */ +public class AFactory implements BaseProviderFactory { + + private static final AFactory INSTANCE = new AFactory(); + + /** + * 获取建造者实例 + * @return 建造者实例 + */ + public static AFactory instance() { + return INSTANCE; + } + + @Override + public ASmsImpl createSms(AConfig aConfig) { + return new ASmsImpl(aConfig); + } + + @Override + public Class getConfigClass() { + return AConfig.class; + } + + @Override + public String getSupplier() { + return "a"; + } +} diff --git a/sms4j-example/Component/Customize/src/main/java/sms4j/local/a/ASmsImpl.java b/sms4j-example/Component/Customize/src/main/java/sms4j/local/a/ASmsImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..309064f327c46467a53cec7983e7cab517016bc6 --- /dev/null +++ b/sms4j-example/Component/Customize/src/main/java/sms4j/local/a/ASmsImpl.java @@ -0,0 +1,108 @@ +package sms4j.local.a; + +import cn.hutool.json.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.callback.CallBack; +import org.dromara.sms4j.api.entity.SmsResponse; +import org.dromara.sms4j.comm.constant.SupplierConstant; +import org.dromara.sms4j.comm.delayedTime.DelayedTime; +import org.dromara.sms4j.provider.service.AbstractSmsBlend; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.concurrent.Executor; + +/** + * 新增厂商的具体短信逻辑实现{@link SmsBlend} + * 本类的逻辑:总是在日志中输出参数信息,并成功返回调用结果。 + * + * @author huangchengxing + */ + + +@Slf4j +public class ASmsImpl extends AbstractSmsBlend { + + /** + * ASmsImpl + *

构造器,用于构造短信实现模块 + * + * @author :Wind + */ + public ASmsImpl(AConfig config, Executor pool, DelayedTime delayedTime) { + super(config, pool, delayedTime); + + } + + /** + * ASmsImpl + *

构造器,用于构造短信实现模块 + */ + public ASmsImpl(AConfig config) { + super(config); + } + + @Override + public String getSupplier() { + return "a"; + } + + @Override + public SmsResponse sendMessage(String phone, String message) { + System.out.println("AAAAAAAAAAAAsend message: phone={"+phone+"}, message={"+message+"}" +this.getConfigId()); + return getResponse(new JSONObject() + .set("phone", phone) + .set("message", message)); + } + + @Override + public SmsResponse sendMessage(String phone, LinkedHashMap messages) { + System.out.println("AAAAAAAAAAAAsend message: phone={"+phone+"}, messages size={"+messages.size()+"}" ); + return getResponse(new JSONObject() + .set("phone", phone) + .set("messages", new JSONObject(messages))); + } + + + @Override + public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap messages) { + System.out.println("AAAAAAAAAAAAsend message: phone={"+phone+"},templateId={"+templateId+"}, messages size={"+ (null == messages?null:messages.size())+"}" ); + return getResponse(new JSONObject() + .set("phone", phone) + .set("templateId", templateId) + .set("messages", new JSONObject(messages))); + } + + @Override + public SmsResponse massTexting(List phones, String message) { + System.out.println("AAAAAAAAAAAAsend message: phone size={"+phones.size()+"}, messages={"+message+"}" ); + return getResponse(new JSONObject() + .set("phones", phones) + .set("message", message)); + } + + @Override + public SmsResponse massTexting(List phones, String templateId, LinkedHashMap messages) { + System.out.println("AAAAAAAAAAAAsend massTexting: phone size={"+phones.size()+"},templateId={"+templateId+"}, messages size={"+(null == messages?null:messages.size())+"}" ); + return getResponse(new JSONObject() + .set("phones", phones) + .set("templateId", templateId) + .set("messages", new JSONObject(messages))); + } + + /* + *

说明:封装结果的方法(可以没有) + * getResponse + * + * @param resJson 厂商的返回信息 + * @author :Wind + * */ + private SmsResponse getResponse(JSONObject resJson) { + SmsResponse smsResponse = new SmsResponse(); + smsResponse.setSuccess(true); + smsResponse.setData(resJson); + smsResponse.setConfigId(getConfigId()); + return smsResponse; + } +} diff --git a/sms4j-example/Component/Customize/src/main/java/sms4j/local/b/BConfig.java b/sms4j-example/Component/Customize/src/main/java/sms4j/local/b/BConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..ee2aa6e489e68689061989cce584736a548d6db7 --- /dev/null +++ b/sms4j-example/Component/Customize/src/main/java/sms4j/local/b/BConfig.java @@ -0,0 +1,26 @@ +package sms4j.local.b; + + +import lombok.Data; +import org.dromara.sms4j.api.universal.SupplierConfig; +import org.dromara.sms4j.provider.config.BaseConfig; + +/** + * 新增厂商的配置实现{@link SupplierConfig} + * 这个类中还可以添加厂商携带的其他属性 + * + * @author huangchengxing + */ + +@Data +public class BConfig extends BaseConfig { + + private String supplier = "b"; + //其他属性 + private String qi2Ta1Shu3Xing4; + + @Override + public String getSupplier() { + return supplier; + } +} diff --git a/sms4j-example/Component/Customize/src/main/java/sms4j/local/b/BFactory.java b/sms4j-example/Component/Customize/src/main/java/sms4j/local/b/BFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..e7979fd1982850550927c8cbaa13ac5a9f6e690c --- /dev/null +++ b/sms4j-example/Component/Customize/src/main/java/sms4j/local/b/BFactory.java @@ -0,0 +1,37 @@ +package sms4j.local.b; + +import org.dromara.sms4j.provider.factory.BaseProviderFactory; + +/** + * 新增厂商的工厂实现{@link BSmsImpl} + * 这个类就是获取LocalSmsImpl的工厂 + * + * @author huangchengxing + */ +public class BFactory implements BaseProviderFactory { + + private static final BFactory INSTANCE = new BFactory(); + + /** + * 获取建造者实例 + * @return 建造者实例 + */ + public static BFactory instance() { + return INSTANCE; + } + + @Override + public BSmsImpl createSms(BConfig aConfig) { + return new BSmsImpl(aConfig); + } + + @Override + public Class getConfigClass() { + return BConfig.class; + } + + @Override + public String getSupplier() { + return "b"; + } +} diff --git a/sms4j-example/Component/Customize/src/main/java/sms4j/local/b/BSmsImpl.java b/sms4j-example/Component/Customize/src/main/java/sms4j/local/b/BSmsImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..0e73f9c3e83bc0959b58121790efdb2af07994a3 --- /dev/null +++ b/sms4j-example/Component/Customize/src/main/java/sms4j/local/b/BSmsImpl.java @@ -0,0 +1,109 @@ +package sms4j.local.b; + +import cn.hutool.json.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.callback.CallBack; +import org.dromara.sms4j.api.entity.SmsResponse; +import org.dromara.sms4j.comm.delayedTime.DelayedTime; +import org.dromara.sms4j.provider.service.AbstractSmsBlend; +import sms4j.local.a.AConfig; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.concurrent.Executor; + +/** + * 新增厂商的具体短信逻辑实现{@link SmsBlend} + * 本类的逻辑:总是在日志中输出参数信息,并成功返回调用结果。 + * + * @author huangchengxing + */ + + +@Slf4j +public class BSmsImpl extends AbstractSmsBlend { + + /** + * ASmsImpl + *

构造器,用于构造短信实现模块 + * + * @author :Wind + */ + public BSmsImpl(BConfig config, Executor pool, DelayedTime delayedTime) { + super(config, pool, delayedTime); + } + + /** + * ASmsImpl + *

构造器,用于构造短信实现模块 + */ + public BSmsImpl(BConfig config) { + super(config); + } + + @Override + public String getSupplier() { + return "b"; + } + + @Override + public SmsResponse sendMessage(String phone, String message) { + System.out.println("BBBBBBBBBBBBBBsend message: phone={"+phone+"}, message={"+message+"}" +this.getConfigId()); + return getResponse(new JSONObject() + .set("phone", phone) + .set("message", message)); + } + + @Override + public SmsResponse sendMessage(String phone, LinkedHashMap messages) { + System.out.println("BBBBBBBBBBBBBBsend message: phone={"+phone+"}, messages={"+messages.size()+"}" ); + return getResponse(new JSONObject() + .set("phone", phone) + .set("messages", new JSONObject(messages))); + } + + + @Override + public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap messages) { + System.out.println("BBBBBBBBBBBBBBsend message: phone={"+phone+"},templateId={"+templateId+"}, messages={"+(null == messages?null:messages.size())+"}" ); + return getResponse(new JSONObject() + .set("phone", phone) + .set("templateId", templateId) + .set("messages", new JSONObject(messages))); + } + + @Override + public SmsResponse massTexting(List phones, String message) { + System.out.println("BBBBBBBBBBBBBBsend message: phone={"+phones.size()+"}, messages={"+message+"}" ); + return getResponse(new JSONObject() + .set("phones", phones) + .set("message", message)); + } + + @Override + public SmsResponse massTexting(List phones, String templateId, LinkedHashMap messages) { + System.out.println("BBBBBBBBBBBBBBsend message: phone={"+phones.size()+"},templateId={"+templateId+"}, messages={"+(null == messages?null:messages.size())+"}" ); + return getResponse(new JSONObject() + .set("phones", phones) + .set("templateId", templateId) + .set("messages", new JSONObject(messages))); + } + + + + /* + *

说明:封装结果的方法(可以没有) + * getResponse + * + * @param resJson 厂商的返回信息 + * @author :Wind + * */ + private SmsResponse getResponse(JSONObject resJson) { + SmsResponse smsResponse = new SmsResponse(); + smsResponse.setSuccess(true); + smsResponse.setData(resJson); + smsResponse.setConfigId(getConfigId()); + return smsResponse; + } +} diff --git a/sms4j-example/Component/Customize/src/main/java/sms4j/local/c/CConfig.java b/sms4j-example/Component/Customize/src/main/java/sms4j/local/c/CConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..eb4da90350b829636a7dd27156f5704207827c72 --- /dev/null +++ b/sms4j-example/Component/Customize/src/main/java/sms4j/local/c/CConfig.java @@ -0,0 +1,26 @@ +package sms4j.local.c; + + +import lombok.Data; +import org.dromara.sms4j.api.universal.SupplierConfig; +import org.dromara.sms4j.provider.config.BaseConfig; + +/** + * 新增厂商的配置实现{@link SupplierConfig} + * 这个类中还可以添加厂商携带的其他属性 + * + * @author huangchengxing + */ + +@Data +public class CConfig extends BaseConfig { + + private String supplier = "c"; + //其他属性 + private String qi2Ta1Shu3Xing4; + + @Override + public String getSupplier() { + return supplier; + } +} diff --git a/sms4j-example/Component/Customize/src/main/java/sms4j/local/c/CFactory.java b/sms4j-example/Component/Customize/src/main/java/sms4j/local/c/CFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..70fc8922a08c7e48ad5b9d2f7198f4944ebef4b3 --- /dev/null +++ b/sms4j-example/Component/Customize/src/main/java/sms4j/local/c/CFactory.java @@ -0,0 +1,37 @@ +package sms4j.local.c; + +import org.dromara.sms4j.provider.factory.BaseProviderFactory; + +/** + * 新增厂商的工厂实现{@link CSmsImpl} + * 这个类就是获取LocalSmsImpl的工厂 + * + * @author huangchengxing + */ +public class CFactory implements BaseProviderFactory { + + private static final CFactory INSTANCE = new CFactory(); + + /** + * 获取建造者实例 + * @return 建造者实例 + */ + public static CFactory instance() { + return INSTANCE; + } + + @Override + public CSmsImpl createSms(CConfig aConfig) { + return new CSmsImpl(aConfig); + } + + @Override + public Class getConfigClass() { + return CConfig.class; + } + + @Override + public String getSupplier() { + return "c"; + } +} diff --git a/sms4j-example/Component/Customize/src/main/java/sms4j/local/c/CSmsImpl.java b/sms4j-example/Component/Customize/src/main/java/sms4j/local/c/CSmsImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..ea8873742393fb80eda6933b39b738f28b3a8f2e --- /dev/null +++ b/sms4j-example/Component/Customize/src/main/java/sms4j/local/c/CSmsImpl.java @@ -0,0 +1,106 @@ +package sms4j.local.c; + +import cn.hutool.json.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.callback.CallBack; +import org.dromara.sms4j.api.entity.SmsResponse; +import org.dromara.sms4j.comm.delayedTime.DelayedTime; +import org.dromara.sms4j.provider.service.AbstractSmsBlend; +import sms4j.local.b.BConfig; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.concurrent.Executor; + +/** + * 新增厂商的具体短信逻辑实现{@link SmsBlend} + * 本类的逻辑:总是在日志中输出参数信息,并成功返回调用结果。 + * + * @author huangchengxing + */ + + +@Slf4j +public class CSmsImpl extends AbstractSmsBlend { + + /** + * ASmsImpl + *

构造器,用于构造短信实现模块 + * + * @author :Wind + */ + public CSmsImpl(CConfig config, Executor pool, DelayedTime delayedTime) { + super(config, pool, delayedTime); + } + + /** + * ASmsImpl + *

构造器,用于构造短信实现模块 + */ + public CSmsImpl(CConfig config) { + super(config); + } + + @Override + public String getSupplier() { + return "c"; + } + + @Override + public SmsResponse sendMessage(String phone, String message) { + System.out.println("CCCCCCCCCCCCCsend message: phone={"+phone+"}, message={"+message+"}"); + return getResponse(new JSONObject() + .set("phone", phone) + .set("message", message)); + } + + @Override + public SmsResponse sendMessage(String phone, LinkedHashMap messages) { + System.out.println("CCCCCCCCCCCCCsend message: phone={"+phone+"}, messages={"+messages.size()+"}" ); + return getResponse(new JSONObject() + .set("phone", phone) + .set("messages", new JSONObject(messages))); + } + + + @Override + public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap messages) { + System.out.println("CCCCCCCCCCCCCsend message: phone={"+phone+"},templateId={"+templateId+"}, messages={"+(null == messages?null:messages.size())+"}" ); + return getResponse(new JSONObject() + .set("phone", phone) + .set("templateId", templateId) + .set("messages", new JSONObject(messages))); + } + + @Override + public SmsResponse massTexting(List phones, String message) { + System.out.println("CCCCCCCCCCCCCsend message: phone={"+phones.size()+"}, messages={"+message+"}" ); + return getResponse(new JSONObject() + .set("phones", phones) + .set("message", message)); + } + + @Override + public SmsResponse massTexting(List phones, String templateId, LinkedHashMap messages) { + System.out.println("CCCCCCCCCCCCCsend message: phone={"+phones.size()+"},templateId={"+templateId+"}, messages={"+(null == messages?null:messages.size())+"}" ); + return getResponse(new JSONObject() + .set("phones", phones) + .set("templateId", templateId) + .set("messages", new JSONObject(messages))); + } + /* + *

说明:封装结果的方法(可以没有) + * getResponse + * + * @param resJson 厂商的返回信息 + * @author :Wind + * */ + private SmsResponse getResponse(JSONObject resJson) { + SmsResponse smsResponse = new SmsResponse(); + smsResponse.setSuccess(true); + smsResponse.setData(resJson); + smsResponse.setConfigId(getConfigId()); + return smsResponse; + } +} diff --git a/sms4j-example/Component/TestCase/README.MD b/sms4j-example/Component/TestCase/README.MD new file mode 100644 index 0000000000000000000000000000000000000000..7c1885ca77cd179b373fc17d05d72c46e8c87989 --- /dev/null +++ b/sms4j-example/Component/TestCase/README.MD @@ -0,0 +1,12 @@ +测试点,命名规则 + +1.账户级限制 +2.区间级限制 +3.黑名单记录 +4.黑名单限制 +5.渠道级限制 +6.参数校验 + +测试类以位视图的方式 +00000 全不涉及 +11111 全涉及 \ No newline at end of file diff --git a/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/ITest.java b/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/ITest.java new file mode 100644 index 0000000000000000000000000000000000000000..c3eb6477d788efc539c63be0b82ff9ab8076498c --- /dev/null +++ b/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/ITest.java @@ -0,0 +1,5 @@ +package org.dromara.sms4j.test; + +public interface ITest { + void test(); +} diff --git a/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/complexity/MultiChannelAllValidate.java b/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/complexity/MultiChannelAllValidate.java new file mode 100644 index 0000000000000000000000000000000000000000..91c7fec950a4277787f300d09bd87956b1f6dbf3 --- /dev/null +++ b/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/complexity/MultiChannelAllValidate.java @@ -0,0 +1,174 @@ + +package org.dromara.sms4j.test.complexity; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; + +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.entity.SmsResponse; +import org.dromara.sms4j.comm.exception.SmsBlendException; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.test.ITest; + +import cn.hutool.core.lang.Assert; + +/* +* 账号级上限:6 +* 时段极上限:5 +* 渠道级上限:8 +* */ +public class MultiChannelAllValidate implements ITest { + + private String PHONE = ""; + private String PHONE1 = ""; + private String CHANNEL1 = ""; + private String CHANNEL2 = ""; + private String CHANNEL3 = ""; + + public MultiChannelAllValidate(String PHONE, String PHONE1, String CHANNEL1, String CHANNEL2, String CHANNEL3) { + this.PHONE = PHONE; + this.PHONE1 = PHONE1; + this.CHANNEL1 = CHANNEL1; + this.CHANNEL2 = CHANNEL2; + this.CHANNEL3 = CHANNEL3; + } + + public void test() { + this.test0(); + this.test1(); + this.test2(); + this.test3(); + this.test4(); + this.test5(); + } + + //基础带参发送 + public void test0() { + SmsBlend smsBlend1 = SmsFactory.getBySupplier(CHANNEL1); + LinkedHashMap map = new LinkedHashMap(); + map.put("test", "400001"); + SmsResponse smsResponse1 = smsBlend1.sendMessage(PHONE, map); + Assert.isTrue(smsResponse1.isSuccess()); + SmsBlend smsBlend2 = SmsFactory.getBySupplier(CHANNEL2); + SmsResponse smsResponse2 = smsBlend2.sendMessage(PHONE, map); + Assert.isTrue(smsResponse2.isSuccess()); + SmsBlend smsBlend3 = SmsFactory.getBySupplier(CHANNEL3); + SmsResponse smsResponse3 = smsBlend3.sendMessage(PHONE, map); + Assert.isTrue(smsResponse3.isSuccess()); + } + + + //基础发送 + public void test1() { + SmsBlend smsBlend1 = SmsFactory.getBySupplier(CHANNEL1); + SmsResponse smsResponse1 = smsBlend1.sendMessage(PHONE1, "400002"); + Assert.isTrue(smsResponse1.isSuccess()); + SmsBlend smsBlend2 = SmsFactory.getBySupplier(CHANNEL2); + SmsResponse smsResponse2 = smsBlend2.sendMessage(PHONE1, "400002"); + Assert.isTrue(smsResponse2.isSuccess()); + SmsBlend smsBlend3 = SmsFactory.getBySupplier(CHANNEL3); + SmsResponse smsResponse3 = smsBlend3.sendMessage(PHONE1, "400002"); + Assert.isTrue(smsResponse3.isSuccess()); + } + + + //参数校验测试,以下同时列举了多种错误情况,会被框架校验住并报错 + public void test2() { + SmsBlendException knowEx = null; + try { + SmsFactory.getBySupplier(CHANNEL1).sendMessage("", "400003"); + } catch (SmsBlendException e) { + knowEx = e; + } + Assert.notNull(knowEx); + knowEx = null; + try { + SmsFactory.getBySupplier(CHANNEL3).massTexting(new ArrayList(), "400004"); + } catch (SmsBlendException e) { + knowEx = e; + } + Assert.notNull(knowEx); + } + + //黑名单测试 + public void test3() { + SmsBlend smsBlend = SmsFactory.getBySupplier(CHANNEL1); + //单黑名单添加 + smsBlend.joinInBlacklist(PHONE); + SmsBlendException knowEx = null; + try { + smsBlend.sendMessage(PHONE, "400005"); + } catch (SmsBlendException e) { + knowEx = e; + } + Assert.notNull(knowEx); + //单黑名单移除 + smsBlend.removeFromBlacklist(PHONE); + SmsResponse smsResponse = smsBlend.sendMessage(PHONE, "400006"); + Assert.isTrue(smsResponse.isSuccess()); + //批量黑名单添加 + smsBlend.batchJoinBlacklist(Collections.singletonList(PHONE)); + knowEx = null; + try { + smsBlend.sendMessage(PHONE, "400007"); + } catch (SmsBlendException e) { + knowEx = e; + } + Assert.notNull(knowEx); + //批量黑名单添加 + smsBlend.batchRemovalFromBlacklist(Collections.singletonList(PHONE)); + smsResponse = smsBlend.sendMessage(PHONE, "400008"); + Assert.isTrue(smsResponse.isSuccess()); + } + + //时段级上限测试、前面PHONE1在1分钟内已经成功发送5笔,再发就会报错 参数配置 5 停顿1分钟刷新时段级计数 + public void test4() { + SmsBlendException knowEx = null; + try { + SmsFactory.getBySupplier(CHANNEL1).sendMessage(PHONE, "400009"); + } catch (SmsBlendException e) { + knowEx = e; + } + Assert.notNull(knowEx); + System.out.println("等待时段刷新"); + try { + Thread.sleep(61 * 1000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + System.out.println("时段过期"); + } + + + //账户级上限测试、前面已经PHONE成功发送5笔再发一笔成功的,再发就会报错 参数配置 6 + public void test5() { + SmsResponse smsResponse = SmsFactory.getBySupplier(CHANNEL1).sendMessage(PHONE, "400010"); + Assert.isTrue(smsResponse.isSuccess()); + SmsBlendException knowEx = null; + try { + SmsFactory.getBySupplier(CHANNEL1).sendMessage(PHONE, "400012"); + } catch (SmsBlendException e) { + knowEx = e; + } + Assert.notNull(knowEx); + } + + //渠道级上限测试、前面已经CHANNEL1成功发送5笔再发送三笔成功的,再发就会报错 参数配置 8 + public void test6() { + SmsResponse smsResponse = SmsFactory.getBySupplier(CHANNEL1).sendMessage(PHONE, "400010"); + Assert.isTrue(smsResponse.isSuccess()); + SmsResponse smsResponse1 = SmsFactory.getBySupplier(CHANNEL1).sendMessage(PHONE, "400010"); + Assert.isTrue(smsResponse1.isSuccess()); + SmsResponse smsResponse2 = SmsFactory.getBySupplier(CHANNEL1).sendMessage(PHONE, "400010"); + Assert.isTrue(smsResponse2.isSuccess()); + SmsBlendException knowEx = null; + try { + SmsFactory.getBySupplier(CHANNEL1).sendMessage(PHONE1, "400013"); + } catch (SmsBlendException e) { + knowEx = e; + } + Assert.notNull(knowEx); + } +} + diff --git a/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/complexity/SimpleChannelAllValidate.java b/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/complexity/SimpleChannelAllValidate.java new file mode 100644 index 0000000000000000000000000000000000000000..25a7ea24a78e0b1fedb3328a1b70ffb79414d07f --- /dev/null +++ b/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/complexity/SimpleChannelAllValidate.java @@ -0,0 +1,162 @@ + +package org.dromara.sms4j.test.complexity; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; + +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.entity.SmsResponse; +import org.dromara.sms4j.api.manage.InterceptorStrategySmsManager; +import org.dromara.sms4j.comm.exception.SmsBlendException; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.test.ITest; + +import cn.hutool.core.lang.Assert; +import sms4j.interceptor.MySecIntercepterStrategy; + +/* +* 账号级上限:4 7 +* 时段极上限:3 5 +* 渠道级上限:5 8 +* */ +public class SimpleChannelAllValidate implements ITest { + + /** + * 填测试手机号 + */ + private String PHONE = ""; + private String PHONE1 = ""; + private String CHANNEL1 = ""; + public SimpleChannelAllValidate(String PHONE, String PHONE1, String CHANNEL1) { + this.PHONE = PHONE; + this.PHONE1 = PHONE1; + this.CHANNEL1 = CHANNEL1; + } + + public void test() { + this.test0(); + this.test1(); + this.test2(); + this.test3(); + this.test4(); + this.test5(); + } + + //基础带参发送 + public void test0() { + SmsBlend smsBlend = SmsFactory.getBySupplier(CHANNEL1); + LinkedHashMap map = new LinkedHashMap(); + map.put("test","400001"); + SmsResponse smsResponse = smsBlend.sendMessage(PHONE, map); + Assert.isTrue(smsResponse.isSuccess()); + SmsResponse smsResponse1 = smsBlend.sendMessage(PHONE, map); + Assert.isTrue(smsResponse1.isSuccess()); + SmsResponse smsResponse2 = smsBlend.sendMessage(PHONE, map); + Assert.isTrue(smsResponse2.isSuccess()); + } + + + //基础发送 + public void test1() { + SmsBlend smsBlend = SmsFactory.getBySupplier(CHANNEL1); + SmsResponse smsResponse = smsBlend.sendMessage(PHONE1, "400002"); + Assert.isTrue(smsResponse.isSuccess()); + } + + + //参数校验测试,以下同时列举了多种错误情况,会被框架校验住并报错 + public void test2() { + SmsBlendException knowEx = null; + try { + SmsFactory.getBySupplier(CHANNEL1).sendMessage("", "400003"); + } catch (SmsBlendException e) { + knowEx = e; + } + Assert.notNull(knowEx); + knowEx = null; + try { + SmsFactory.getBySupplier(CHANNEL1).massTexting(new ArrayList(), "400004"); + } catch (SmsBlendException e) { + knowEx = e; + } + Assert.notNull(knowEx); + } + + //黑名单测试 + public void test3() { + SmsBlend smsBlend = SmsFactory.getBySupplier(CHANNEL1); + //单黑名单添加 + smsBlend.joinInBlacklist(PHONE); + SmsBlendException knowEx = null; + try { + smsBlend.sendMessage(PHONE, "400005"); + } catch (SmsBlendException e) { + knowEx = e; + } + Assert.notNull(knowEx); + //单黑名单移除 + smsBlend.removeFromBlacklist(PHONE); + SmsResponse smsResponse = smsBlend.sendMessage(PHONE, "400006"); + Assert.isTrue(smsResponse.isSuccess()); + //批量黑名单添加 + smsBlend.batchJoinBlacklist(Collections.singletonList(PHONE)); + knowEx = null; + try { + smsBlend.sendMessage(PHONE, "400007"); + } catch (SmsBlendException e) { + knowEx = e; + } + Assert.notNull(knowEx); + //批量黑名单添加 + smsBlend.batchRemovalFromBlacklist(Collections.singletonList(PHONE)); + smsResponse = smsBlend.sendMessage(PHONE, "400008"); + Assert.isTrue(smsResponse.isSuccess()); + } + + //时段级上限测试、前面PHONE1在1分钟内已经成功发送3笔,再发就会报错 参数配置 3 停顿1分钟刷新时段级计数 + public void test4() { + SmsBlendException knowEx = null; + try { + SmsFactory.getBySupplier(CHANNEL1).sendMessage(PHONE, "400009"); + } catch (SmsBlendException e) { + knowEx = e; + } + Assert.notNull(knowEx); + System.out.println("等待时段刷新"); + try { + Thread.sleep(60 * 1000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + System.out.println("时段过期"); + } + + + //账户级上限测试、前面已经PHONE成功发送3笔再发一笔成功的,再发就会报错 参数配置 4 + public void test5() { + MySecIntercepterStrategy mySecIntercepterStrategy = new MySecIntercepterStrategy(); + InterceptorStrategySmsManager.setInterceptorStrategyMapping(mySecIntercepterStrategy); + SmsResponse smsResponse = SmsFactory.getBySupplier(CHANNEL1).sendMessage(PHONE, "400010"); + Assert.isTrue(smsResponse.isSuccess()); + SmsBlendException knowEx = null; + try { + SmsFactory.getBySupplier(CHANNEL1).sendMessage(PHONE, "400012"); + } catch (SmsBlendException e) { + knowEx = e; + } + Assert.notNull(knowEx); + } + + //渠道级上限测试、前面已经CHANNEL1成功发送5笔,再发就会报错 参数配置 5 + public void test6() { + SmsBlendException knowEx = null; + try { + SmsFactory.getBySupplier(CHANNEL1).sendMessage(PHONE1, "400013"); + } catch (SmsBlendException e) { + knowEx = e; + } + Assert.notNull(knowEx); + } +} + diff --git a/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/restricted/AcctMaxRestricted5Times.java b/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/restricted/AcctMaxRestricted5Times.java new file mode 100644 index 0000000000000000000000000000000000000000..497983bc79cb5c99b1539ad6d1bf407edc87e4e5 --- /dev/null +++ b/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/restricted/AcctMaxRestricted5Times.java @@ -0,0 +1,44 @@ +package org.dromara.sms4j.test.restricted; + +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.entity.SmsResponse; +import org.dromara.sms4j.comm.exception.SmsBlendException; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.test.ITest; + +import cn.hutool.core.lang.Assert; + +public class AcctMaxRestricted5Times implements ITest { + + private final String CHANNEL; + private final String PHONE; + + public AcctMaxRestricted5Times(String channel, String phone) { + CHANNEL = channel; + PHONE = phone; + } + + @Override + public void test() { + SmsBlend smsBlend = SmsFactory.getBySupplier(CHANNEL); + SmsResponse smsResponse1 = smsBlend.sendMessage(PHONE,"300001"); + Assert.isTrue(smsResponse1.isSuccess()); + SmsResponse smsResponse2 = smsBlend.sendMessage(PHONE,"300002"); + Assert.isTrue(smsResponse2.isSuccess()); + SmsResponse smsResponse3 = smsBlend.sendMessage(PHONE,"300003"); + Assert.isTrue(smsResponse3.isSuccess()); + SmsResponse smsResponse4 = smsBlend.sendMessage(PHONE,"300004"); + Assert.isTrue(smsResponse4.isSuccess()); + SmsResponse smsResponse5 = smsBlend.sendMessage(PHONE,"300005"); + Assert.isTrue(smsResponse5.isSuccess()); + //第六次发送已经达到渠道上限应该抛出异常 + SmsBlendException knowEx = null; + try { + smsBlend.sendMessage(PHONE,"300006"); + } catch (SmsBlendException e) { + knowEx = e; + } + Assert.notNull(knowEx); + + } +} diff --git a/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/restricted/ChannelMaxRestricted5Times.java b/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/restricted/ChannelMaxRestricted5Times.java new file mode 100644 index 0000000000000000000000000000000000000000..9fafc6fe398d4dbf8a7ceec180498d8462014363 --- /dev/null +++ b/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/restricted/ChannelMaxRestricted5Times.java @@ -0,0 +1,44 @@ +package org.dromara.sms4j.test.restricted; + +import cn.hutool.core.lang.Assert; + +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.entity.SmsResponse; +import org.dromara.sms4j.comm.exception.SmsBlendException; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.test.ITest; + +public class ChannelMaxRestricted5Times implements ITest { + + private final String CHANNEL; + private final String PHONE; + + public ChannelMaxRestricted5Times(String channel, String phone) { + CHANNEL = channel; + PHONE = phone; + } + + @Override + public void test() { + SmsBlend smsBlend = SmsFactory.getBySupplier(CHANNEL); + SmsResponse smsResponse1 = smsBlend.sendMessage(PHONE,"300001"); + Assert.isTrue(smsResponse1.isSuccess()); + SmsResponse smsResponse2 = smsBlend.sendMessage(PHONE,"300002"); + Assert.isTrue(smsResponse2.isSuccess()); + SmsResponse smsResponse3 = smsBlend.sendMessage(PHONE,"300003"); + Assert.isTrue(smsResponse3.isSuccess()); + SmsResponse smsResponse4 = smsBlend.sendMessage(PHONE,"300004"); + Assert.isTrue(smsResponse4.isSuccess()); + SmsResponse smsResponse5 = smsBlend.sendMessage(PHONE,"300005"); + Assert.isTrue(smsResponse5.isSuccess()); + //第六次发送已经达到渠道上限应该抛出异常 + SmsBlendException knowEx = null; + try { + smsBlend.sendMessage(PHONE,"300006"); + } catch (SmsBlendException e) { + knowEx = e; + } + Assert.notNull(knowEx); + + } +} diff --git a/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/restricted/SpanMaxRestricted5Times.java b/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/restricted/SpanMaxRestricted5Times.java new file mode 100644 index 0000000000000000000000000000000000000000..2378b96e17384106d7dcf119a30e63ba5d0bce6c --- /dev/null +++ b/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/restricted/SpanMaxRestricted5Times.java @@ -0,0 +1,44 @@ +package org.dromara.sms4j.test.restricted; + +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.entity.SmsResponse; +import org.dromara.sms4j.comm.exception.SmsBlendException; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.test.ITest; + +import cn.hutool.core.lang.Assert; + +public class SpanMaxRestricted5Times implements ITest { + + private final String CHANNEL; + private final String PHONE; + + public SpanMaxRestricted5Times(String channel, String phone) { + CHANNEL = channel; + PHONE = phone; + } + + @Override + public void test() { + SmsBlend smsBlend = SmsFactory.getBySupplier(CHANNEL); + SmsResponse smsResponse1 = smsBlend.sendMessage(PHONE,"300001"); + Assert.isTrue(smsResponse1.isSuccess()); + SmsResponse smsResponse2 = smsBlend.sendMessage(PHONE,"300002"); + Assert.isTrue(smsResponse2.isSuccess()); + SmsResponse smsResponse3 = smsBlend.sendMessage(PHONE,"300003"); + Assert.isTrue(smsResponse3.isSuccess()); + SmsResponse smsResponse4 = smsBlend.sendMessage(PHONE,"300004"); + Assert.isTrue(smsResponse4.isSuccess()); + SmsResponse smsResponse5 = smsBlend.sendMessage(PHONE,"300005"); + Assert.isTrue(smsResponse5.isSuccess()); + //第六次发送已经达到渠道上限应该抛出异常 + SmsBlendException knowEx = null; + try { + smsBlend.sendMessage(PHONE,"300006"); + } catch (SmsBlendException e) { + knowEx = e; + } + Assert.notNull(knowEx); + + } +} diff --git a/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/send/SimpleSendMsgById.java b/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/send/SimpleSendMsgById.java new file mode 100644 index 0000000000000000000000000000000000000000..3063e73d2a783e07b1042fe7e4ccf7919eeb2e97 --- /dev/null +++ b/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/send/SimpleSendMsgById.java @@ -0,0 +1,27 @@ +package org.dromara.sms4j.test.send; + +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.entity.SmsResponse; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.test.ITest; + +import cn.hutool.core.lang.Assert; + +public class SimpleSendMsgById implements ITest { + + private final String CHANNEL; + private final String PHONE; + + public SimpleSendMsgById(String channel, String phone) { + CHANNEL = channel; + PHONE = phone; + } + //通过 配置id 获取 SmsBlend,发送消息给 CHANNEL 厂商 + public void test(){ + SmsBlend smsBlend = SmsFactory.getSmsBlend(CHANNEL); + //基础发送 + SmsResponse smsResponse = smsBlend.sendMessage(PHONE, "10001"); + + Assert.isTrue(smsResponse.isSuccess()); + } +} diff --git a/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/send/SimpleSendMsgByLoadBalance.java b/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/send/SimpleSendMsgByLoadBalance.java new file mode 100644 index 0000000000000000000000000000000000000000..fea6208d34174c82e2c52ce535eccef1f2c34dde --- /dev/null +++ b/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/send/SimpleSendMsgByLoadBalance.java @@ -0,0 +1,25 @@ +package org.dromara.sms4j.test.send; + +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.entity.SmsResponse; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.test.ITest; + +import cn.hutool.core.lang.Assert; + +public class SimpleSendMsgByLoadBalance implements ITest { + + private final String PHONE; + + public SimpleSendMsgByLoadBalance(String channel, String phone) { + PHONE = phone; + } + //通过 负载均衡器 获取 SmsBlend,发送消息给 CHANNEL 厂商 + public void test(){ + SmsBlend smsBlend = SmsFactory.getSmsBlend(); + //基础发送 + SmsResponse smsResponse = smsBlend.sendMessage(PHONE, "10002"); + + Assert.isTrue(smsResponse.isSuccess()); + } +} diff --git a/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/send/SimpleSendMsgBySupplier.java b/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/send/SimpleSendMsgBySupplier.java new file mode 100644 index 0000000000000000000000000000000000000000..aae7fd17f33b95f855e2c40d995453a1603cae3c --- /dev/null +++ b/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/send/SimpleSendMsgBySupplier.java @@ -0,0 +1,27 @@ +package org.dromara.sms4j.test.send; + +import cn.hutool.core.lang.Assert; + +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.entity.SmsResponse; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.test.ITest; + +public class SimpleSendMsgBySupplier implements ITest { + + private final String CHANNEL; + private final String PHONE; + + public SimpleSendMsgBySupplier(String channel, String phone) { + CHANNEL = channel; + PHONE = phone; + } + //通过 Supplier 获取 SmsBlend,发送消息给 CHANNEL 厂商 + public void test(){ + SmsBlend smsBlend = SmsFactory.getBySupplier(CHANNEL); + //基础发送 + SmsResponse smsResponse = smsBlend.sendMessage(PHONE, "10001"); + + Assert.isTrue(smsResponse.isSuccess()); + } +} diff --git a/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/validate/BlackListValidate.java b/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/validate/BlackListValidate.java new file mode 100644 index 0000000000000000000000000000000000000000..8c6c02181e4cbae8eb1bdda7373480d120c36ad0 --- /dev/null +++ b/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/validate/BlackListValidate.java @@ -0,0 +1,81 @@ +package org.dromara.sms4j.test.validate; + +import cn.hutool.core.lang.Assert; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.entity.SmsResponse; +import org.dromara.sms4j.comm.exception.SmsBlendException; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.test.ITest; + +public class BlackListValidate implements ITest { + + private final String CHANNEL; + private final String PHONE; + + public BlackListValidate(String channel, String phone) { + CHANNEL = channel; + PHONE = phone; + } + + //黑名单的添加删除的功能测试,以及黑名单命中记录的处理 + @Override + public void test() { + SmsBlend smsBlend = SmsFactory.getBySupplier(CHANNEL); + //单黑名单添加 + smsBlend.joinInBlacklist(PHONE); + SmsBlendException knowEx = null; + //下面会因为被黑名单触发拦截所以报错 + try { + smsBlend.sendMessage(PHONE, "200003"); + } catch (SmsBlendException e) { + knowEx = e; + } + Assert.notNull(knowEx); + //查看命中记录是否正确记录 + checkBlackListRecord(smsBlend); + //单黑名单移除 + smsBlend.removeFromBlacklist(PHONE); + //正常发送 + SmsResponse smsResponse = smsBlend.sendMessage(PHONE, "200004"); + Assert.isTrue(smsResponse.isSuccess()); + //清理黑名单命中记录 + smsBlend.clearTriggerRecord(); + //清理黑名单命中记录后,黑名单记录中应该没有该记录所以checkBlackListRecord会报错 + RuntimeException runtimeException = null; + try{ + checkBlackListRecord(smsBlend); + }catch (RuntimeException e){ + runtimeException = e; + } + Assert.notNull(runtimeException); + //批量黑名单添加 + smsBlend.batchJoinBlacklist(Collections.singletonList(PHONE)); + knowEx = null; + //下面会因为被黑名单触发拦截所以报错 + try { + smsBlend.sendMessage(PHONE, "200005"); + } catch (SmsBlendException e) { + knowEx = e; + } + Assert.notNull(knowEx); + //查看命中记录是否正确记录 + checkBlackListRecord(smsBlend); + //批量黑名单删除 + smsBlend.batchRemovalFromBlacklist(Collections.singletonList(PHONE)); + //应该正常发送 + smsResponse = smsBlend.sendMessage(PHONE, "200006"); + Assert.isTrue(smsResponse.isSuccess()); + } + + public void checkBlackListRecord(SmsBlend smsBlend){ + List triggerRecord = smsBlend.getTriggerRecord(); + if (triggerRecord.stream().filter(record -> record.contains(PHONE)).collect(Collectors.toList()).size() == 0) { + throw new RuntimeException("blackList model fail"); + } + } +} diff --git a/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/validate/ParamValidate.java b/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/validate/ParamValidate.java new file mode 100644 index 0000000000000000000000000000000000000000..6ad3dfc339c918ea877ec186581a955e445d7eb9 --- /dev/null +++ b/sms4j-example/Component/TestCase/src/main/java/org/dromara/sms4j/test/validate/ParamValidate.java @@ -0,0 +1,45 @@ +package org.dromara.sms4j.test.validate; + +import cn.hutool.core.lang.Assert; + +import java.util.ArrayList; +import java.util.Collections; + +import org.dromara.sms4j.api.entity.SmsResponse; +import org.dromara.sms4j.comm.exception.SmsBlendException; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.test.ITest; + +public class ParamValidate implements ITest { + + private final String CHANNEL; + private final String PHONE; + + public ParamValidate(String channel, String phone) { + CHANNEL = channel; + PHONE = phone; + } + + /* + * 验证参数是否正确,传入空 电话号会被校验住 + * */ + public void test() { + SmsBlendException knowEx = null; + try { + SmsFactory.getBySupplier(CHANNEL).sendMessage("", "200001"); + } catch (SmsBlendException e) { + knowEx = e; + } + Assert.notNull(knowEx); + knowEx = null; + try { + SmsFactory.getBySupplier(CHANNEL).massTexting(new ArrayList(), "200002"); + } catch (SmsBlendException e) { + knowEx = e; + } + Assert.notNull(knowEx); + SmsResponse smsResponse = SmsFactory.getBySupplier(CHANNEL).massTexting(Collections.singletonList(PHONE), "200003"); + Assert.isTrue(smsResponse.isSuccess()); + + } +} diff --git a/sms4j-example/JavaSE/pom.xml b/sms4j-example/JavaSE/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..f1bd55f1ae036bc6caa7aafea00d9ee20f7062ef --- /dev/null +++ b/sms4j-example/JavaSE/pom.xml @@ -0,0 +1,28 @@ + + 4.0.0 + + org.dromara.sms4j + sms4j-example + 1.0-SNAPSHOT + + JavaSE + JavaSE-Demo + + + org.dromara.sms4j + sms4j-javase-plugin + ${sms4j.version} + + + org.dromara.sms4j + TestCase + 1.0-SNAPSHOT + + + org.dromara.sms4j + Customize + 1.0-SNAPSHOT + + + diff --git a/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanAcctRestricted.java b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanAcctRestricted.java new file mode 100644 index 0000000000000000000000000000000000000000..1f1dac51c2fd8bc7cbf21cd11e96c1765b2d2d8e --- /dev/null +++ b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanAcctRestricted.java @@ -0,0 +1,56 @@ +package org.dromara.sms4j.demo; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.universal.SupplierConfig; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.javase.config.SEInitializer; +import org.dromara.sms4j.provider.config.SmsConfig; + +import sms4j.local.a.AConfig; +import sms4j.local.a.AFactory; + +public class ConfigBeanAcctRestricted { + public static void main(String[] args) { + + // 全局基础配置 + SmsConfig smsConfig = new SmsConfig(); + //24小时账号级发送上限限制 + smsConfig.setAccountMax(3); + + // 开启限制,关闭后只有参数检验拦截器生效 + smsConfig.setRestricted(true); + + // 服务商渠道配置 + List blends = new ArrayList(); + // 服务商 + AConfig aConfig = new AConfig(); + aConfig.setConfigId("a1"); + blends.add(aConfig); + + //为了方便成功通过的演示,这里是自定义的服务商渠道,如果使用sms4j预置的渠道无需此配置 + AFactory myFactory = new AFactory(); + + //初始化SMS + SEInitializer + //这里之后的方法顺序可以任意排列,但是必须以initializer开始 + .initializer() + //为了方便成功通过的演示,这里是自定义的服务商渠道,如果使用sms4j预置的渠道无需此配置 + .registerFactory(myFactory) + //这里之前的方法顺序可以任意排列,但是必须以fromConfig结尾 + .fromConfig(smsConfig,blends); + + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + //会报错并且发送失败 + try { + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + }catch (Exception e){ + System.out.println(e); + } + } +} diff --git a/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanBasicSend.java b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanBasicSend.java new file mode 100644 index 0000000000000000000000000000000000000000..8be5fe56df56641f6ad3aeb55fd9d167bfab092e --- /dev/null +++ b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanBasicSend.java @@ -0,0 +1,131 @@ +package org.dromara.sms4j.demo; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.dromara.sms4j.aliyun.config.AlibabaConfig; +import org.dromara.sms4j.api.manage.InterceptorStrategySmsManager; +import org.dromara.sms4j.api.universal.SupplierConfig; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.javase.config.SEInitializer; +import org.dromara.sms4j.provider.config.SmsConfig; + +import sms4j.dao.MySmsDao; +import sms4j.interceptor.MyIntercepterStrategy; +import sms4j.interceptor.MyInterceptor; +import sms4j.interceptor.MySecIntercepterStrategy; +import sms4j.local.a.AConfig; +import sms4j.local.a.AFactory; + +public class ConfigBeanBasicSend { + public static void main(String[] args) { + + // 全局基础配置 + SmsConfig smsConfig = new SmsConfig(); + + // 关闭限制,关闭后只有参数检验拦截器生效 + smsConfig.setRestricted(false); + + // 服务商渠道配置 + List blends = new ArrayList(); + // 服务商 + AConfig aConfig = new AConfig(); + aConfig.setConfigId("a1"); + blends.add(aConfig); + + //为了方便成功通过的演示,这里是自定义的服务商渠道,如果使用sms4j预置的渠道无需此配置 + AFactory myFactory = new AFactory(); + + //初始化SMS + SEInitializer + //这里之后的方法顺序可以任意排列,但是必须以initializer开始 + .initializer() + //为了方便成功通过的演示,这里是自定义的服务商渠道注册,如果使用sms4j预置的渠道无需此配置 + .registerFactory(myFactory) + //这里之前的方法顺序可以任意排列,但是必须以fromConfig结尾 + .fromConfig(smsConfig,blends); + //发送固定消息模板短信 + //这里的Supplier 是 aConfig.getSupplier(),即从a渠道中若有多个配置则获取任一配置 + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + + //发送固定模板多模板参数短信 + //这个map存放需要用到的模板参数 + LinkedHashMap map4Normal = new LinkedHashMap<>(); + map4Normal.put("param1","value1"); + map4Normal.put("param2","value2"); + //这里的Supplier 是 aConfig.getSupplier(),即从a渠道中若有多个配置则获取任一配置 + SmsFactory.getBySupplier("a").sendMessage("22222222222", map4Normal); + + //使用指定模板发送短信 + LinkedHashMap map4Point = new LinkedHashMap<>(); + map4Point.put("param1","value1"); + map4Point.put("param2","value2"); + map4Point.put("param3","value3"); + //这里的Supplier 是 aConfig.getSupplier(),即从a渠道中若有多个配置则获取任一配置 + SmsFactory.getBySupplier("a").sendMessage("33333333333","templetaId", map4Point); + + //群发短信,固定模板短信 + //此方法使用配置文件中预设的短信模板进行短信发送,该方法指定的模板变量只能存在一个(配置文件中) + //这个数组是批量发送消息的手机号,会一次发送多个,注意,发送多个账号也只会触发一次拦截器,比如黑名单拦截器,会在一次把所有手机号全部校验,而不是校验多次 + List phones = new ArrayList<>(); + phones.add("44444444444"); + phones.add("55555555555"); + //这里的Supplier 是 aConfig.getSupplier(),即从a渠道中若有多个配置则获取任一配置 + SmsFactory.getBySupplier("a").massTexting(phones, "200001"); + + //异步发送固定模板短信 + //这里的Supplier 是 aConfig.getSupplier(),即从a渠道中若有多个配置则获取任一配置 + //不关注执行结果 + SmsFactory.getBySupplier("a").sendMessageAsync("66666666666", "200001"); + //关注执行结果 + SmsFactory.getBySupplier("a").sendMessageAsync("77777777777", "200001", e-> System.out.println(e)); + + //异步发送自定义模板短信 + LinkedHashMap map4Async = new LinkedHashMap<>(); + map4Async.put("param1","value1"); + map4Async.put("param2","value2"); + map4Async.put("param3","value3"); + map4Async.put("param4","value4"); + //这里的Supplier 是 aConfig.getSupplier(),即从a渠道中若有多个配置则获取任一配置 + //不关注执行结果 + SmsFactory.getBySupplier("a").sendMessageAsync("88888888888","templetaId", map4Async); + //关注执行结果 + SmsFactory.getBySupplier("a").sendMessageAsync("99999999999","templetaId", map4Async,e-> System.out.println(e)); + + + //使用自定义模板发送延时短信 + //使用指定模板发送短信 + LinkedHashMap map4Delayed = new LinkedHashMap<>(); + map4Delayed.put("param1","value1"); + map4Delayed.put("param2","value2"); + map4Delayed.put("param3","value3"); + map4Delayed.put("param4","value4"); + map4Delayed.put("param5","value5"); + //这里的Supplier 是 aConfig.getSupplier(),即从a渠道中若有多个配置则获取任一配置 + SmsFactory.getBySupplier("a").delayedMessage("01111111111","templetaId", map4Delayed,1000L); + + //群发固定模板延迟短信 + List phones4Delay = new ArrayList<>(); + phones4Delay.add("02222222222"); + phones4Delay.add("03333333333"); + //这里的Supplier 是 aConfig.getSupplier(),即从a渠道中若有多个配置则获取任一配置 + SmsFactory.getBySupplier("a").delayMassTexting(phones4Delay, "200001",1000L); + + //群发自定义模板延迟短信 + List phones4Delayed = new ArrayList<>(); + phones4Delayed.add("04444444444"); + phones4Delayed.add("05555555555"); + LinkedHashMap map4Delay = new LinkedHashMap<>(); + map4Delay.put("param1","value1"); + map4Delay.put("param2","value2"); + map4Delay.put("param3","value3"); + map4Delay.put("param4","value4"); + map4Delay.put("param5","value5"); + map4Delay.put("param6","value6"); + //这里的Supplier 是 aConfig.getSupplier(),即从a渠道中若有多个配置则获取任一配置 + SmsFactory.getBySupplier("a").delayMassTexting(phones4Delayed,"templetaId", map4Delay,1000L); + } +} diff --git a/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanBlackList.java b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanBlackList.java new file mode 100644 index 0000000000000000000000000000000000000000..0e598bb4ab9af20eb1910dcebcb8a2ee35522096 --- /dev/null +++ b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanBlackList.java @@ -0,0 +1,89 @@ +package org.dromara.sms4j.demo; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.universal.SupplierConfig; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.javase.config.SEInitializer; +import org.dromara.sms4j.provider.config.SmsConfig; + +import sms4j.dao.MySmsDao; +import sms4j.local.a.AConfig; +import sms4j.local.a.AFactory; + +public class ConfigBeanBlackList { + public static void main(String[] args) { + + // 全局基础配置 + SmsConfig smsConfig = new SmsConfig(); + + // 开启限制,关闭后只有参数检验拦截器生效 + smsConfig.setRestricted(true); + + // 服务商渠道配置 + List blends = new ArrayList(); + // 服务商 + AConfig aConfig = new AConfig(); + aConfig.setConfigId("a1"); + blends.add(aConfig); + + //为了方便成功通过的演示,这里是自定义的服务商渠道,如果使用sms4j预置的渠道无需此配置 + AFactory myFactory = new AFactory(); + + //初始化SMS + SEInitializer + //这里之后的方法顺序可以任意排列,但是必须以initializer开始 + .initializer() + //为了方便成功通过的演示,这里是自定义的服务商渠道,如果使用sms4j预置的渠道无需此配置 + .registerFactory(myFactory) + //这里之前的方法顺序可以任意排列,但是必须以fromConfig结尾 + .fromConfig(smsConfig,blends); + + //获取任一smsBlend + SmsBlend smsBlend = SmsFactory.getBySupplier("a"); + + //加入黑名单 + smsBlend.joinInBlacklist("11111111111"); + + //会报错并且发送失败 + try { + smsBlend.sendMessage("11111111111", "200001"); + }catch (Exception e){ + System.out.println(e); + } + + //移除黑名单 + smsBlend.removeFromBlacklist("11111111111"); + + //发送成功 + smsBlend.sendMessage("11111111111", "200001"); + + //批量加入黑名单 + smsBlend.batchJoinBlacklist(Collections.singletonList("11111111111")); + + //会报错并且发送失败 + try { + smsBlend.sendMessage("11111111111", "200001"); + }catch (Exception e){ + System.out.println(e); + } + + //批量移除黑名单 + smsBlend.batchRemovalFromBlacklist(Collections.singletonList("11111111111")); + + //发送成功 + smsBlend.sendMessage("11111111111", "200001"); + + //命中记录获取 + System.out.println(smsBlend.getTriggerRecord()); + + //命中记录清理 + smsBlend.clearTriggerRecord(); + + //命中记录获取 + System.out.println(smsBlend.getTriggerRecord()); + } +} diff --git a/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanChannelRestricted.java b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanChannelRestricted.java new file mode 100644 index 0000000000000000000000000000000000000000..01e009772bcc96d6e8186037bbd03611098bd698 --- /dev/null +++ b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanChannelRestricted.java @@ -0,0 +1,54 @@ +package org.dromara.sms4j.demo; + +import java.util.ArrayList; +import java.util.List; + +import org.dromara.sms4j.api.universal.SupplierConfig; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.javase.config.SEInitializer; +import org.dromara.sms4j.provider.config.SmsConfig; + +import sms4j.local.a.AConfig; +import sms4j.local.a.AFactory; + +public class ConfigBeanChannelRestricted { + public static void main(String[] args) { + + // 全局基础配置 + SmsConfig smsConfig = new SmsConfig(); + + // 开启限制,关闭后只有参数检验拦截器生效 + smsConfig.setRestricted(true); + + // 服务商渠道配置 + List blends = new ArrayList(); + // 服务商 + AConfig aConfig = new AConfig(); + aConfig.setConfigId("a1"); + //渠道级上线,永久计算 + aConfig.setMaximum(3); + blends.add(aConfig); + + //为了方便成功通过的演示,这里是自定义的服务商渠道,如果使用sms4j预置的渠道无需此配置 + AFactory myFactory = new AFactory(); + + //初始化SMS + SEInitializer + //这里之后的方法顺序可以任意排列,但是必须以initializer开始 + .initializer() + //为了方便成功通过的演示,这里是自定义的服务商渠道,如果使用sms4j预置的渠道无需此配置 + .registerFactory(myFactory) + //这里之前的方法顺序可以任意排列,但是必须以fromConfig结尾 + .fromConfig(smsConfig,blends); + + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + //会报错并且发送失败 + try { + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + }catch (Exception e){ + System.out.println(e); + } + } +} diff --git a/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanCustomizeChannel.java b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanCustomizeChannel.java new file mode 100644 index 0000000000000000000000000000000000000000..5dbef66809374755caa0e5f8f477e2c260c5300e --- /dev/null +++ b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanCustomizeChannel.java @@ -0,0 +1,51 @@ +package org.dromara.sms4j.demo; + +import java.util.ArrayList; +import java.util.List; + +import org.dromara.sms4j.api.manage.InterceptorStrategySmsManager; +import org.dromara.sms4j.api.universal.SupplierConfig; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.javase.config.SEInitializer; +import org.dromara.sms4j.provider.config.SmsConfig; + +import sms4j.dao.MySmsDao; +import sms4j.interceptor.MyIntercepterStrategy; +import sms4j.interceptor.MyInterceptor; +import sms4j.interceptor.MySecIntercepterStrategy; +import sms4j.local.a.AConfig; +import sms4j.local.a.AFactory; + +public class ConfigBeanCustomizeChannel { + public static void main(String[] args) { + + // 全局基础配置 + SmsConfig smsConfig = new SmsConfig(); + + //关闭限制,关闭后只有参数检验拦截器生效 + smsConfig.setRestricted(false); + + // 服务商渠道配置 + List blends = new ArrayList(); + // 自定义服务商 + AConfig aConfig = new AConfig(); + aConfig.setMaximum(5); + aConfig.setConfigId("a1"); + blends.add(aConfig); + + //自定义渠道工厂 + AFactory myFactory = new AFactory(); + + //初始化SMS + SEInitializer + //这里之后的方法顺序可以任意排列,但是必须以initializer开始 + .initializer() + //注册自定义渠道工厂 + .registerFactory(myFactory) + //这里之前的方法顺序可以任意排列,但是必须以fromConfig结尾 + .fromConfig(smsConfig,blends); + + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + + } +} diff --git a/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanCustomizeInterceptor.java b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanCustomizeInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..3d7b85a0f4dc973f8dc64f649c2f93dcff2f2d16 --- /dev/null +++ b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanCustomizeInterceptor.java @@ -0,0 +1,65 @@ +package org.dromara.sms4j.demo; + +import java.util.ArrayList; +import java.util.List; + +import org.dromara.sms4j.api.manage.InterceptorStrategySmsManager; +import org.dromara.sms4j.api.universal.SupplierConfig; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.javase.config.SEInitializer; +import org.dromara.sms4j.provider.config.SmsConfig; + +import sms4j.dao.MySmsDao; +import sms4j.interceptor.MyIntercepterStrategy; +import sms4j.interceptor.MyInterceptor; +import sms4j.interceptor.MySecIntercepterStrategy; +import sms4j.local.a.AConfig; +import sms4j.local.a.AFactory; + +public class ConfigBeanCustomizeInterceptor { + public static void main(String[] args) { + + // 全局基础配置 + SmsConfig smsConfig = new SmsConfig(); + + //关闭限制,关闭后只有参数检验拦截器生效 + smsConfig.setRestricted(false); + + // 服务商渠道配置 + List blends = new ArrayList(); + // 服务商 + AConfig aConfig = new AConfig(); + aConfig.setConfigId("a1"); + blends.add(aConfig); + + //为了方便成功通过的演示,这里是自定义的服务商渠道,如果使用sms4j预置的渠道无需此配置 + AFactory myFactory = new AFactory(); + + //自定义的拦截器,自定义拦截器与拦截器策略绑定,所以必须要有对应的拦截器策略,具体关系类似切点和增强 + MyInterceptor myInterceptor = new MyInterceptor(); + + //自定义拦截器策略 + MyIntercepterStrategy myIntercepterStrategy = new MyIntercepterStrategy(); + + //初始化SMS + SEInitializer + //这里之后的方法顺序可以任意排列,但是必须以initializer开始 + .initializer() + //为了方便成功通过的演示,这里是自定义的服务商渠道,如果使用sms4j预置的渠道无需此配置 + .registerFactory(myFactory) + //注册自定义拦截器 + .registerSmsMethodInterceptor(myInterceptor) + //注册自定义拦截器策略 + .registerIInterceptorStrategy(myIntercepterStrategy) + //这里之前的方法顺序可以任意排列,但是必须以fromConfig结尾 + .fromConfig(smsConfig,blends); + + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + + //热修改拦截器策略 + MySecIntercepterStrategy mySecIntercepterStrategy = new MySecIntercepterStrategy(); + InterceptorStrategySmsManager.setInterceptorStrategyMapping(mySecIntercepterStrategy); + + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + } +} diff --git a/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanCustomizeSmsDao.java b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanCustomizeSmsDao.java new file mode 100644 index 0000000000000000000000000000000000000000..77dfa3248866508407a9f42774e43ae221398937 --- /dev/null +++ b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanCustomizeSmsDao.java @@ -0,0 +1,50 @@ +package org.dromara.sms4j.demo; + +import java.util.ArrayList; +import java.util.List; + +import org.dromara.sms4j.api.universal.SupplierConfig; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.javase.config.SEInitializer; +import org.dromara.sms4j.provider.config.SmsConfig; + +import sms4j.dao.MySmsDao; +import sms4j.local.a.AConfig; +import sms4j.local.a.AFactory; + +public class ConfigBeanCustomizeSmsDao { + public static void main(String[] args) { + + // 全局基础配置 + SmsConfig smsConfig = new SmsConfig(); + + //关闭限制,关闭后只有参数检验拦截器生效 + smsConfig.setRestricted(false); + + // 服务商渠道配置 + List blends = new ArrayList(); + // 服务商 + AConfig aConfig = new AConfig(); + aConfig.setConfigId("a1"); + blends.add(aConfig); + + //为了方便成功通过的演示,这里是自定义的服务商渠道,如果使用sms4j预置的渠道无需此配置 + AFactory myFactory = new AFactory(); + + //自定义Dao + MySmsDao mySmsDao = MySmsDao.getInstance();; + + //初始化SMS + SEInitializer + //这里之后的方法顺序可以任意排列,但是必须以initializer开始 + .initializer() + //为了方便成功通过的演示,这里是自定义的服务商渠道,如果使用sms4j预置的渠道无需此配置 + .registerFactory(myFactory) + //注册自定义 smsDao + .registerSmsDao(mySmsDao) + //这里之前的方法顺序可以任意排列,但是必须以fromConfig结尾 + .fromConfig(smsConfig,blends); + + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + } +} diff --git a/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanSms4jFullFunctions.java b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanSms4jFullFunctions.java new file mode 100644 index 0000000000000000000000000000000000000000..a7dce935ab48f62febeedbd504fb64566e637326 --- /dev/null +++ b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanSms4jFullFunctions.java @@ -0,0 +1,76 @@ +package org.dromara.sms4j.demo; + +import org.dromara.sms4j.api.manage.InterceptorStrategySmsManager; +import org.dromara.sms4j.api.universal.SupplierConfig; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.javase.config.SEInitializer; +import org.dromara.sms4j.provider.config.SmsConfig; + +import sms4j.dao.MySmsDao; +import sms4j.interceptor.MyIntercepterStrategy; +import sms4j.interceptor.MyInterceptor; +import sms4j.interceptor.MySecIntercepterStrategy; +import sms4j.local.a.AConfig; +import sms4j.local.a.AFactory; + +import java.util.ArrayList; +import java.util.List; + +/* +* 文档地址 : https://sms4j.com/doc3/javase.htmlhttps://sms4j.com/doc3/javase.html +* */ +public class ConfigBeanSms4jFullFunctions { + public static void main(String[] args) { + + + // 全局基础配置 + SmsConfig smsConfig = new SmsConfig(); + // 账户级上限 + smsConfig.setAccountMax(4); + smsConfig.setRestricted(true); + + // 服务商渠道配置 + List blends = new ArrayList(); + // 服务商 + AConfig aConfig = new AConfig(); + aConfig.setMaximum(5); + aConfig.setConfigId("a1"); + blends.add(aConfig); + + //自定义渠道工厂 + AFactory myFactory = new AFactory(); + + //自定义拦截器 + MyInterceptor myInterceptor = new MyInterceptor(); + + //自定义拦截器策略 + MyIntercepterStrategy myIntercepterStrategy = new MyIntercepterStrategy(); + + //自定义Dao + MySmsDao mySmsDao = MySmsDao.getInstance();; + + //初始化SMS + SEInitializer + //这里之后的方法顺序可以任意排列,但是必须以initializer开始 + .initializer() + //注册自定义拦截器策略 + .registerIInterceptorStrategy(myIntercepterStrategy) + //注册自定义拦截器 + .registerSmsMethodInterceptor(myInterceptor) + //注册自定义渠道工厂 + .registerFactory(myFactory) + //注册自定义 smsDao + .registerSmsDao(mySmsDao) + //这里之前的方法顺序可以任意排列,但是必须以fromConfig结尾 + .fromConfig(smsConfig,blends); + + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + + //自定义拦截器执行策略 + MySecIntercepterStrategy mySecIntercepterStrategy = new MySecIntercepterStrategy(); + //热替换拦截器执行策略 + InterceptorStrategySmsManager.setInterceptorStrategyMapping(mySecIntercepterStrategy); + + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + } +} diff --git a/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanSpanRestricted.java b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanSpanRestricted.java new file mode 100644 index 0000000000000000000000000000000000000000..96b44e87f3970eb2fa9585b85377354dd2dc4c82 --- /dev/null +++ b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/ConfigBeanSpanRestricted.java @@ -0,0 +1,54 @@ +package org.dromara.sms4j.demo; + +import java.util.ArrayList; +import java.util.List; + +import org.dromara.sms4j.api.universal.SupplierConfig; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.javase.config.SEInitializer; +import org.dromara.sms4j.provider.config.SmsConfig; + +import sms4j.local.a.AConfig; +import sms4j.local.a.AFactory; + +public class ConfigBeanSpanRestricted { + public static void main(String[] args) { + + // 全局基础配置 + SmsConfig smsConfig = new SmsConfig(); + //1分钟 时段级账户发送上限限制 + smsConfig.setMinuteMax(3); + + // 开启限制,关闭后只有参数检验拦截器生效 + smsConfig.setRestricted(true); + + // 服务商渠道配置 + List blends = new ArrayList(); + // 服务商 + AConfig aConfig = new AConfig(); + aConfig.setConfigId("a1"); + blends.add(aConfig); + + //为了方便成功通过的演示,这里是自定义的服务商渠道,如果使用sms4j预置的渠道无需此配置 + AFactory myFactory = new AFactory(); + + //初始化SMS + SEInitializer + //这里之后的方法顺序可以任意排列,但是必须以initializer开始 + .initializer() + //为了方便成功通过的演示,这里是自定义的服务商渠道,如果使用sms4j预置的渠道无需此配置 + .registerFactory(myFactory) + //这里之前的方法顺序可以任意排列,但是必须以fromConfig结尾 + .fromConfig(smsConfig,blends); + + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + //会报错并且发送失败 + try { + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + }catch (Exception e){ + System.out.println(e); + } + } +} diff --git a/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/YamlBasicSend.java b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/YamlBasicSend.java new file mode 100644 index 0000000000000000000000000000000000000000..466117ba9ea0dac8c530ffe3688c031c361c2ac1 --- /dev/null +++ b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/YamlBasicSend.java @@ -0,0 +1,114 @@ +package org.dromara.sms4j.demo; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; + +import org.dromara.sms4j.api.universal.SupplierConfig; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.javase.config.SEInitializer; +import org.dromara.sms4j.provider.config.SmsConfig; + +import sms4j.local.a.AConfig; +import sms4j.local.a.AFactory; + +/* +* 文档地址 : https://sms4j.com/doc3/javase.htmlhttps://sms4j.com/doc3/javase.html +* */ +public class YamlBasicSend { + public static void main(String[] args) { + + //为了方便成功通过的演示,这里是自定义的服务商渠道,如果使用sms4j预置的渠道无需此配置 + AFactory myFactory = new AFactory(); + + //初始化SMS + SEInitializer + //这里之后的方法顺序可以任意排列,但是必须以initializer开始 + .initializer() + //为了方便成功通过的演示,这里是自定义的服务商渠道注册,如果使用sms4j预置的渠道无需此配置 + .registerFactory(myFactory) + //这里之前的方法顺序可以任意排列,但是必须以fromConfig结尾 + .fromYaml(); + //发送固定消息模板短信 + //这里的Supplier 是 aConfig.getSupplier(),即从a渠道中若有多个配置则获取任一配置 + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + + //发送固定模板多模板参数短信 + //这个map存放需要用到的模板参数 + LinkedHashMap map4Normal = new LinkedHashMap<>(); + map4Normal.put("param1","value1"); + map4Normal.put("param2","value2"); + //这里的Supplier 是 aConfig.getSupplier(),即从a渠道中若有多个配置则获取任一配置 + SmsFactory.getBySupplier("a").sendMessage("22222222222", map4Normal); + + //使用指定模板发送短信 + LinkedHashMap map4Point = new LinkedHashMap<>(); + map4Point.put("param1","value1"); + map4Point.put("param2","value2"); + map4Point.put("param3","value3"); + //这里的Supplier 是 aConfig.getSupplier(),即从a渠道中若有多个配置则获取任一配置 + SmsFactory.getBySupplier("a").sendMessage("33333333333","templetaId", map4Point); + + //群发短信,固定模板短信 + //此方法使用配置文件中预设的短信模板进行短信发送,该方法指定的模板变量只能存在一个(配置文件中) + //这个数组是批量发送消息的手机号,会一次发送多个,注意,发送多个账号也只会触发一次拦截器,比如黑名单拦截器,会在一次把所有手机号全部校验,而不是校验多次 + List phones = new ArrayList<>(); + phones.add("44444444444"); + phones.add("55555555555"); + //这里的Supplier 是 aConfig.getSupplier(),即从a渠道中若有多个配置则获取任一配置 + SmsFactory.getBySupplier("a").massTexting(phones, "200001"); + + //异步发送固定模板短信 + //这里的Supplier 是 aConfig.getSupplier(),即从a渠道中若有多个配置则获取任一配置 + //不关注执行结果 + SmsFactory.getBySupplier("a").sendMessageAsync("66666666666", "200001"); + //关注执行结果 + SmsFactory.getBySupplier("a").sendMessageAsync("77777777777", "200001", e-> System.out.println(e)); + + //异步发送自定义模板短信 + LinkedHashMap map4Async = new LinkedHashMap<>(); + map4Async.put("param1","value1"); + map4Async.put("param2","value2"); + map4Async.put("param3","value3"); + map4Async.put("param4","value4"); + //这里的Supplier 是 aConfig.getSupplier(),即从a渠道中若有多个配置则获取任一配置 + //不关注执行结果 + SmsFactory.getBySupplier("a").sendMessageAsync("88888888888","templetaId", map4Async); + //关注执行结果 + SmsFactory.getBySupplier("a").sendMessageAsync("99999999999","templetaId", map4Async,e-> System.out.println(e)); + + + //使用自定义模板发送延时短信 + //使用指定模板发送短信 + LinkedHashMap map4Delayed = new LinkedHashMap<>(); + map4Delayed.put("param1","value1"); + map4Delayed.put("param2","value2"); + map4Delayed.put("param3","value3"); + map4Delayed.put("param4","value4"); + map4Delayed.put("param5","value5"); + //这里的Supplier 是 aConfig.getSupplier(),即从a渠道中若有多个配置则获取任一配置 + SmsFactory.getBySupplier("a").delayedMessage("01111111111","templetaId", map4Delayed,1000L); + + //群发固定模板延迟短信 + List phones4Delay = new ArrayList<>(); + phones4Delay.add("02222222222"); + phones4Delay.add("03333333333"); + //这里的Supplier 是 aConfig.getSupplier(),即从a渠道中若有多个配置则获取任一配置 + SmsFactory.getBySupplier("a").delayMassTexting(phones4Delay, "200001",1000L); + + //群发自定义模板延迟短信 + List phones4Delayed = new ArrayList<>(); + phones4Delayed.add("04444444444"); + phones4Delayed.add("05555555555"); + LinkedHashMap map4Delay = new LinkedHashMap<>(); + map4Delay.put("param1","value1"); + map4Delay.put("param2","value2"); + map4Delay.put("param3","value3"); + map4Delay.put("param4","value4"); + map4Delay.put("param5","value5"); + map4Delay.put("param6","value6"); + //这里的Supplier 是 aConfig.getSupplier(),即从a渠道中若有多个配置则获取任一配置 + SmsFactory.getBySupplier("a").delayMassTexting(phones4Delayed,"templetaId", map4Delay,1000L); + + } +} diff --git a/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/YamlCustomizeChannel.java b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/YamlCustomizeChannel.java new file mode 100644 index 0000000000000000000000000000000000000000..a0ecd3ca46dea5ed75db9efb6f25d3a2105b05a1 --- /dev/null +++ b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/YamlCustomizeChannel.java @@ -0,0 +1,34 @@ +package org.dromara.sms4j.demo; + +import java.util.ArrayList; +import java.util.List; + +import org.dromara.sms4j.api.universal.SupplierConfig; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.javase.config.SEInitializer; +import org.dromara.sms4j.provider.config.SmsConfig; + +import sms4j.local.a.AConfig; +import sms4j.local.a.AFactory; + +public class YamlCustomizeChannel { + public static void main(String[] args) { + + + + //自定义渠道工厂 + AFactory myFactory = new AFactory(); + + //初始化SMS + SEInitializer + //这里之后的方法顺序可以任意排列,但是必须以initializer开始 + .initializer() + //注册自定义渠道工厂 + .registerFactory(myFactory) + //这里之前的方法顺序可以任意排列,但是必须以fromConfig结尾 + .fromYaml(); + + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + + } +} diff --git a/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/YamlCustomizeInterceptor.java b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/YamlCustomizeInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..702f289e8336686a8ddbce8f07614aa6645a04c4 --- /dev/null +++ b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/YamlCustomizeInterceptor.java @@ -0,0 +1,51 @@ +package org.dromara.sms4j.demo; + +import java.util.ArrayList; +import java.util.List; + +import org.dromara.sms4j.api.manage.InterceptorStrategySmsManager; +import org.dromara.sms4j.api.universal.SupplierConfig; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.javase.config.SEInitializer; +import org.dromara.sms4j.provider.config.SmsConfig; + +import sms4j.interceptor.MyIntercepterStrategy; +import sms4j.interceptor.MyInterceptor; +import sms4j.interceptor.MySecIntercepterStrategy; +import sms4j.local.a.AConfig; +import sms4j.local.a.AFactory; + +public class YamlCustomizeInterceptor { + public static void main(String[] args) { + + //为了方便成功通过的演示,这里是自定义的服务商渠道,如果使用sms4j预置的渠道无需此配置 + AFactory myFactory = new AFactory(); + + //自定义的拦截器,自定义拦截器与拦截器策略绑定,所以必须要有对应的拦截器策略,具体关系类似切点和增强 + MyInterceptor myInterceptor = new MyInterceptor(); + + //自定义拦截器策略 + MyIntercepterStrategy myIntercepterStrategy = new MyIntercepterStrategy(); + + //初始化SMS + SEInitializer + //这里之后的方法顺序可以任意排列,但是必须以initializer开始 + .initializer() + //为了方便成功通过的演示,这里是自定义的服务商渠道,如果使用sms4j预置的渠道无需此配置 + .registerFactory(myFactory) + //注册自定义拦截器 + .registerSmsMethodInterceptor(myInterceptor) + //注册自定义拦截器策略 + .registerIInterceptorStrategy(myIntercepterStrategy) + //这里之前的方法顺序可以任意排列,但是必须以fromConfig结尾 + .fromYaml(); + + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + + //热修改拦截器策略 + MySecIntercepterStrategy mySecIntercepterStrategy = new MySecIntercepterStrategy(); + InterceptorStrategySmsManager.setInterceptorStrategyMapping(mySecIntercepterStrategy); + + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + } +} diff --git a/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/YamlCustomizeSmsDao.java b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/YamlCustomizeSmsDao.java new file mode 100644 index 0000000000000000000000000000000000000000..3bcee993d516b4a529e1fb8ed500697f30f1f1b7 --- /dev/null +++ b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/YamlCustomizeSmsDao.java @@ -0,0 +1,37 @@ +package org.dromara.sms4j.demo; + +import java.util.ArrayList; +import java.util.List; + +import org.dromara.sms4j.api.universal.SupplierConfig; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.javase.config.SEInitializer; +import org.dromara.sms4j.provider.config.SmsConfig; + +import sms4j.dao.MySmsDao; +import sms4j.local.a.AConfig; +import sms4j.local.a.AFactory; + +public class YamlCustomizeSmsDao { + public static void main(String[] args) { + + //为了方便成功通过的演示,这里是自定义的服务商渠道,如果使用sms4j预置的渠道无需此配置 + AFactory myFactory = new AFactory(); + + //自定义Dao + MySmsDao mySmsDao = MySmsDao.getInstance();; + + //初始化SMS + SEInitializer + //这里之后的方法顺序可以任意排列,但是必须以initializer开始 + .initializer() + //为了方便成功通过的演示,这里是自定义的服务商渠道,如果使用sms4j预置的渠道无需此配置 + .registerFactory(myFactory) + //注册自定义 smsDao + .registerSmsDao(mySmsDao) + //这里之前的方法顺序可以任意排列,但是必须以fromConfig结尾 + .fromYaml(); + + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + } +} diff --git a/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/YamlFullFunctions.java b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/YamlFullFunctions.java new file mode 100644 index 0000000000000000000000000000000000000000..d4aa10ed7544c8fe7b5db09e3b360c7db1751725 --- /dev/null +++ b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/demo/YamlFullFunctions.java @@ -0,0 +1,55 @@ +package org.dromara.sms4j.demo; + +import sms4j.dao.MySmsDao; +import sms4j.interceptor.MyIntercepterStrategy; +import sms4j.interceptor.MyInterceptor; +import sms4j.interceptor.MySecIntercepterStrategy; +import sms4j.local.a.AFactory; + +import org.dromara.sms4j.api.manage.InterceptorStrategySmsManager; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.javase.config.SEInitializer; + +/* +* 文档地址 : https://sms4j.com/doc3/javase.htmlhttps://sms4j.com/doc3/javase.html +* */ +public class YamlFullFunctions { + public static void main(String[] args) { + + //自定义渠道工厂 + AFactory myFactory = new AFactory(); + + //自定义拦截器 + MyInterceptor myInterceptor = new MyInterceptor(); + + //自定义拦截器策略 + MyIntercepterStrategy myIntercepterStrategy = new MyIntercepterStrategy(); + + //自定义Dao + MySmsDao mySmsDao = MySmsDao.getInstance(); + + //初始化SMS + SEInitializer + //这里之后的方法顺序可以任意排列,但是必须以initializer开始 + .initializer() + //注册自定义拦截器策略,可以有多个本方法调用 + .registerIInterceptorStrategy(myIntercepterStrategy) + //注册自定义拦截器,可以有多个本方法调用 + .registerSmsMethodInterceptor(myInterceptor) + //注册自定义渠道工厂,可以有多个本方法调用 + .registerFactory(myFactory) + //注册自定义 smsDao,只能有一个,以最后一次调用为准 + .registerSmsDao(mySmsDao) + //这里之前的方法顺序可以任意排列,但是必须以fromYaml结尾 + .fromYaml(); + + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + + //自定义拦截器执行策略 + MySecIntercepterStrategy mySecIntercepterStrategy = new MySecIntercepterStrategy(); + //热替换拦截器执行策略 + InterceptorStrategySmsManager.setInterceptorStrategyMapping(mySecIntercepterStrategy); + + SmsFactory.getBySupplier("a").sendMessage("11111111111", "200001"); + } +} diff --git a/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEConfigBeanBlackListValidateTest.java b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEConfigBeanBlackListValidateTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e782003dae5258cb46d4f6bc7eae5df2ed3034f2 --- /dev/null +++ b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEConfigBeanBlackListValidateTest.java @@ -0,0 +1,67 @@ +package org.dromara.sms4j.test; + +import org.dromara.sms4j.api.universal.SupplierConfig; +import org.dromara.sms4j.javase.config.SEInitializer; +import org.dromara.sms4j.provider.config.SmsConfig; +import org.dromara.sms4j.test.validate.BlackListValidate; + +import sms4j.dao.MySmsDao; +import sms4j.interceptor.MyIntercepterStrategy; +import sms4j.interceptor.MyInterceptor; +import sms4j.local.a.AConfig; +import sms4j.local.a.AFactory; + +import java.util.ArrayList; +import java.util.List; + +/* +* 测试情况 +* */ +public class SEConfigBeanBlackListValidateTest { + + public static void main(String[] args) { + // 全局基础配置 + SmsConfig smsConfig = new SmsConfig(); + // 账户级上限 + smsConfig.setAccountMax(4); + smsConfig.setRestricted(true); + + // 服务商渠道配置 + List blends = new ArrayList(); + // 服务商 + AConfig aConfig = new AConfig(); + aConfig.setMaximum(5); + aConfig.setConfigId("a1"); + blends.add(aConfig); + + //自定义渠道工厂 + AFactory myFactory = new AFactory(); + + //自定义拦截器 + MyInterceptor myInterceptor = new MyInterceptor(); + + //自定义拦截器策略 + MyIntercepterStrategy myIntercepterStrategy = new MyIntercepterStrategy(); + + //自定义Dao + MySmsDao mySmsDao = MySmsDao.getInstance();; + + //初始化SMS + SEInitializer + //这里之后的方法顺序可以任意排列,但是必须以initializer开始 + .initializer() + //注册自定义拦截器策略 + .registerIInterceptorStrategy(myIntercepterStrategy) + //注册自定义拦截器 + .registerSmsMethodInterceptor(myInterceptor) + //注册自定义渠道工厂 + .registerFactory(myFactory) + //注册自定义 smsDao + .registerSmsDao(mySmsDao) + //这里之前的方法顺序可以任意排列,但是必须以fromConfig结尾 + .fromConfig(smsConfig,blends); + + BlackListValidate blackListValidate = new BlackListValidate("a","11111111111"); + blackListValidate.test(); + } +} diff --git a/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEConfigBeanMultiChannelAllValidateTest.java b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEConfigBeanMultiChannelAllValidateTest.java new file mode 100644 index 0000000000000000000000000000000000000000..3553889282b21f7a073cba09cd9e1a3df5a9dc38 --- /dev/null +++ b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEConfigBeanMultiChannelAllValidateTest.java @@ -0,0 +1,69 @@ +package org.dromara.sms4j.test; + +import org.dromara.sms4j.api.universal.SupplierConfig; +import org.dromara.sms4j.javase.config.SEInitializer; +import org.dromara.sms4j.provider.config.SmsConfig; +import org.dromara.sms4j.test.complexity.MultiChannelAllValidate; + +import sms4j.dao.MySmsDao; +import sms4j.interceptor.MyIntercepterStrategy; +import sms4j.interceptor.MyInterceptor; +import sms4j.local.a.AConfig; +import sms4j.local.a.AFactory; +import sms4j.local.b.BFactory; +import sms4j.local.c.CFactory; + +import java.util.ArrayList; +import java.util.List; + +/* +* 测试情况 +* */ +public class SEConfigBeanMultiChannelAllValidateTest { + + public static void main(String[] args) { + // 全局基础配置 + SmsConfig smsConfig = new SmsConfig(); + // 账户级上限 + smsConfig.setAccountMax(4); + smsConfig.setRestricted(true); + + // 服务商渠道配置 + List blends = new ArrayList(); + // 服务商 + AConfig aConfig = new AConfig(); + aConfig.setMaximum(5); + aConfig.setConfigId("a1"); + blends.add(aConfig); + + //自定义渠道工厂 + AFactory myFactory = new AFactory(); + + //自定义拦截器 + MyInterceptor myInterceptor = new MyInterceptor(); + + //自定义拦截器策略 + MyIntercepterStrategy myIntercepterStrategy = new MyIntercepterStrategy(); + + //自定义Dao + MySmsDao mySmsDao = MySmsDao.getInstance();; + + //初始化SMS + SEInitializer + //这里之后的方法顺序可以任意排列,但是必须以initializer开始 + .initializer() + //注册自定义拦截器策略 + .registerIInterceptorStrategy(myIntercepterStrategy) + //注册自定义拦截器 + .registerSmsMethodInterceptor(myInterceptor) + //注册自定义渠道工厂 + .registerFactory(myFactory) + //注册自定义 smsDao + .registerSmsDao(mySmsDao) + //这里之前的方法顺序可以任意排列,但是必须以fromConfig结尾 + .fromConfig(smsConfig,blends); + + MultiChannelAllValidate multiChannelAllValidate = new MultiChannelAllValidate("11111111111", "22222222222", "a", "b", "c"); + multiChannelAllValidate.test(); + } +} diff --git a/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEConfigBeanParamValidateTest.java b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEConfigBeanParamValidateTest.java new file mode 100644 index 0000000000000000000000000000000000000000..62b2f604b46dcd5a67a4701e010cd87cf542188e --- /dev/null +++ b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEConfigBeanParamValidateTest.java @@ -0,0 +1,67 @@ +package org.dromara.sms4j.test; + +import org.dromara.sms4j.api.universal.SupplierConfig; +import org.dromara.sms4j.javase.config.SEInitializer; +import org.dromara.sms4j.provider.config.SmsConfig; +import org.dromara.sms4j.test.validate.ParamValidate; + +import sms4j.dao.MySmsDao; +import sms4j.interceptor.MyIntercepterStrategy; +import sms4j.interceptor.MyInterceptor; +import sms4j.local.a.AConfig; +import sms4j.local.a.AFactory; + +import java.util.ArrayList; +import java.util.List; + +/* +* 测试情况 +* */ +public class SEConfigBeanParamValidateTest { + + public static void main(String[] args) { + // 全局基础配置 + SmsConfig smsConfig = new SmsConfig(); + // 账户级上限 + smsConfig.setAccountMax(4); + smsConfig.setRestricted(true); + + // 服务商渠道配置 + List blends = new ArrayList(); + // 服务商 + AConfig aConfig = new AConfig(); + aConfig.setMaximum(5); + aConfig.setConfigId("a1"); + blends.add(aConfig); + + //自定义渠道工厂 + AFactory myFactory = new AFactory(); + + //自定义拦截器 + MyInterceptor myInterceptor = new MyInterceptor(); + + //自定义拦截器策略 + MyIntercepterStrategy myIntercepterStrategy = new MyIntercepterStrategy(); + + //自定义Dao + MySmsDao mySmsDao = MySmsDao.getInstance();; + + //初始化SMS + SEInitializer + //这里之后的方法顺序可以任意排列,但是必须以initializer开始 + .initializer() + //注册自定义拦截器策略 + .registerIInterceptorStrategy(myIntercepterStrategy) + //注册自定义拦截器 + .registerSmsMethodInterceptor(myInterceptor) + //注册自定义渠道工厂 + .registerFactory(myFactory) + //注册自定义 smsDao + .registerSmsDao(mySmsDao) + //这里之前的方法顺序可以任意排列,但是必须以fromConfig结尾 + .fromConfig(smsConfig,blends); + + ParamValidate paramValidate = new ParamValidate("a","11111111111"); + paramValidate.test(); + } +} diff --git a/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEConfigBeanSendsTest.java b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEConfigBeanSendsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..3421dffa86c26c2ed6dd3c7410245fffaa172eae --- /dev/null +++ b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEConfigBeanSendsTest.java @@ -0,0 +1,72 @@ +package org.dromara.sms4j.test; + +import org.dromara.sms4j.api.universal.SupplierConfig; +import org.dromara.sms4j.javase.config.SEInitializer; +import org.dromara.sms4j.provider.config.SmsConfig; +import org.dromara.sms4j.test.send.SimpleSendMsgById; +import org.dromara.sms4j.test.send.SimpleSendMsgByLoadBalance; +import org.dromara.sms4j.test.send.SimpleSendMsgBySupplier; + +import sms4j.dao.MySmsDao; +import sms4j.interceptor.MyIntercepterStrategy; +import sms4j.interceptor.MyInterceptor; +import sms4j.local.a.AConfig; +import sms4j.local.a.AFactory; + +import java.util.ArrayList; +import java.util.List; + +/* +* 测试情况 +* */ +public class SEConfigBeanSendsTest { + + public static void main(String[] args) { + // 全局基础配置 + SmsConfig smsConfig = new SmsConfig(); + // 账户级上限 + smsConfig.setAccountMax(4); + smsConfig.setRestricted(true); + + // 服务商渠道配置 + List blends = new ArrayList(); + // 服务商 + AConfig aConfig = new AConfig(); + aConfig.setMaximum(5); + aConfig.setConfigId("a1"); + blends.add(aConfig); + + //自定义渠道工厂 + AFactory myFactory = new AFactory(); + + //自定义拦截器 + MyInterceptor myInterceptor = new MyInterceptor(); + + //自定义拦截器策略 + MyIntercepterStrategy myIntercepterStrategy = new MyIntercepterStrategy(); + + //自定义Dao + MySmsDao mySmsDao = MySmsDao.getInstance();; + + //初始化SMS + SEInitializer + //这里之后的方法顺序可以任意排列,但是必须以initializer开始 + .initializer() + //注册自定义拦截器策略 + .registerIInterceptorStrategy(myIntercepterStrategy) + //注册自定义拦截器 + .registerSmsMethodInterceptor(myInterceptor) + //注册自定义渠道工厂 + .registerFactory(myFactory) + //注册自定义 smsDao + .registerSmsDao(mySmsDao) + //这里之前的方法顺序可以任意排列,但是必须以fromConfig结尾 + .fromConfig(smsConfig,blends); + SimpleSendMsgById simpleSendMsgById = new SimpleSendMsgById("a1", "11111111111"); + simpleSendMsgById.test(); + SimpleSendMsgByLoadBalance simpleSendMsgByLoadBalance = new SimpleSendMsgByLoadBalance("a","11111111111"); + simpleSendMsgByLoadBalance.test(); + SimpleSendMsgBySupplier simpleSendMsgBySupplier = new SimpleSendMsgBySupplier("a","11111111111"); + simpleSendMsgBySupplier.test(); + } +} diff --git a/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEConfigBeanSimpleChannelAllValidateTest.java b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEConfigBeanSimpleChannelAllValidateTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6c865cd05625eb71670573a48418457f2aa95d90 --- /dev/null +++ b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEConfigBeanSimpleChannelAllValidateTest.java @@ -0,0 +1,69 @@ +package org.dromara.sms4j.test; + +import org.dromara.sms4j.api.universal.SupplierConfig; +import org.dromara.sms4j.javase.config.SEInitializer; +import org.dromara.sms4j.provider.config.SmsConfig; +import org.dromara.sms4j.test.complexity.SimpleChannelAllValidate; + +import sms4j.dao.MySmsDao; +import sms4j.interceptor.MyIntercepterStrategy; +import sms4j.interceptor.MyInterceptor; +import sms4j.local.a.AConfig; +import sms4j.local.a.AFactory; +import sms4j.local.b.BFactory; +import sms4j.local.c.CFactory; + +import java.util.ArrayList; +import java.util.List; + +/* +* 测试情况 +* */ +public class SEConfigBeanSimpleChannelAllValidateTest { + + public static void main(String[] args) { + // 全局基础配置 + SmsConfig smsConfig = new SmsConfig(); + // 账户级上限 + smsConfig.setAccountMax(4); + smsConfig.setRestricted(true); + + // 服务商渠道配置 + List blends = new ArrayList(); + // 服务商 + AConfig aConfig = new AConfig(); + aConfig.setMaximum(5); + aConfig.setConfigId("a1"); + blends.add(aConfig); + + //自定义渠道工厂 + AFactory myFactory = new AFactory(); + + //自定义拦截器 + MyInterceptor myInterceptor = new MyInterceptor(); + + //自定义拦截器策略 + MyIntercepterStrategy myIntercepterStrategy = new MyIntercepterStrategy(); + + //自定义Dao + MySmsDao mySmsDao = MySmsDao.getInstance();; + + //初始化SMS + SEInitializer + //这里之后的方法顺序可以任意排列,但是必须以initializer开始 + .initializer() + //注册自定义拦截器策略 + .registerIInterceptorStrategy(myIntercepterStrategy) + //注册自定义拦截器 + .registerSmsMethodInterceptor(myInterceptor) + //注册自定义渠道工厂 + .registerFactory(myFactory) + //注册自定义 smsDao + .registerSmsDao(mySmsDao) + //这里之前的方法顺序可以任意排列,但是必须以fromConfig结尾 + .fromConfig(smsConfig,blends); + + SimpleChannelAllValidate simpleChannelAllValidate = new SimpleChannelAllValidate("11111111111", "22222222222", "a"); + simpleChannelAllValidate.test(); + } +} diff --git a/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEYmlBlackListValidateTest.java b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEYmlBlackListValidateTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9aaf94267927cf903e4b072c7f0425427cb78976 --- /dev/null +++ b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEYmlBlackListValidateTest.java @@ -0,0 +1,47 @@ +package org.dromara.sms4j.test; + +import org.dromara.sms4j.javase.config.SEInitializer; +import org.dromara.sms4j.test.validate.BlackListValidate; + +import sms4j.dao.MySmsDao; +import sms4j.interceptor.MyIntercepterStrategy; +import sms4j.interceptor.MyInterceptor; +import sms4j.local.a.AFactory; + +/* +* 测试情况 +* */ +public class SEYmlBlackListValidateTest { + + public static void main(String[] args) { + //自定义渠道工厂 + AFactory myFactory = new AFactory(); + + //自定义拦截器 + MyInterceptor myInterceptor = new MyInterceptor(); + + //自定义拦截器策略 + MyIntercepterStrategy myIntercepterStrategy = new MyIntercepterStrategy(); + + //自定义Dao + MySmsDao mySmsDao = MySmsDao.getInstance(); + + //初始化SMS + SEInitializer + //这里之后的方法顺序可以任意排列,但是必须以initializer开始 + .initializer() + //注册自定义拦截器策略 + .registerIInterceptorStrategy(myIntercepterStrategy) + //注册自定义拦截器 + .registerSmsMethodInterceptor(myInterceptor) + //注册自定义渠道工厂 + .registerFactory(myFactory) + //注册自定义 smsDao + .registerSmsDao(mySmsDao) + //这里之前的方法顺序可以任意排列,但是必须以fromYaml结尾 + .fromYaml(); + + BlackListValidate blackListValidate = new BlackListValidate("a","11111111111"); + blackListValidate.test(); + } +} diff --git a/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEYmlMultiChannelAllValidateTest.java b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEYmlMultiChannelAllValidateTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6639476b477c8bfc2c91770a93dc79cc58e011cc --- /dev/null +++ b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEYmlMultiChannelAllValidateTest.java @@ -0,0 +1,56 @@ +package org.dromara.sms4j.test; + +import org.dromara.sms4j.javase.config.SEInitializer; +import org.dromara.sms4j.test.complexity.MultiChannelAllValidate; +import org.dromara.sms4j.test.send.SimpleSendMsgById; +import org.dromara.sms4j.test.send.SimpleSendMsgByLoadBalance; +import org.dromara.sms4j.test.send.SimpleSendMsgBySupplier; + +import sms4j.dao.MySmsDao; +import sms4j.interceptor.MyIntercepterStrategy; +import sms4j.interceptor.MyInterceptor; +import sms4j.local.a.AFactory; +import sms4j.local.b.BFactory; +import sms4j.local.c.CFactory; + +/* +* 测试情况 +* */ +public class SEYmlMultiChannelAllValidateTest { + + public static void main(String[] args) { + //自定义渠道工厂 + AFactory myFactory = new AFactory(); + BFactory bFactory = new BFactory(); + CFactory cFactory = new CFactory(); + + //自定义拦截器 + MyInterceptor myInterceptor = new MyInterceptor(); + + //自定义拦截器策略 + MyIntercepterStrategy myIntercepterStrategy = new MyIntercepterStrategy(); + + //自定义Dao + MySmsDao mySmsDao = MySmsDao.getInstance(); + + //初始化SMS + SEInitializer + //这里之后的方法顺序可以任意排列,但是必须以initializer开始 + .initializer() + //注册自定义拦截器策略,可以有多个本方法调用 + .registerIInterceptorStrategy(myIntercepterStrategy) + //注册自定义拦截器,可以有多个本方法调用 + .registerSmsMethodInterceptor(myInterceptor) + //注册自定义渠道工厂,可以有多个本方法调用 + .registerFactory(myFactory) + .registerFactory(bFactory) + .registerFactory(cFactory) + //注册自定义 smsDao,只能有一个,以最后一次调用为准 + .registerSmsDao(mySmsDao) + //这里之前的方法顺序可以任意排列,但是必须以fromYaml结尾 + .fromYaml(); + + MultiChannelAllValidate multiChannelAllValidate = new MultiChannelAllValidate("11111111111", "22222222222", "a", "b", "c"); + multiChannelAllValidate.test(); + } +} diff --git a/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEYmlParamValidateTest.java b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEYmlParamValidateTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8ce13ff1aeaf92c5aebea7cc85f5fbdee602d6fd --- /dev/null +++ b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEYmlParamValidateTest.java @@ -0,0 +1,60 @@ +package org.dromara.sms4j.test; + +import java.util.ArrayList; +import java.util.List; + +import org.dromara.sms4j.aliyun.config.AlibabaConfig; +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.universal.SupplierConfig; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.javase.config.SEInitializer; +import org.dromara.sms4j.provider.config.SmsConfig; +import org.dromara.sms4j.test.validate.ParamValidate; + +import sms4j.dao.MySmsDao; +import sms4j.interceptor.MyIntercepterStrategy; +import sms4j.interceptor.MyInterceptor; +import sms4j.local.a.AConfig; +import sms4j.local.a.AFactory; +import sms4j.local.b.BConfig; +import sms4j.local.b.BFactory; +import sms4j.local.c.CConfig; +import sms4j.local.c.CFactory; + +/* +* 测试情况 +* */ +public class SEYmlParamValidateTest { + + public static void main(String[] args) { + //自定义渠道工厂 + AFactory myFactory = new AFactory(); + + //自定义拦截器 + MyInterceptor myInterceptor = new MyInterceptor(); + + //自定义拦截器策略 + MyIntercepterStrategy myIntercepterStrategy = new MyIntercepterStrategy(); + + //自定义Dao + MySmsDao mySmsDao = MySmsDao.getInstance();; + + //初始化SMS + SEInitializer + //这里之后的方法顺序可以任意排列,但是必须以initializer开始 + .initializer() + //注册自定义拦截器策略 + .registerIInterceptorStrategy(myIntercepterStrategy) + //注册自定义拦截器 + .registerSmsMethodInterceptor(myInterceptor) + //注册自定义渠道工厂 + .registerFactory(myFactory) + //注册自定义 smsDao + .registerSmsDao(mySmsDao) + //这里之前的方法顺序可以任意排列,但是必须以fromYaml结尾 + .fromYaml(); + + ParamValidate paramValidate = new ParamValidate("a","11111111111"); + paramValidate.test(); + } +} diff --git a/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEYmlSendsTest.java b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEYmlSendsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..202a5fe7f2c917c2ffa7a0d773540ef11b88140e --- /dev/null +++ b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEYmlSendsTest.java @@ -0,0 +1,53 @@ +package org.dromara.sms4j.test; + +import org.dromara.sms4j.javase.config.SEInitializer; +import org.dromara.sms4j.test.send.SimpleSendMsgById; +import org.dromara.sms4j.test.send.SimpleSendMsgByLoadBalance; +import org.dromara.sms4j.test.send.SimpleSendMsgBySupplier; + +import sms4j.dao.MySmsDao; +import sms4j.interceptor.MyIntercepterStrategy; +import sms4j.interceptor.MyInterceptor; +import sms4j.local.a.AFactory; + +/* +* 测试情况 +* */ +public class SEYmlSendsTest { + + public static void main(String[] args) { + //自定义渠道工厂 + AFactory myFactory = new AFactory(); + + //自定义拦截器 + MyInterceptor myInterceptor = new MyInterceptor(); + + //自定义拦截器策略 + MyIntercepterStrategy myIntercepterStrategy = new MyIntercepterStrategy(); + + //自定义Dao + MySmsDao mySmsDao = MySmsDao.getInstance();; + + //初始化SMS + SEInitializer + //这里之后的方法顺序可以任意排列,但是必须以initializer开始 + .initializer() + //注册自定义拦截器策略,可以有多个本方法调用 + .registerIInterceptorStrategy(myIntercepterStrategy) + //注册自定义拦截器,可以有多个本方法调用 + .registerSmsMethodInterceptor(myInterceptor) + //注册自定义渠道工厂,可以有多个本方法调用 + .registerFactory(myFactory) + //注册自定义 smsDao,只能有一个,以最后一次调用为准 + .registerSmsDao(mySmsDao) + //这里之前的方法顺序可以任意排列,但是必须以fromYaml结尾 + .fromYaml(); + + SimpleSendMsgById simpleSendMsgById = new SimpleSendMsgById("a1", "11111111111"); + simpleSendMsgById.test(); + SimpleSendMsgByLoadBalance simpleSendMsgByLoadBalance = new SimpleSendMsgByLoadBalance("a","11111111111"); + simpleSendMsgByLoadBalance.test(); + SimpleSendMsgBySupplier simpleSendMsgBySupplier = new SimpleSendMsgBySupplier("a","11111111111"); + simpleSendMsgBySupplier.test(); + } +} diff --git a/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEYmlSimpleChannelAllValidateTest.java b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEYmlSimpleChannelAllValidateTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d8848702c8e23cf681afd12fc1ae71051f229374 --- /dev/null +++ b/sms4j-example/JavaSE/src/main/java/org/dromara/sms4j/test/SEYmlSimpleChannelAllValidateTest.java @@ -0,0 +1,54 @@ +package org.dromara.sms4j.test; + +import org.dromara.sms4j.javase.config.SEInitializer; +import org.dromara.sms4j.test.complexity.MultiChannelAllValidate; +import org.dromara.sms4j.test.complexity.SimpleChannelAllValidate; + +import sms4j.dao.MySmsDao; +import sms4j.interceptor.MyIntercepterStrategy; +import sms4j.interceptor.MyInterceptor; +import sms4j.local.a.AFactory; +import sms4j.local.b.BFactory; +import sms4j.local.c.CFactory; + +/* +* 测试情况 +* */ +public class SEYmlSimpleChannelAllValidateTest { + + public static void main(String[] args) { + //自定义渠道工厂 + AFactory myFactory = new AFactory(); + BFactory bFactory = new BFactory(); + CFactory cFactory = new CFactory(); + + //自定义拦截器 + MyInterceptor myInterceptor = new MyInterceptor(); + + //自定义拦截器策略 + MyIntercepterStrategy myIntercepterStrategy = new MyIntercepterStrategy(); + + //自定义Dao + MySmsDao mySmsDao = MySmsDao.getInstance();; + + //初始化SMS + SEInitializer + //这里之后的方法顺序可以任意排列,但是必须以initializer开始 + .initializer() + //注册自定义拦截器策略,可以有多个本方法调用 + .registerIInterceptorStrategy(myIntercepterStrategy) + //注册自定义拦截器,可以有多个本方法调用 + .registerSmsMethodInterceptor(myInterceptor) + //注册自定义渠道工厂,可以有多个本方法调用 + .registerFactory(myFactory) + .registerFactory(bFactory) + .registerFactory(cFactory) + //注册自定义 smsDao,只能有一个,以最后一次调用为准 + .registerSmsDao(mySmsDao) + //这里之前的方法顺序可以任意排列,但是必须以fromYaml结尾 + .fromYaml(); + + SimpleChannelAllValidate simpleChannelAllValidate = new SimpleChannelAllValidate("11111111111", "22222222222", "a"); + simpleChannelAllValidate.test(); + } +} diff --git a/sms4j-example/JavaSE/src/main/resources/sms4j.yml b/sms4j-example/JavaSE/src/main/resources/sms4j.yml new file mode 100644 index 0000000000000000000000000000000000000000..7a6c3a8edc63985f6657fe45faf1245504fa3ca0 --- /dev/null +++ b/sms4j-example/JavaSE/src/main/resources/sms4j.yml @@ -0,0 +1,23 @@ +sms: + # 标注从yml读取配置 + config-type: yaml + # 标注所有的限制是否开启,黑名单和调用参数校验无法关闭 + restricted: true + # 时段级限制 + minute-max: 5 + # 账号级限制 + account-max: 6 + # sms渠道配置 + blends: + # ID + a1: + # 渠道ID,如果是自定义要和自定义的supplierID是一样的 + supplier: a + # 渠道级限制 + maximum: 8 + b1: + supplier: b + maximum: 8 + c1: + supplier: c + maximum: 8 diff --git a/sms4j-example/SpringBoot/SpringBootYamlFile/pom.xml b/sms4j-example/SpringBoot/SpringBootYamlFile/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..ed0104eb0c7478a94d776a2473e334f3c29574ff --- /dev/null +++ b/sms4j-example/SpringBoot/SpringBootYamlFile/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + + org.dromara.sms4j + SpringBoot + 1.0-SNAPSHOT + + + org.dromara.sms4j + SpringBootYamlFile + 1.0-SNAPSHOT + + \ No newline at end of file diff --git a/sms4j-example/SpringBoot/SpringBootYamlFile/src/main/java/org/dromara/sms4j/min/BootSms4jTestByYaml2.java b/sms4j-example/SpringBoot/SpringBootYamlFile/src/main/java/org/dromara/sms4j/min/BootSms4jTestByYaml2.java new file mode 100644 index 0000000000000000000000000000000000000000..6805c714cdff02ba20e8bcd853c883c38739eb5f --- /dev/null +++ b/sms4j-example/SpringBoot/SpringBootYamlFile/src/main/java/org/dromara/sms4j/min/BootSms4jTestByYaml2.java @@ -0,0 +1,16 @@ +package org.dromara.sms4j.min; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication +@ComponentScan(basePackages = {"org.dromara.sms4j.source"}) +public class BootSms4jTestByYaml2 { + + public static void main(String[] args) { + SpringApplication.run(BootSms4jTestByYaml2.class, args); + + } + +} diff --git a/sms4j-example/SpringBoot/SpringBootYamlFile/src/main/java/org/dromara/sms4j/source/Load.java b/sms4j-example/SpringBoot/SpringBootYamlFile/src/main/java/org/dromara/sms4j/source/Load.java new file mode 100644 index 0000000000000000000000000000000000000000..64eaf0b47cbb11454eeedd0ef31fa836e114dd98 --- /dev/null +++ b/sms4j-example/SpringBoot/SpringBootYamlFile/src/main/java/org/dromara/sms4j/source/Load.java @@ -0,0 +1,46 @@ +package org.dromara.sms4j.source; + +import org.dromara.sms4j.api.dao.SmsDao; +import org.dromara.sms4j.provider.factory.ProviderFactoryHolder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import sms4j.dao.MySmsDao; +import sms4j.interceptor.MyIntercepterStrategy; +import sms4j.interceptor.MyInterceptor; +import sms4j.local.a.AFactory; +import sms4j.local.b.BFactory; +import sms4j.local.c.CFactory; + +@Configuration +public class Load { + + @Bean + public SmsDao smsDao(){ + return MySmsDao.getInstance(); + } + + @Bean + public AFactory aFactory() { + return AFactory.instance(); + } + + @Bean + public BFactory bFactory() { + return BFactory.instance(); + } + + @Bean + public CFactory cFactory() { + return CFactory.instance(); + } + + @Bean + public MyIntercepterStrategy myIntercepterStrategy() { + return new MyIntercepterStrategy(); + } + + @Bean + public MyInterceptor myInterceptor() { + return new MyInterceptor(); + } +} diff --git a/sms4j-example/SpringBoot/SpringBootYamlFile/src/main/resources/application.yml b/sms4j-example/SpringBoot/SpringBootYamlFile/src/main/resources/application.yml new file mode 100644 index 0000000000000000000000000000000000000000..7a6c3a8edc63985f6657fe45faf1245504fa3ca0 --- /dev/null +++ b/sms4j-example/SpringBoot/SpringBootYamlFile/src/main/resources/application.yml @@ -0,0 +1,23 @@ +sms: + # 标注从yml读取配置 + config-type: yaml + # 标注所有的限制是否开启,黑名单和调用参数校验无法关闭 + restricted: true + # 时段级限制 + minute-max: 5 + # 账号级限制 + account-max: 6 + # sms渠道配置 + blends: + # ID + a1: + # 渠道ID,如果是自定义要和自定义的supplierID是一样的 + supplier: a + # 渠道级限制 + maximum: 8 + b1: + supplier: b + maximum: 8 + c1: + supplier: c + maximum: 8 diff --git a/sms4j-example/SpringBoot/SpringbootReadConfig/pom.xml b/sms4j-example/SpringBoot/SpringbootReadConfig/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..0261ee1d78c038003fe0cd4bddd4111dcba89029 --- /dev/null +++ b/sms4j-example/SpringBoot/SpringbootReadConfig/pom.xml @@ -0,0 +1,18 @@ + + + 4.0.0 + + + org.dromara.sms4j + SpringBoot + 1.0-SNAPSHOT + + + org.dromara.sms4j + SpringbootReadConfig + 1.0-SNAPSHOT + + + \ No newline at end of file diff --git a/sms4j-example/SpringBoot/SpringbootReadConfig/src/main/java/org/dromara/sms4j/test/blacklist/BootConfigBlackListValidateConfig.java b/sms4j-example/SpringBoot/SpringbootReadConfig/src/main/java/org/dromara/sms4j/test/blacklist/BootConfigBlackListValidateConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..0d8367f8713836107a65ae8ea01a5f46389a1630 --- /dev/null +++ b/sms4j-example/SpringBoot/SpringbootReadConfig/src/main/java/org/dromara/sms4j/test/blacklist/BootConfigBlackListValidateConfig.java @@ -0,0 +1,68 @@ +package org.dromara.sms4j.test.blacklist; + +import org.dromara.sms4j.core.datainterface.SmsBlendsSelectedConfig; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.provider.config.BaseConfig; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.context.event.EventListener; + + +import sms4j.dao.MySmsDao; +import sms4j.interceptor.MyIntercepterStrategy; +import sms4j.interceptor.MyInterceptor; +import sms4j.local.a.AConfig; +import sms4j.local.a.AFactory; + +// SmsReadConfig 是一个存在但是未来可能被删除的一个接口,理想状态是使用 【SmsBlendsBeanConfig、SmsBlendsSelectedConfig】 SmsReadConfig正是继承了前面提到的两个接口 +// 这里为了只用一个类配置以此测试演示,使用中可以分开配置不用都写在一起 +@Configuration +public class BootConfigBlackListValidateConfig implements SmsBlendsSelectedConfig { + + //自定义渠道工厂 + @Bean + public AFactory myFactory() { + return new AFactory(); + } + + //自定义拦截器 + @Bean + public MyInterceptor myInterceptor() { + return new MyInterceptor(); + } + + //自定义拦截器策略 + @Bean + public MyIntercepterStrategy myIntercepterStrategy() { + return new MyIntercepterStrategy(); + } + + //自定义Dao + @Bean + public MySmsDao mySmsDao() { + return MySmsDao.getInstance(); + } + + @Override + public BaseConfig getSupplierConfig(String configId) { + // 服务商渠道配置 + // 服务商 + AConfig aConfig = new AConfig(); + if ("a1".equals(configId)){ + aConfig.setMaximum(5); + aConfig.setConfigId("a1"); + } + if ("a2".equals(configId)){ + aConfig.setMaximum(5); + aConfig.setConfigId("a2"); + } + return aConfig; + } + + @EventListener + //不是非要用监听器,有无数种方法,这里就是介绍这个SmsBlendsSelectedConfig 需要你在本类加载之后手动createSmsBlend选择使用那一个配置 + public void whenYouAppStarted(ContextRefreshedEvent event){ + SmsFactory.createSmsBlend(this,"a1"); + } +} diff --git a/sms4j-example/SpringBoot/SpringbootReadConfig/src/main/java/org/dromara/sms4j/test/blacklist/BootConfigBlackListValidateTest.java b/sms4j-example/SpringBoot/SpringbootReadConfig/src/main/java/org/dromara/sms4j/test/blacklist/BootConfigBlackListValidateTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a6ef686fd56aa602e9d3e2ea07d771a412e12f1b --- /dev/null +++ b/sms4j-example/SpringBoot/SpringbootReadConfig/src/main/java/org/dromara/sms4j/test/blacklist/BootConfigBlackListValidateTest.java @@ -0,0 +1,16 @@ +package org.dromara.sms4j.test.blacklist; + +import org.dromara.sms4j.test.validate.BlackListValidate; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class BootConfigBlackListValidateTest { + + public static void main(String[] args) { + SpringApplication.run(BootConfigBlackListValidateTest.class, args); + + BlackListValidate blackListValidate = new BlackListValidate("a","11111111111"); + blackListValidate.test(); + } +} diff --git a/sms4j-example/SpringBoot/SpringbootReadConfig/src/main/java/org/dromara/sms4j/test/paramvalidate/BootConfigParamValidateConfig.java b/sms4j-example/SpringBoot/SpringbootReadConfig/src/main/java/org/dromara/sms4j/test/paramvalidate/BootConfigParamValidateConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..45edb1aacc8efa568686a9a623675a52517491d9 --- /dev/null +++ b/sms4j-example/SpringBoot/SpringbootReadConfig/src/main/java/org/dromara/sms4j/test/paramvalidate/BootConfigParamValidateConfig.java @@ -0,0 +1,67 @@ +package org.dromara.sms4j.test.paramvalidate; + +import org.dromara.sms4j.core.datainterface.SmsBlendsSelectedConfig; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.sms4j.provider.config.BaseConfig; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.context.event.EventListener; + +import sms4j.dao.MySmsDao; +import sms4j.interceptor.MyIntercepterStrategy; +import sms4j.interceptor.MyInterceptor; +import sms4j.local.a.AConfig; +import sms4j.local.a.AFactory; + +// SmsReadConfig 是一个存在但是未来可能被删除的一个接口,理想状态是使用 【SmsBlendsBeanConfig、SmsBlendsSelectedConfig】 SmsReadConfig正是继承了前面提到的两个接口 +// 这里为了只用一个类配置以此测试演示,使用中可以分开配置不用都写在一起 +@Configuration +public class BootConfigParamValidateConfig implements SmsBlendsSelectedConfig { + + //自定义渠道工厂 + @Bean + public AFactory myFactory() { + return new AFactory(); + } + + //自定义拦截器 + @Bean + public MyInterceptor myInterceptor() { + return new MyInterceptor(); + } + + //自定义拦截器策略 + @Bean + public MyIntercepterStrategy myIntercepterStrategy() { + return new MyIntercepterStrategy(); + } + + //自定义Dao + @Bean + public MySmsDao mySmsDao() { + return MySmsDao.getInstance(); + } + + @Override + public BaseConfig getSupplierConfig(String configId) { + // 服务商渠道配置 + // 服务商 + AConfig aConfig = new AConfig(); + if ("a1".equals(configId)){ + aConfig.setMaximum(5); + aConfig.setConfigId("a1"); + } + if ("a2".equals(configId)){ + aConfig.setMaximum(5); + aConfig.setConfigId("a2"); + } + return aConfig; + } + + @EventListener + //不是非要用监听器,有无数种方法,这里就是介绍这个SmsBlendsSelectedConfig 需要你在本类加载之后手动createSmsBlend选择使用那一个配置 + public void whenYouAppStarted(ContextRefreshedEvent event){ + SmsFactory.createSmsBlend(this,"a1"); + } +} diff --git a/sms4j-example/SpringBoot/SpringbootReadConfig/src/main/java/org/dromara/sms4j/test/paramvalidate/BootConfigParamValidateTest.java b/sms4j-example/SpringBoot/SpringbootReadConfig/src/main/java/org/dromara/sms4j/test/paramvalidate/BootConfigParamValidateTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a56f894bffb30d80d451635aab0f0d2d9892f13e --- /dev/null +++ b/sms4j-example/SpringBoot/SpringbootReadConfig/src/main/java/org/dromara/sms4j/test/paramvalidate/BootConfigParamValidateTest.java @@ -0,0 +1,15 @@ +package org.dromara.sms4j.test.paramvalidate; + +import org.dromara.sms4j.test.validate.ParamValidate; +import org.springframework.boot.SpringApplication; + +public class BootConfigParamValidateTest { + + public static void main(String[] args) { + SpringApplication.run(org.dromara.sms4j.test.blacklist.BootConfigBlackListValidateTest.class, args); + + + ParamValidate paramValidate = new ParamValidate("a","11111111111"); + paramValidate.test(); + } +} diff --git a/sms4j-example/SpringBoot/SpringbootReadConfig/src/main/resources/application.yml b/sms4j-example/SpringBoot/SpringbootReadConfig/src/main/resources/application.yml new file mode 100644 index 0000000000000000000000000000000000000000..8fc9b069ae914982e4dfa013a06663383fdbb771 --- /dev/null +++ b/sms4j-example/SpringBoot/SpringbootReadConfig/src/main/resources/application.yml @@ -0,0 +1,9 @@ +sms: + # 标注从yml读取配置 + config-type: interface + # 是否开启拦截 + restricted: true + # 账户发送上限 + account-max: 4 + # 分钟发送上限 + minute-max: 3 diff --git a/sms4j-example/SpringBoot/pom.xml b/sms4j-example/SpringBoot/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..bd885233068a89edba31ae537823d739b4f57659 --- /dev/null +++ b/sms4j-example/SpringBoot/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + + org.dromara.sms4j + sms4j-example + 1.0-SNAPSHOT + + pom + + SpringbootReadConfig + SpringBootYamlFile + + + SpringBoot + 1.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-dependencies + ${spring.boot.version} + pom + import + + + org.dromara.sms4j + sms4j-spring-boot-starter + ${sms4j.version} + + + org.springframework.boot + spring-boot-starter + ${spring.boot.version} + + + org.dromara.sms4j + TestCase + 1.0-SNAPSHOT + + + org.dromara.sms4j + Customize + 1.0-SNAPSHOT + + + \ No newline at end of file diff --git "a/sms4j-example/\346\240\267\344\276\213\347\273\223\346\236\204.MD" "b/sms4j-example/\346\240\267\344\276\213\347\273\223\346\236\204.MD" new file mode 100644 index 0000000000000000000000000000000000000000..23507062586a8558620927f087072ad5cc68e5c0 --- /dev/null +++ "b/sms4j-example/\346\240\267\344\276\213\347\273\223\346\236\204.MD" @@ -0,0 +1,51 @@ +# 项目结构 +* sms4j-example + * [Component](Component) 基础依赖,包括测试案例和自定义的相关内容 + * [Customize](Component%2FCustomize) sms4j扩展的自定义案例的相关内容 + * 自定义SmsDao实现 [dao](Component%2FCustomize%2Fsrc%2Fmain%2Fjava%2Fsms4j%2Fdao) + * 自定义拦截器、拦截器策略实现 [interceptor](Component%2FCustomize%2Fsrc%2Fmain%2Fjava%2Fsms4j%2Finterceptor) + * 自定义厂商实现 [local](Component%2FCustomize%2Fsrc%2Fmain%2Fjava%2Fsms4j%2Flocal) + * [TestCase](base%2FTestCase) 测试案例 + * 核心参数校验案例 [ParamValidate.java](Component%2FTestCase%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Ftest%2Fvalidate%2FParamValidate.java) + * 黑名单添加删除触发案例 [BlackListValidate.java](Component%2FTestCase%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Ftest%2Fvalidate%2FBlackListValidate.java) + * 基础发送案例 SmsFactory.getSmsBlend(CHANNEL) [SimpleSendMsgById.java](Component%2FTestCase%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Ftest%2Fsend%2FSimpleSendMsgById.java) + * 基础发送案例 SmsFactory.getSmsBlend() [SimpleSendMsgByLoadBalance.java](Component%2FTestCase%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Ftest%2Fsend%2FSimpleSendMsgByLoadBalance.java) + * 基础发送案例 SmsFactory.getBySupplier(CHANNEL) [SimpleSendMsgBySupplier.java](Component%2FTestCase%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Ftest%2Fsend%2FSimpleSendMsgBySupplier.java) + * 账号级限制案例发送6次报错 [AcctMaxRestricted5Times.java](Component%2FTestCase%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Ftest%2Frestricted%2FAcctMaxRestricted5Times.java) + * 渠道级限制案例发送6次报错 [ChannelMaxRestricted5Times.java](Component%2FTestCase%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Ftest%2Frestricted%2FChannelMaxRestricted5Times.java) + * 时段级限制案例发送6次报错 [SpanMaxRestricted5Times.java](Component%2FTestCase%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Ftest%2Frestricted%2FSpanMaxRestricted5Times.java) + * 单渠道全校验案例 [SimpleChannelAllValidate.java](Component%2FTestCase%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Ftest%2Fcomplexity%2FSimpleChannelAllValidate.java) + * 多渠道全校验案例 [MultiChannelAllValidate.java](Component%2FTestCase%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Ftest%2Fcomplexity%2FMultiChannelAllValidate.java) + * [JavaSE-Demo](JavaSE-Demo) JavaSE环境下的样例工程和测试工程 + * [demo](JavaSE-Demo%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Fdemo) 样例工程 + * ConfigBean配置的账户级限制 [ConfigBeanAcctRestricted.java](JavaSE-Demo%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Fdemo%2FConfigBeanAcctRestricted.java) + * ConfigBean配置的基础发送 [ConfigBeanBasicSend.java](JavaSE-Demo%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Fdemo%2FConfigBeanBasicSend.java) + * ConfigBean配置的黑名单使用 [ConfigBeanBlackList.java](JavaSE-Demo%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Fdemo%2FConfigBeanBlackList.java) + * ConfigBean配置的渠道级限制 [ConfigBeanChannelRestricted.java](JavaSE-Demo%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Fdemo%2FConfigBeanChannelRestricted.java) + * ConfigBean配置的自定义渠道 [ConfigBeanCustomizeChannel.java](JavaSE-Demo%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Fdemo%2FConfigBeanCustomizeChannel.java) + * ConfigBean配置的自定义拦截器 [ConfigBeanCustomizeInterceptor.java](JavaSE-Demo%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Fdemo%2FConfigBeanCustomizeInterceptor.java) + * ConfigBean配置的自定义SmsDao [ConfigBeanCustomizeSmsDao.java](JavaSE-Demo%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Fdemo%2FConfigBeanCustomizeSmsDao.java) + * ConfigBean配置的全部功能 [ConfigBeanSms4jFullFunctions.java](JavaSE-Demo%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Fdemo%2FConfigBeanSms4jFullFunctions.java) + * ConfigBean配置的时段级限制 [ConfigBeanSpanRestricted.java](JavaSE-Demo%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Fdemo%2FConfigBeanSpanRestricted.java) + * Yaml配置的基础发送 [YamlBasicSend.java](JavaSE-Demo%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Fdemo%2FYamlBasicSend.java) + * Yaml配置的全部功能 [YamlFullFunctions.java](JavaSE-Demo%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Fdemo%2FYamlFullFunctions.java) + * Yaml配置的黑名单使用除配置在yaml里其它与ConfigBean相同 + * Yaml配置的账户级限制除配置在yaml里其它与ConfigBean相同 + * Yaml配置的渠道级限制除配置在yaml里其它与ConfigBean相同 + * Yaml配置的时段级限制除配置在yaml里其它与ConfigBean相同 + * Yaml配置的自定义渠道 [YamlCustomizeChannel.java](JavaSE-Demo%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Fdemo%2FYamlCustomizeChannel.java) + * Yaml配置的自定义拦截器 [YamlCustomizeInterceptor.java](JavaSE-Demo%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Fdemo%2FYamlCustomizeInterceptor.java) + * Yaml配置的自定义SmsDao [YamlCustomizeSmsDao.java](JavaSE-Demo%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Fdemo%2FYamlCustomizeSmsDao.java) + * 测试工程 + * yml黑名单功能测试 [SEYmlBlackListValidateTest.java](JavaSE-Demo%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Ftest%2FSEYmlBlackListValidateTest.java) + * yml多渠道全功能测试 [SEYmlMultiChannelAllValidateTest.java](JavaSE-Demo%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Ftest%2FSEYmlMultiChannelAllValidateTest.java) + * yml核心参数测试 [SEYmlParamValidateTest.java](JavaSE-Demo%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Ftest%2FSEYmlParamValidateTest.java) + * yml发送基础测试 [SEYmlSendsTest.java](JavaSE-Demo%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Ftest%2FSEYmlSendsTest.java) + * yml单渠道全功能测试 [SEYmlSimpleChannelAllValidateTest.java](JavaSE-Demo%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Ftest%2FSEYmlSimpleChannelAllValidateTest.java) + * ConfigBean黑名单功能测试 [SEConfigBeanBlackListValidateTest.java](JavaSE-Demo%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Ftest%2FSEConfigBeanBlackListValidateTest.java) + * ConfigBean多渠道全功能测试 [SEConfigBeanMultiChannelAllValidateTest.java](JavaSE-Demo%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Ftest%2FSEConfigBeanMultiChannelAllValidateTest.java) + * ConfigBean核心参数测试 [SEConfigBeanParamValidateTest.java](JavaSE-Demo%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Ftest%2FSEConfigBeanParamValidateTest.java) + * ConfigBean发送基础测试 [SEConfigBeanSendsTest.java](JavaSE-Demo%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Ftest%2FSEConfigBeanSendsTest.java) + * ConfigBean单渠道全功能测试 [SEConfigBeanSimpleChannelAllValidateTest.java](JavaSE-Demo%2Fsrc%2Fmain%2Fjava%2Forg%2Fdromara%2Fsms4j%2Ftest%2FSEConfigBeanSimpleChannelAllValidateTest.java) + * [SpringBoot](SpringBoot) + \ No newline at end of file diff --git a/sms4j-javase-plugin/src/main/java/org/dromara/sms4j/javase/config/SEInitializer.java b/sms4j-javase-plugin/src/main/java/org/dromara/sms4j/javase/config/SEInitializer.java index e4e50e0f9911fc5f4f74bf2d7c9f82c090cd8c9b..1426de6f65ce1e10b3f8470e7920d579608a3ba7 100644 --- a/sms4j-javase-plugin/src/main/java/org/dromara/sms4j/javase/config/SEInitializer.java +++ b/sms4j-javase-plugin/src/main/java/org/dromara/sms4j/javase/config/SEInitializer.java @@ -3,50 +3,30 @@ package org.dromara.sms4j.javase.config; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.io.resource.ClassPathResource; -import cn.hutool.core.util.StrUtil; -import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; import lombok.extern.slf4j.Slf4j; -import org.dromara.sms4j.aliyun.config.AlibabaFactory; import org.dromara.sms4j.api.SmsBlend; import org.dromara.sms4j.api.dao.SmsDao; -import org.dromara.sms4j.api.dao.SmsDaoDefaultImpl; +import org.dromara.sms4j.api.proxy.SmsMethodInterceptor; +import org.dromara.sms4j.api.strategy.IInterceptorStrategy; import org.dromara.sms4j.api.universal.SupplierConfig; -import org.dromara.sms4j.cloopen.config.CloopenFactory; -import org.dromara.sms4j.comm.constant.Constant; import org.dromara.sms4j.comm.exception.SmsBlendException; -import org.dromara.sms4j.comm.utils.SmsUtils; import org.dromara.sms4j.core.factory.SmsFactory; -import org.dromara.sms4j.core.proxy.EnvirmentHolder; -import org.dromara.sms4j.core.proxy.SmsProxyFactory; -import org.dromara.sms4j.core.proxy.processor.BlackListProcessor; -import org.dromara.sms4j.core.proxy.processor.BlackListRecordingProcessor; -import org.dromara.sms4j.core.proxy.processor.CoreMethodParamValidateProcessor; -import org.dromara.sms4j.core.proxy.processor.RestrictedProcessor; -import org.dromara.sms4j.core.proxy.processor.SingleBlendRestrictedProcessor; -import org.dromara.sms4j.ctyun.config.CtyunFactory; -import org.dromara.sms4j.dingzhong.config.DingZhongFactory; -import org.dromara.sms4j.emay.config.EmayFactory; -import org.dromara.sms4j.huawei.config.HuaweiFactory; +import org.dromara.sms4j.core.initalize.AbstractInitalizer; import org.dromara.sms4j.javase.util.YamlUtils; -import org.dromara.sms4j.jdcloud.config.JdCloudFactory; -import org.dromara.sms4j.lianlu.config.LianLuFactory; -import org.dromara.sms4j.netease.config.NeteaseFactory; import org.dromara.sms4j.provider.config.SmsConfig; import org.dromara.sms4j.provider.factory.BaseProviderFactory; import org.dromara.sms4j.provider.factory.BeanFactory; import org.dromara.sms4j.provider.factory.ProviderFactoryHolder; -import org.dromara.sms4j.tencent.config.TencentFactory; -import org.dromara.sms4j.unisms.config.UniFactory; -import org.dromara.sms4j.yunpian.config.YunPianFactory; -import org.dromara.sms4j.zhutong.config.ZhutongFactory; import java.beans.BeanInfo; +import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; @@ -56,7 +36,7 @@ import java.util.Map; * 初始化类 */ @Slf4j -public class SEInitializer { +public class SEInitializer extends AbstractInitalizer { private static final SEInitializer INSTANCE = new SEInitializer(); @@ -64,14 +44,13 @@ public class SEInitializer { return INSTANCE; } - private SmsDao smsDao; /** * 默认从sms4j.yml文件中读取配置 */ public void fromYaml() { - ClassPathResource yamlResouce = new ClassPathResource("sms4j.yml"); - this.fromYaml(yamlResouce.readUtf8Str()); + ClassPathResource yamlResource = new ClassPathResource("sms4j.yml"); + this.fromYaml(yamlResource.readUtf8Str()); } /** @@ -109,32 +88,29 @@ public class SEInitializer { if (CollUtil.isEmpty(configList)) { return; } - try{ + try { Map> blends = new HashMap<>(); for (SupplierConfig supplierConfig : configList) { Map param = new HashMap<>(); - String channel = supplierConfig.getSupplier(); + String channel = supplierConfig.getConfigId(); + if (null == channel){ + throw new IllegalArgumentException("自定义Config对象未设置configId"); + } Class clazz = supplierConfig.getClass(); BeanInfo beanInfo = Introspector.getBeanInfo(clazz, Object.class); PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { Method readMethod = propertyDescriptor.getReadMethod(); Object item = readMethod.invoke(supplierConfig); - param.put(propertyDescriptor.getName(),item); + param.put(propertyDescriptor.getName(), item); } - blends.put(channel,param); + blends.put(channel, param); } - //持有初始化配置信息 - EnvirmentHolder.frozenEnvirmet(smsConfig, blends); - - //注册执行器实现 - SmsProxyFactory.addProcessor(new RestrictedProcessor()); - SmsProxyFactory.addProcessor(new BlackListProcessor()); - SmsProxyFactory.addProcessor(new BlackListRecordingProcessor()); - SmsProxyFactory.addProcessor(new SingleBlendRestrictedProcessor()); - SmsProxyFactory.addProcessor(new CoreMethodParamValidateProcessor()); - }catch (Exception e){ + initInterceptor(blends, smsConfig); + } catch (IntrospectionException | InvocationTargetException e) { log.error("配置对象转换配置信息失败,但不影响基础功能的使用。【注意】:未加载SMS4J扩展功能模块,拦截器,参数校验可能失效!"); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); } for (SupplierConfig supplierConfig : configList) { SmsFactory.createSmsBlend(supplierConfig); @@ -142,12 +118,22 @@ public class SEInitializer { } /** - * 注册服务商工厂 + * 注册拦截器 * - * @param factory 服务商工厂 + * @param interceptor 拦截器 */ - public SEInitializer registerFactory(BaseProviderFactory factory) { - ProviderFactoryHolder.registerFactory(factory); + public SEInitializer registerSmsMethodInterceptor(SmsMethodInterceptor interceptor) { + doRegisterSmsMethodInterceptor(interceptor); + return this; + } + + /** + * 注册拦截器执行策略 + * + * @param interceptorStrategy 拦截器执行策略 + */ + public SEInitializer registerIInterceptorStrategy(IInterceptorStrategy interceptorStrategy) { + doRegisterIInterceptorStrategy(interceptorStrategy); return this; } @@ -160,8 +146,17 @@ public class SEInitializer { if (smsDao == null) { throw new SmsBlendException("注册DAO实例失败,实例不能为空"); } - this.smsDao = smsDao; - SESmsDaoHolder.setSmsDao(smsDao); + doRegisterSmsDao(smsDao); + return this; + } + + /** + * 注册服务商工厂 + * + * @param factory 服务商工厂 + */ + public SEInitializer registerFactory(BaseProviderFactory factory) { + ProviderFactoryHolder.registerFactory(factory); return this; } @@ -176,67 +171,22 @@ public class SEInitializer { throw new SmsBlendException("初始化配置失败"); } - //注册默认DAO实例 - if (this.smsDao == null) { - this.registerSmsDao(SmsDaoDefaultImpl.getInstance()); - } - //注册默认工厂 registerDefaultFactory(); //初始化SmsConfig整体配置文件 BeanUtil.copyProperties(smsConfig, BeanFactory.getSmsConfig()); - // 解析服务商配置 + //获取各厂商配置 Map> blends = smsConfig.getBlends(); - //持有初始化配置信息 - EnvirmentHolder.frozenEnvirmet(smsConfig, blends); + //装在拦截器和拦截器策略 + initInterceptor(blends, smsConfig); - //注册执行器实现 - SmsProxyFactory.addProcessor(new RestrictedProcessor()); - SmsProxyFactory.addProcessor(new BlackListProcessor()); - SmsProxyFactory.addProcessor(new BlackListRecordingProcessor()); - SmsProxyFactory.addProcessor(new SingleBlendRestrictedProcessor()); - SmsProxyFactory.addProcessor(new CoreMethodParamValidateProcessor()); - for (String configId : blends.keySet()) { - Map configMap = blends.get(configId); - Object supplierObj = configMap.get(Constant.SUPPLIER_KEY); - String supplier = supplierObj == null ? "" : String.valueOf(supplierObj); - supplier = StrUtil.isEmpty(supplier) ? configId : supplier; - BaseProviderFactory providerFactory = (BaseProviderFactory) ProviderFactoryHolder.requireForSupplier(supplier); - if (providerFactory == null) { - log.warn("创建\"{}\"的短信服务失败,未找到服务商为\"{}\"的服务", configId, supplier); - continue; - } - configMap.put("config-id", configId); - SmsUtils.replaceKeysSeperator(configMap, "-", "_"); - JSONObject configJson = new JSONObject(configMap); - SupplierConfig supplierConfig = JSONUtil.toBean(configJson, providerFactory.getConfigClass()); - SmsFactory.createSmsBlend(supplierConfig); - } + // 解析供应商配置 + doParseChannelConfigWithCreate(blends); } - /** - * 注册默认工厂实例 - */ - private void registerDefaultFactory() { - ProviderFactoryHolder.registerFactory(AlibabaFactory.instance()); - ProviderFactoryHolder.registerFactory(CloopenFactory.instance()); - ProviderFactoryHolder.registerFactory(CtyunFactory.instance()); - ProviderFactoryHolder.registerFactory(EmayFactory.instance()); - ProviderFactoryHolder.registerFactory(HuaweiFactory.instance()); - ProviderFactoryHolder.registerFactory(NeteaseFactory.instance()); - ProviderFactoryHolder.registerFactory(TencentFactory.instance()); - ProviderFactoryHolder.registerFactory(UniFactory.instance()); - ProviderFactoryHolder.registerFactory(YunPianFactory.instance()); - ProviderFactoryHolder.registerFactory(ZhutongFactory.instance()); - ProviderFactoryHolder.registerFactory(LianLuFactory.instance()); - ProviderFactoryHolder.registerFactory(DingZhongFactory.instance()); - if (SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) { - ProviderFactoryHolder.registerFactory(JdCloudFactory.instance()); - } - } /** * 初始化配置bean diff --git a/sms4j-javase-plugin/src/main/java/org/dromara/sms4j/javase/config/SESmsDaoHolder.java b/sms4j-javase-plugin/src/main/java/org/dromara/sms4j/javase/config/SESmsDaoHolder.java deleted file mode 100644 index 7188b297318de037c874855dd044bd74efc3c863..0000000000000000000000000000000000000000 --- a/sms4j-javase-plugin/src/main/java/org/dromara/sms4j/javase/config/SESmsDaoHolder.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.dromara.sms4j.javase.config; - -import lombok.Getter; -import org.dromara.sms4j.api.dao.SmsDao; - -public class SESmsDaoHolder { - - @Getter - private static SmsDao smsDao = null; - - public static void setSmsDao(SmsDao smsDao) { - SESmsDaoHolder.smsDao = smsDao; - } -} diff --git a/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/config/OaSupplierConfig.java b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/config/OaSupplierConfig.java index bc56064d9cc77c8c22ce5d3f9fbdc5b3d1045cbe..e4dbbb6f83a534c0dc5794a45eeb54ff989db625 100644 --- a/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/config/OaSupplierConfig.java +++ b/sms4j-oa-plugin/sms4j-oa-core/src/main/java/org/dromara/oa/core/config/OaSupplierConfig.java @@ -3,6 +3,7 @@ package org.dromara.oa.core.config; import org.dromara.oa.api.OaSender; import org.dromara.oa.core.provider.config.OaConfig; import org.dromara.oa.core.provider.factory.OaBaseProviderFactory; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -31,7 +32,7 @@ public class OaSupplierConfig { protected OaBlendsInitializer smsOasInitializer( List> factoryList, OaConfig oaConfig, - Map> oas) { + @Qualifier("oas") Map> oas) { return new OaBlendsInitializer(factoryList,oaConfig,oas); } } diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/lianlu/config/LianLuFactory.java b/sms4j-provider/src/main/java/org/dromara/sms4j/lianlu/config/LianLuFactory.java index 6477fbdeea9b9244e3f6094015f6056cc146c703..d03a9ac45204ac25d9ba4f073661e79c5d02956a 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/lianlu/config/LianLuFactory.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/lianlu/config/LianLuFactory.java @@ -4,6 +4,9 @@ import org.dromara.sms4j.comm.constant.SupplierConstant; import org.dromara.sms4j.lianlu.service.LianLuSmsImpl; import org.dromara.sms4j.provider.factory.BaseProviderFactory; +/** + * 联鹿短信 + * */ public class LianLuFactory implements BaseProviderFactory { private static final LianLuFactory INSTANCE = new LianLuFactory(); diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/local/LocalConfig.java b/sms4j-provider/src/main/java/org/dromara/sms4j/local/LocalConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..b0dd233ceabd568454a3e2dfe89a5e0e181b352c --- /dev/null +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/local/LocalConfig.java @@ -0,0 +1,20 @@ +package org.dromara.sms4j.local; + +import lombok.Getter; +import lombok.Setter; +import org.dromara.sms4j.api.universal.SupplierConfig; +import org.dromara.sms4j.comm.constant.SupplierConstant; + +/** + * 用于测试的{@link SupplierConfig}实现 + * + * @author huangchengxing + * @see SupplierConstant#LOCAL + */ +@Setter +@Getter +public class LocalConfig implements SupplierConfig { + + private String configId = SupplierConstant.LOCAL; + private String supplier = SupplierConstant.LOCAL; +} diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/local/LocalFactory.java b/sms4j-provider/src/main/java/org/dromara/sms4j/local/LocalFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..3cb4cad78d4f0b0b9f0dd780898b6b880a68ddc8 --- /dev/null +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/local/LocalFactory.java @@ -0,0 +1,39 @@ +package org.dromara.sms4j.local; + +import org.dromara.sms4j.aliyun.config.AlibabaFactory; +import org.dromara.sms4j.comm.constant.SupplierConstant; +import org.dromara.sms4j.provider.factory.BaseProviderFactory; + +/** + * 用于创建{@link LocalSmsImpl}的工厂实现 + * + * @author huangchengxing + * @see SupplierConstant#LOCAL + */ +public class LocalFactory implements BaseProviderFactory { + + private static final LocalFactory INSTANCE = new LocalFactory(); + + /** + * 获取建造者实例 + * @return 建造者实例 + */ + public static LocalFactory instance() { + return INSTANCE; + } + + @Override + public LocalSmsImpl createSms(LocalConfig localConfig) { + return new LocalSmsImpl(); + } + + @Override + public Class getConfigClass() { + return LocalConfig.class; + } + + @Override + public String getSupplier() { + return SupplierConstant.LOCAL; + } +} diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/local/LocalSmsImpl.java b/sms4j-provider/src/main/java/org/dromara/sms4j/local/LocalSmsImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..e02b0f9526a54e19955a85e155a26df4df544694 --- /dev/null +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/local/LocalSmsImpl.java @@ -0,0 +1,133 @@ +package org.dromara.sms4j.local; + +import cn.hutool.json.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.callback.CallBack; +import org.dromara.sms4j.api.entity.SmsResponse; +import org.dromara.sms4j.comm.constant.SupplierConstant; + +import java.util.LinkedHashMap; +import java.util.List; + +/** + * 用于测试的{@link SmsBlend}实现, + * 总是在日志中输出参数信息,并成功返回调用结果。 + * + * @author huangchengxing + * @see SupplierConstant#LOCAL + */ +@Slf4j +public class LocalSmsImpl implements SmsBlend { + + @Override + public String getConfigId() { + return SupplierConstant.LOCAL; + } + + @Override + public String getSupplier() { + return SupplierConstant.LOCAL; + } + + @Override + public SmsResponse sendMessage(String phone, String message) { + log.info("send message: phone={}, message={}", phone, message); + return getResponse(new JSONObject() + .set("phone", phone) + .set("message", message)); + } + + @Override + public SmsResponse sendMessage(String phone, LinkedHashMap messages) { + log.info("send message: phone={}, messages={}", phone, messages); + return getResponse(new JSONObject() + .set("phone", phone) + .set("messages", new JSONObject(messages))); + } + + @Override + public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap messages) { + log.info("send message: phone={}, templateId={}, messages={}", phone, templateId, messages); + return getResponse(new JSONObject() + .set("phone", phone) + .set("templateId", templateId) + .set("messages", new JSONObject(messages))); + } + + @Override + public SmsResponse massTexting(List phones, String message) { + log.info("mass texting: phones={}, message={}", phones, message); + return getResponse(new JSONObject() + .set("phones", phones) + .set("message", message)); + } + + @Override + public SmsResponse massTexting(List phones, String templateId, LinkedHashMap messages) { + log.info("mass texting: phones={}, templateId={}, messages={}", phones, templateId, messages); + return getResponse(new JSONObject() + .set("phones", phones) + .set("templateId", templateId) + .set("messages", new JSONObject(messages))); + } + + @Override + public void sendMessageAsync(String phone, String message, CallBack callBack) { + log.info("send message asynchronously: phone={}, message={}", phone, message); + // do nothing + callBack.callBack(getResponse(new JSONObject() + .set("phone", phone) + .set("message", message))); + } + + @Override + public void sendMessageAsync(String phone, String message) { + log.info("send message asynchronously: phone={}, message={}", phone, message); + // do nothing + } + + @Override + public void sendMessageAsync(String phone, String templateId, LinkedHashMap messages, CallBack callBack) { + log.info("send message asynchronously: phone={}, templateId={}, messages={}", phone, templateId, messages); + // do nothing + callBack.callBack(getResponse(new JSONObject() + .set("phone", phone) + .set("templateId", templateId) + .set("messages", new JSONObject(messages)))); + } + + @Override + public void sendMessageAsync(String phone, String templateId, LinkedHashMap messages) { + log.info("send message asynchronously: phone={}, templateId={}, messages={}", phone, templateId, messages); + // do nothing + } + + @Override + public void delayedMessage(String phone, String message, Long delayedTime) { + log.info("delayed message: phone={}, message={}, delayedTime={}", phone, message, delayedTime); + } + + @Override + public void delayedMessage(String phone, String templateId, LinkedHashMap messages, Long delayedTime) { + log.info("delayed message: phone={}, templateId={}, messages={}, delayedTime={}", phone, templateId, messages, delayedTime); + } + + @Override + public void delayMassTexting(List phones, String message, Long delayedTime) { + log.info("delayed mass texting: phones={}, message={}, delayedTime={}", phones, message, delayedTime); + } + + @Override + public void delayMassTexting(List phones, String templateId, LinkedHashMap messages, Long delayedTime) { + log.info("delayed mass texting: phones={}, templateId={}, messages={}, delayedTime={}", phones, templateId, messages, delayedTime); + } + + private SmsResponse getResponse(JSONObject resJson) { + SmsResponse smsResponse = new SmsResponse(); + smsResponse.setSuccess(true); + smsResponse.setData(resJson); + smsResponse.setConfigId(getConfigId()); + return smsResponse; + } +} diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/yoke/config/SmartYokeConfig.java b/sms4j-provider/src/main/java/org/dromara/sms4j/yoke/config/SmartYokeConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..c776bb1592c70ec26c12cc4cf64be1a7fb1602ec --- /dev/null +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/yoke/config/SmartYokeConfig.java @@ -0,0 +1,45 @@ +package org.dromara.sms4j.yoke.config; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.sms4j.comm.constant.SupplierConstant; +import org.dromara.sms4j.provider.config.BaseConfig; + +/** + * {@code @ClassName} SmartYokeConfig + * {@code @Description} 油客配置 + * {@code @Author} 孙浩 + * {@code @Date} 2026/1/12 15:55 + * {@code @Version} 1.0 + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class SmartYokeConfig extends BaseConfig { + + /** + * 渠道标识 固定为 wuche + */ + private final String source = "wuche"; + /** + * 请求地址 + */ + private String requestUrl = "https://pay3.smartyoke.com/smartyouke/platform/api/sms.action"; + + + /** + * 获取供应商 + */ + @Override + public String getSupplier() { + return SupplierConstant.YOKE; + } + + + /** + * 此外还需要添加以下参数 + * accessKeyId: 密钥Id 对应 appId + * accessKeySecret: 密钥 + * signature: 签名值 + * templateId: 模板Id + */ +} diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/yoke/config/SmartYokeFactory.java b/sms4j-provider/src/main/java/org/dromara/sms4j/yoke/config/SmartYokeFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..32c3fc08ef7385b72ded67e246bcfff05403dee2 --- /dev/null +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/yoke/config/SmartYokeFactory.java @@ -0,0 +1,43 @@ +package org.dromara.sms4j.yoke.config; + +import org.dromara.sms4j.provider.factory.AbstractProviderFactory; +import org.dromara.sms4j.yoke.service.SmartYokeServiceImpl; + +/** + * {@code @ClassName} SmartYokeFactory + * {@code @Description} TODO + * {@code @Author} 孙浩 + * {@code @Date} 2026/1/13 9:55 + * {@code @Version} 1.0 + */ +public class SmartYokeFactory extends AbstractProviderFactory { + + + private static final SmartYokeFactory INSTANCE = new SmartYokeFactory(); + + /** + * 创建短信实现 + * + * @param smartYokeConfig 短信配置 + * @return 短信实现 + */ + @Override + public SmartYokeServiceImpl createSms(SmartYokeConfig smartYokeConfig) { + return new SmartYokeServiceImpl(smartYokeConfig); + } + + /** + * 获取建造者实例 + * + * @return 建造者实例 + */ + public static SmartYokeFactory instance() { + return INSTANCE; + } + + + @Override + public String getSupplier() { + return ""; + } +} diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/yoke/constant/YokeConst.java b/sms4j-provider/src/main/java/org/dromara/sms4j/yoke/constant/YokeConst.java new file mode 100644 index 0000000000000000000000000000000000000000..9f64ac40637aa65766da088ed49f3bab7cf5f57f --- /dev/null +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/yoke/constant/YokeConst.java @@ -0,0 +1,50 @@ +package org.dromara.sms4j.yoke.constant; + + + +/** + * {@code @ClassName} YokeConst + * {@code @Description} TODO + * {@code @Author} 孙浩 + * {@code @Date} 2026/1/13 9:25 + * {@code @Version} 1.0 + */ +public class YokeConst { + public YokeConst() { + } + + /** + * 请求参数字段 + */ + public static final String APPID = "appid"; + public static final String TIMESTAMP = "timestamp"; + public static final String NONCE_STR = "nonce_str"; + public static final String YMD = "yyyyMMddHHmmss"; + + public static final String SIGN = "sign"; + + // 请求体参数字段 + public static final String SOURCE = "source"; + public static final String MOBILE = "mobile"; + public static final String CODE = "code"; + public static final String TEMPLATE_CODE = "templateCode"; + public static final String SIGN_NAME = "signName"; + + + /** + * 短信单次最大发送 手机号 数量 + */ + public static final int MAX_SINGLE_SEND_PHONE_NUM = 50; + + + /** + * 发送成功标识码 + */ + public static final String CODE_100 = "100"; + + + /** + * 返回数据的key + */ + public static final String DATA = "msg"; +} diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/yoke/service/SmartYokeServiceImpl.java b/sms4j-provider/src/main/java/org/dromara/sms4j/yoke/service/SmartYokeServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..04f1fce846ba180ef9f9bb0b047c224ea5bd0c49 --- /dev/null +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/yoke/service/SmartYokeServiceImpl.java @@ -0,0 +1,170 @@ +package org.dromara.sms4j.yoke.service; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.json.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.dromara.sms4j.api.entity.SmsResponse; +import org.dromara.sms4j.comm.constant.Constant; +import org.dromara.sms4j.comm.constant.SupplierConstant; +import org.dromara.sms4j.comm.delayedTime.DelayedTime; +import org.dromara.sms4j.comm.exception.SmsBlendException; +import org.dromara.sms4j.comm.utils.SmsUtils; +import org.dromara.sms4j.provider.service.AbstractSmsBlend; +import org.dromara.sms4j.yoke.config.SmartYokeConfig; +import org.dromara.sms4j.yoke.constant.YokeConst; +import org.dromara.sms4j.yoke.utils.YokeSignUtil; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executor; + +/** + * {@code @ClassName} SmartYokeServiceImpl + * {@code @Description} 油客短信是内部签约来获取每个模板 是由用户向厂商申请拿到templateId,从而发送对应模板短信 + * {@code @Author} 孙浩 + * {@code @Date} 2026/1/12 16:03 + * {@code @Version} 1.0 + */ +@Slf4j +public class SmartYokeServiceImpl extends AbstractSmsBlend { + + int retry = 0; + + + /** + * 构造器,用于构造短信实现模块 + * + * @param config 短信配置 + * @param pool 线程池 + * @author :sunhao + */ + public SmartYokeServiceImpl(SmartYokeConfig config, Executor pool, DelayedTime delayed) { + super(config, pool, delayed); + } + /** + * 构造器,用于构造短信实现模块 + * + * @param config 短信配置 + * @author :sunhao + */ + public SmartYokeServiceImpl(SmartYokeConfig config) { + super(config); + } + + + @Override + public SmsResponse sendMessage(String phone, String message) { + SmartYokeConfig smartYokeConfig = getConfig(); + try { + Map headers = new LinkedHashMap<>(1); + headers.put(Constant.CONTENT_TYPE, Constant.ACCEPT); + headers.put(Constant.ACCEPT_CHARSET, StandardCharsets.UTF_8.displayName()); + String nonceStr = SmsUtils.getRandomString(32); + String timestamp = DateUtil.format(LocalDateTime.now(), YokeConst.YMD); + Map map = new HashMap<>(); + map.put(YokeConst.APPID, smartYokeConfig.getAccessKeyId()); + map.put(YokeConst.TIMESTAMP, timestamp); + map.put(YokeConst.NONCE_STR, nonceStr); + Map bodyMap = new HashMap<>(); + bodyMap.put(YokeConst.SOURCE, smartYokeConfig.getSource()); + bodyMap.put(YokeConst.MOBILE, phone); + bodyMap.put(YokeConst.CODE, message); + if(SmsUtils.isNotEmpty(smartYokeConfig.getTemplateId())){ + bodyMap.put(YokeConst.TEMPLATE_CODE,smartYokeConfig.getTemplateId()); + } + if(SmsUtils.isNotEmpty(smartYokeConfig.getSignature())){ + bodyMap.put(YokeConst.SIGN_NAME, URLEncoder.encode(smartYokeConfig.getSignature(), StandardCharsets.UTF_8.displayName())); + } + map.put(YokeConst.SIGN, YokeSignUtil.getSign(nonceStr, timestamp, smartYokeConfig.getAccessKeyId(), smartYokeConfig.getAccessKeySecret(), bodyMap)); + JSONObject entries = this.http.postJson(String.format(smartYokeConfig.getRequestUrl() + "?%s", YokeSignUtil.sortSign(map)), headers, bodyMap); + SmsResponse smsResponse = this.getResponse(entries); + if (!smsResponse.isSuccess() && this.retry != smartYokeConfig.getMaxRetries()) { + return this.requestRetry(phone, message); + } else { + this.retry = 0; + return smsResponse; + } + } catch (Exception e) { + return this.requestRetry(phone, message); + } + } + + private SmsResponse getResponse(JSONObject entries) { + SmsResponse smsResponse = new SmsResponse(); + smsResponse.setSuccess(entries.containsKey(YokeConst.CODE) && YokeConst.CODE_100.equals(entries.get(YokeConst.CODE))); + smsResponse.setData(entries.get(YokeConst.DATA)); + smsResponse.setConfigId(this.getConfigId()); + return smsResponse; + } + + /** + * 重试发送 + * + * @param phone 手机号 + * @param message 短信内容 + * @return {@link SmsResponse} + * @author :sunhao + */ + private SmsResponse requestRetry(String phone, String message) { + this.http.safeSleep(this.getConfig().getRetryInterval()); + ++this.retry; + log.warn("短信第 {{}} 次重新发送", this.retry); + return this.sendMessage(phone, message); + } + + + + @Override + public SmsResponse sendMessage(String phone, LinkedHashMap messages) { + List list = new ArrayList<>(); + for (Map.Entry entry : messages.entrySet()) { + list.add(entry.getValue()); + } + return this.sendMessage(phone, SmsUtils.listToString(list)); + } + + @Override + public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap messages) { + return this.sendMessage(phone, messages); + } + + @Override + public SmsResponse massTexting(List phones, String message) { + if (phones.size() > YokeConst.MAX_SINGLE_SEND_PHONE_NUM) { + throw new SmsBlendException("单次发送超过最大发送上限,建议每次群发短信人数低于%s", YokeConst.MAX_SINGLE_SEND_PHONE_NUM); + } else { + return this.sendMessage(SmsUtils.listToString(phones), message); + } + } + + @Override + public SmsResponse massTexting(List phones, String templateId, LinkedHashMap messages) { + if (phones.size() > YokeConst.MAX_SINGLE_SEND_PHONE_NUM) { + throw new SmsBlendException("单次发送超过最大发送上限,建议每次群发短信人数低于%s", YokeConst.MAX_SINGLE_SEND_PHONE_NUM); + } else { + List list = new ArrayList<>(); + for (Map.Entry entry : messages.entrySet()) { + list.add(entry.getValue()); + } + return this.sendMessage(SmsUtils.listToString(phones), SmsUtils.listToString(list)); + } + } + + + /** + * 获取供应商名称 + * + * @return 供应商名称 + * @author :sunhao + */ + @Override + public String getSupplier() { + return SupplierConstant.YOKE; + } +} diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/yoke/utils/YokeSignUtil.java b/sms4j-provider/src/main/java/org/dromara/sms4j/yoke/utils/YokeSignUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..0b11b25698acc267ccc37063275442bc349268ea --- /dev/null +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/yoke/utils/YokeSignUtil.java @@ -0,0 +1,80 @@ +package org.dromara.sms4j.yoke.utils; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.digest.DigestUtil; +import org.apache.commons.codec.binary.Hex; +import org.dromara.sms4j.comm.exception.SmsBlendException; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * {@code @ClassName} YokeSignUtil + * {@code @Author} 孙浩 + * {@code @Date} 2026/1/12 16:05 + * {@code @Version} 1.0 + */ +public class YokeSignUtil { + + + /** + * 获取签名 + * + * @param nonceStr 随机字符串 + * @param timestamp 时间戳 + * @param appId appId + * @param signKey 密钥 + * @param bodyMap 参数 + * @return 签名 + * @author :sunhao + */ + public static String getSign(String nonceStr, String timestamp, String appId, String signKey, Map bodyMap) { + try { + Map map = new HashMap<>(); + map.put("appid", appId); + map.put("timestamp", timestamp); + map.put("nonce_str", nonceStr); + map.put("body", com.alibaba.fastjson.JSONObject.toJSONString(bodyMap)); + String sortSigns = sortSign(map) + "&key=" + signKey; + byte[] bytes = DigestUtil.sha256(sortSigns.getBytes()); + return Hex.encodeHexString(bytes).toUpperCase(); + } catch (Exception e) { + throw new SmsBlendException(e.getMessage()); + } + } + + + /** + * 排序参数 + * + * @param map 参数 + * @return 排序后的参数 + * @author :sunhao + */ + public static String sortSign(Map map) { + Set keySet = map.keySet(); + String[] keyArray = keySet.toArray(new String[0]); + Arrays.sort(keyArray); + StringBuilder sb = new StringBuilder(); + for (String k : keyArray) { + sb.append(k).append("=").append(map.get(k)).append("&"); + } + String str = sb.toString(); + if (str.endsWith("&")) { + str = substringBeforeLast(str, "&"); + } + return str; + } + + + public static String substringBeforeLast(String str, String separator) { + if (!StrUtil.isEmpty(str) && !StrUtil.isEmpty(separator)) { + int pos = str.lastIndexOf(separator); + return pos == -1 ? str : str.substring(0, pos); + } else { + return str; + } + } +} diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/zhutong/config/ZhutongFactory.java b/sms4j-provider/src/main/java/org/dromara/sms4j/zhutong/config/ZhutongFactory.java index 154c63c190efee91cdd417c8ae134117cc6eca13..ec63be42507acd26004d6a497523b611588bb601 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/zhutong/config/ZhutongFactory.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/zhutong/config/ZhutongFactory.java @@ -6,6 +6,9 @@ import org.dromara.sms4j.comm.constant.SupplierConstant; import org.dromara.sms4j.provider.factory.AbstractProviderFactory; import org.dromara.sms4j.zhutong.service.ZhutongSmsImpl; +/** + * 助通短信 + * */ @NoArgsConstructor(access = AccessLevel.PRIVATE) public class ZhutongFactory extends AbstractProviderFactory { private static final ZhutongFactory INSTANCE = new ZhutongFactory(); diff --git a/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/config/SmsBlendsInitializer.java b/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/config/SmsBlendsInitializer.java index 983ce80df986667792ec52d970c9dff7191f2dd3..998c9b2fc1ecc03f02a2a84213241fb2253b72bb 100644 --- a/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/config/SmsBlendsInitializer.java +++ b/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/config/SmsBlendsInitializer.java @@ -1,38 +1,15 @@ package org.dromara.sms4j.solon.config; -import cn.hutool.core.util.StrUtil; -import cn.hutool.json.JSONObject; -import cn.hutool.json.JSONUtil; import lombok.extern.slf4j.Slf4j; -import org.dromara.sms4j.aliyun.config.AlibabaFactory; import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.dao.SmsDao; +import org.dromara.sms4j.api.proxy.SmsMethodInterceptor; +import org.dromara.sms4j.api.strategy.IInterceptorStrategy; import org.dromara.sms4j.api.universal.SupplierConfig; -import org.dromara.sms4j.cloopen.config.CloopenFactory; -import org.dromara.sms4j.comm.constant.Constant; -import org.dromara.sms4j.comm.utils.SmsUtils; -import org.dromara.sms4j.core.factory.SmsFactory; -import org.dromara.sms4j.core.proxy.EnvirmentHolder; -import org.dromara.sms4j.core.proxy.SmsProxyFactory; -import org.dromara.sms4j.core.proxy.processor.BlackListProcessor; -import org.dromara.sms4j.core.proxy.processor.BlackListRecordingProcessor; -import org.dromara.sms4j.core.proxy.processor.CoreMethodParamValidateProcessor; -import org.dromara.sms4j.core.proxy.processor.RestrictedProcessor; -import org.dromara.sms4j.core.proxy.processor.SingleBlendRestrictedProcessor; -import org.dromara.sms4j.ctyun.config.CtyunFactory; -import org.dromara.sms4j.dingzhong.config.DingZhongFactory; -import org.dromara.sms4j.emay.config.EmayFactory; -import org.dromara.sms4j.huawei.config.HuaweiFactory; -import org.dromara.sms4j.jdcloud.config.JdCloudFactory; -import org.dromara.sms4j.lianlu.config.LianLuFactory; -import org.dromara.sms4j.netease.config.NeteaseFactory; +import org.dromara.sms4j.core.initalize.AbstractInitalizer; import org.dromara.sms4j.provider.config.SmsConfig; import org.dromara.sms4j.provider.factory.BaseProviderFactory; import org.dromara.sms4j.provider.factory.ProviderFactoryHolder; -import org.dromara.sms4j.solon.holder.SolonSmsDaoHolder; -import org.dromara.sms4j.tencent.config.TencentFactory; -import org.dromara.sms4j.unisms.config.UniFactory; -import org.dromara.sms4j.yunpian.config.YunPianFactory; -import org.dromara.sms4j.zhutong.config.ZhutongFactory; import org.noear.solon.core.AppContext; import java.util.List; @@ -40,78 +17,35 @@ import java.util.Map; @Slf4j -public class SmsBlendsInitializer { - private final List> factoryList; - - private final SmsConfig smsConfig; - private final Map> blends; - private final AppContext context; +public class SmsBlendsInitializer extends AbstractInitalizer { public SmsBlendsInitializer(List> factoryList, SmsConfig smsConfig, Map> blends, AppContext context - ){ - this.factoryList = factoryList; - this.smsConfig = smsConfig; - this.blends = blends; - this.context = context; - onApplicationEvent(); - } - - public void onApplicationEvent() { - this.registerDefaultFactory(); + ) { // 注册短信对象工厂 - ProviderFactoryHolder.registerFactory(factoryList); - //持有初始化配置信息 - EnvirmentHolder.frozenEnvirmet(smsConfig, blends); - //框架依赖持有缓存扩展 - new SolonSmsDaoHolder(context); - //注册执行器实现 - SmsProxyFactory.addProcessor(new RestrictedProcessor()); - SmsProxyFactory.addProcessor(new BlackListProcessor()); - SmsProxyFactory.addProcessor(new BlackListRecordingProcessor()); - SmsProxyFactory.addProcessor(new SingleBlendRestrictedProcessor()); - SmsProxyFactory.addProcessor(new CoreMethodParamValidateProcessor()); - // 解析供应商配置 - for(String configId : blends.keySet()) { - Map configMap = blends.get(configId); - Object supplierObj = configMap.get(Constant.SUPPLIER_KEY); - String supplier = supplierObj == null ? "" : String.valueOf(supplierObj); - supplier = StrUtil.isEmpty(supplier) ? configId : supplier; - BaseProviderFactory providerFactory = (BaseProviderFactory) ProviderFactoryHolder.requireForSupplier(supplier); - if(providerFactory == null) { - log.warn("创建\"{}\"的短信服务失败,未找到供应商为\"{}\"的服务", configId, supplier); - continue; - } - configMap.put("config-id", configId); - SmsUtils.replaceKeysSeperator(configMap, "-", "_"); - JSONObject configJson = new JSONObject(configMap); - SupplierConfig supplierConfig = JSONUtil.toBean(configJson, providerFactory.getConfigClass()); - SmsFactory.createSmsBlend(supplierConfig); - } + this.registerDefaultFactory(); - } + //注册缓存实现 + doRegisterSmsDao(context.getBean(SmsDao.class)); - /** - * 注册默认工厂实例 - */ - private void registerDefaultFactory() { - ProviderFactoryHolder.registerFactory(AlibabaFactory.instance()); - ProviderFactoryHolder.registerFactory(CloopenFactory.instance()); - ProviderFactoryHolder.registerFactory(CtyunFactory.instance()); - ProviderFactoryHolder.registerFactory(EmayFactory.instance()); - ProviderFactoryHolder.registerFactory(HuaweiFactory.instance()); - ProviderFactoryHolder.registerFactory(NeteaseFactory.instance()); - ProviderFactoryHolder.registerFactory(TencentFactory.instance()); - ProviderFactoryHolder.registerFactory(UniFactory.instance()); - ProviderFactoryHolder.registerFactory(YunPianFactory.instance()); - ProviderFactoryHolder.registerFactory(ZhutongFactory.instance()); - ProviderFactoryHolder.registerFactory(LianLuFactory.instance()); - ProviderFactoryHolder.registerFactory(DingZhongFactory.instance()); - if(SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) { - ProviderFactoryHolder.registerFactory(JdCloudFactory.instance()); + //注册拦截器 + List smsMethodInterceptors = context.getBeansOfType(SmsMethodInterceptor.class); + for (SmsMethodInterceptor smsMethodInterceptor : smsMethodInterceptors) { + doRegisterSmsMethodInterceptor(smsMethodInterceptor); + } + + //注册拦截器策略 + List interceptorStrategies = context.getBeansOfType(IInterceptorStrategy.class); + for (IInterceptorStrategy interceptorStrategy : interceptorStrategies) { + doRegisterIInterceptorStrategy(interceptorStrategy); } - } + //装在拦截器和拦截器策略 + initInterceptor(blends, smsConfig); + + // 解析供应商配置 + doParseChannelConfigWithCreate(blends); + } } diff --git a/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/holder/SolonSmsDaoHolder.java b/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/holder/SolonSmsDaoHolder.java deleted file mode 100644 index cef3c8750b310bad028e04661d4313a0d6f34aaa..0000000000000000000000000000000000000000 --- a/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/holder/SolonSmsDaoHolder.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.dromara.sms4j.solon.holder; - -import org.dromara.sms4j.api.dao.SmsDao; -import org.dromara.sms4j.api.dao.SmsDaoDefaultImpl; -import org.dromara.sms4j.comm.utils.SmsUtils; -import org.noear.solon.core.AppContext; - -public class SolonSmsDaoHolder{ - - private static SmsDao smsDao; - - public SolonSmsDaoHolder(AppContext context) { - context.getBeanAsync(SmsDao.class, bean -> smsDao = bean); - } - - public static SmsDao getSmsDao() { - if (SmsUtils.isEmpty(smsDao)){ - smsDao = SmsDaoDefaultImpl.getInstance(); - } - return smsDao; - } -} diff --git a/sms4j-spring-boot-example/src/main/java/org/dromara/sms4j/example/Sms4jApplication.java b/sms4j-spring-boot-example/src/main/java/org/dromara/sms4j/example/Sms4jApplication.java index 4946f8c54251f16f703adab3836ced3aa333239e..1b627bc4cd22648d65a0087d2f7e57185a17f330 100644 --- a/sms4j-spring-boot-example/src/main/java/org/dromara/sms4j/example/Sms4jApplication.java +++ b/sms4j-spring-boot-example/src/main/java/org/dromara/sms4j/example/Sms4jApplication.java @@ -1,8 +1,14 @@ package org.dromara.sms4j.example; +import org.dromara.sms4j.api.entity.SmsResponse; +import org.dromara.sms4j.comm.constant.SupplierConstant; +import org.dromara.sms4j.core.factory.SmsFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import java.util.ArrayList; +import java.util.LinkedHashMap; + /** * 主类 * diff --git a/sms4j-spring-boot-example/src/test/java/org/dromara/sms4j/example/SmsProcessorTest.java b/sms4j-spring-boot-example/src/test/java/org/dromara/sms4j/example/SmsMethodInterceptorTest.java similarity index 57% rename from sms4j-spring-boot-example/src/test/java/org/dromara/sms4j/example/SmsProcessorTest.java rename to sms4j-spring-boot-example/src/test/java/org/dromara/sms4j/example/SmsMethodInterceptorTest.java index 4c94d4ae8757d08ba5018886ebef00163278dbc5..829b7690add645652611e37f9cf062d0e7550546 100644 --- a/sms4j-spring-boot-example/src/test/java/org/dromara/sms4j/example/SmsProcessorTest.java +++ b/sms4j-spring-boot-example/src/test/java/org/dromara/sms4j/example/SmsMethodInterceptorTest.java @@ -8,6 +8,7 @@ import org.dromara.sms4j.comm.constant.SupplierConstant; import org.dromara.sms4j.comm.exception.SmsBlendException; import org.dromara.sms4j.comm.utils.SmsUtils; import org.dromara.sms4j.core.factory.SmsFactory; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; @@ -20,7 +21,7 @@ import java.util.LinkedHashMap; */ @Slf4j @SpringBootTest -public class SmsProcessorTest { +public class SmsMethodInterceptorTest { /** * 填测试手机号 */ @@ -31,7 +32,7 @@ public class SmsProcessorTest { @Test public void test1() { System.out.println("------------"); - SmsBlend smsBlend = SmsFactory.getBySupplier(SupplierConstant.UNISMS); + SmsBlend smsBlend = SmsFactory.getBySupplier(SupplierConstant.LOCAL); SmsResponse smsResponse = smsBlend.sendMessage(PHONE, SmsUtils.getRandomInt(6)); Assert.isTrue(smsResponse.isSuccess()); System.out.println(smsResponse.getData()); @@ -44,7 +45,7 @@ public class SmsProcessorTest { public void test2() { System.out.println("------------"); - SmsBlend smsBlend = SmsFactory.getBySupplier(SupplierConstant.HUAWEI); + SmsBlend smsBlend = SmsFactory.getBySupplier(SupplierConstant.LOCAL); SmsResponse smsResponse = smsBlend.sendMessage(PHONE1, SmsUtils.getRandomInt(6)); Assert.isTrue(smsResponse.isSuccess()); System.out.println(smsResponse.getData()); @@ -56,62 +57,28 @@ public class SmsProcessorTest { public void test3() { System.out.println("------------"); - SmsBlendException knowEx = null; - try { - SmsFactory.getBySupplier(SupplierConstant.UNISMS).sendMessage(PHONE, new LinkedHashMap<>()); - } catch (SmsBlendException e) { - knowEx = e; - System.out.println(knowEx.getMessage()); - } - Assert.notNull(knowEx); - knowEx = null; - try { - SmsFactory.getBySupplier(SupplierConstant.UNISMS).sendMessage("", SmsUtils.getRandomInt(6)); - } catch (SmsBlendException e) { - knowEx = e; - System.out.println(knowEx.getMessage()); - } - Assert.notNull(knowEx); - knowEx = null; - try { - SmsFactory.getBySupplier(SupplierConstant.UNISMS).sendMessage(PHONE, ""); - } catch (SmsBlendException e) { - knowEx = e; - System.out.println(knowEx.getMessage()); - } - Assert.notNull(knowEx); - knowEx = null; - try { - SmsFactory.getBySupplier(SupplierConstant.UNISMS).sendMessage(PHONE, "111", new LinkedHashMap<>()); - } catch (SmsBlendException e) { - knowEx = e; - System.out.println(knowEx.getMessage()); - } - Assert.notNull(knowEx); - knowEx = null; - try { - SmsFactory.getBySupplier(SupplierConstant.UNISMS).massTexting(Collections.singletonList(PHONE), ""); - } catch (SmsBlendException e) { - knowEx = e; - System.out.println(knowEx.getMessage()); - } - Assert.notNull(knowEx); - knowEx = null; - try { - SmsFactory.getBySupplier(SupplierConstant.UNISMS).massTexting(Collections.singletonList(PHONE), "2222", new LinkedHashMap<>()); - } catch (SmsBlendException e) { - knowEx = e; - System.out.println(knowEx.getMessage()); - } - Assert.notNull(knowEx); - knowEx = null; - try { - SmsFactory.getBySupplier(SupplierConstant.UNISMS).massTexting(new ArrayList<>(), "321321"); - } catch (SmsBlendException e) { - knowEx = e; - System.out.println(knowEx.getMessage()); - } - Assert.notNull(knowEx); + SmsBlend sb = SmsFactory.getBySupplier(SupplierConstant.LOCAL); + Assertions.assertThrows(SmsBlendException.class, + () -> sb.sendMessage(PHONE, new LinkedHashMap<>()) + ); + Assertions.assertThrows(SmsBlendException.class, + () -> sb.sendMessage("", SmsUtils.getRandomInt(6)) + ); + Assertions.assertThrows(SmsBlendException.class, + () -> sb.sendMessage(PHONE, "") + ); + Assertions.assertThrows(SmsBlendException.class, + () -> sb.sendMessage(PHONE, "111", new LinkedHashMap<>()) + ); + Assertions.assertThrows(SmsBlendException.class, + () -> sb.massTexting(Collections.singletonList(PHONE), "") + ); + Assertions.assertThrows(SmsBlendException.class, + () -> sb.massTexting(Collections.singletonList(PHONE), "2222", new LinkedHashMap<>()) + ); + Assertions.assertThrows(SmsBlendException.class, + () -> sb.massTexting(new ArrayList<>(), "321321") + ); } //黑名单测试 @@ -119,7 +86,7 @@ public class SmsProcessorTest { public void test4() { System.out.println("------------"); - SmsBlend smsBlend = SmsFactory.getBySupplier(SupplierConstant.UNISMS); + SmsBlend smsBlend = SmsFactory.getBySupplier(SupplierConstant.LOCAL); //单黑名单添加 smsBlend.joinInBlacklist(PHONE); SmsBlendException knowEx = null; @@ -155,17 +122,10 @@ public class SmsProcessorTest { @Test public void test5() { System.out.println("------------"); - - SmsResponse smsResponse = SmsFactory.getBySupplier(SupplierConstant.UNISMS).sendMessage(PHONE, SmsUtils.getRandomInt(6)); + SmsBlend sb = SmsFactory.getBySupplier(SupplierConstant.LOCAL); + SmsResponse smsResponse = sb.sendMessage(PHONE, SmsUtils.getRandomInt(6)); Assert.isTrue(smsResponse.isSuccess()); - SmsBlendException knowEx = null; - try { - SmsFactory.getBySupplier(SupplierConstant.UNISMS).sendMessage(PHONE, SmsUtils.getRandomInt(6)); - } catch (SmsBlendException e) { - knowEx = e; - System.out.println(knowEx.getMessage()); - } - Assert.notNull(knowEx); + Assertions.assertThrows(SmsBlendException.class, () -> sb.sendMessage(PHONE, SmsUtils.getRandomInt(6))); } //渠道级上限测试、需成功发送6笔,再发就会报错 参数配置 6 @@ -173,12 +133,13 @@ public class SmsProcessorTest { public void test6() { System.out.println("------------"); - SmsResponse smsResponse = SmsFactory.getBySupplier(SupplierConstant.UNISMS).sendMessage(PHONE1, SmsUtils.getRandomInt(6)); + SmsResponse smsResponse = SmsFactory.getBySupplier(SupplierConstant.LOCAL) + .sendMessage(PHONE1, SmsUtils.getRandomInt(6)); Assert.isTrue(smsResponse.isSuccess()); SmsBlendException knowEx = null; try { - SmsFactory.getBySupplier(SupplierConstant.UNISMS).sendMessage(PHONE1, SmsUtils.getRandomInt(6)); + SmsFactory.getBySupplier(SupplierConstant.LOCAL).sendMessage(PHONE1, SmsUtils.getRandomInt(6)); } catch (SmsBlendException e) { knowEx = e; System.out.println(knowEx.getMessage()); diff --git a/sms4j-spring-boot-example/src/test/java/org/dromara/sms4j/example/YokeTest.java b/sms4j-spring-boot-example/src/test/java/org/dromara/sms4j/example/YokeTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c1d097485c02b203defc06b001753b5045516ee1 --- /dev/null +++ b/sms4j-spring-boot-example/src/test/java/org/dromara/sms4j/example/YokeTest.java @@ -0,0 +1,35 @@ +package org.dromara.sms4j.example; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.entity.SmsResponse; +import org.dromara.sms4j.yoke.config.SmartYokeConfig; +import org.dromara.sms4j.yoke.config.SmartYokeFactory; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +/** + * {@code @ClassName} YokeTest + * {@code @Description} TODO + * {@code @Author} 孙浩 + * {@code @Date} 2026/1/13 10:07 + * {@code @Version} 1.0 + */ +@Slf4j +@SpringBootTest +public class YokeTest { + + + @Test + public void testSendYokeSms() { + SmartYokeConfig smartYokeConfig = new SmartYokeConfig(); + smartYokeConfig.setAccessKeyId("6511516541615saw"); + smartYokeConfig.setAccessKeySecret("wqsqwsqw"); + smartYokeConfig.setTemplateId("sqwsq"); + smartYokeConfig.setSignature("sqsq"); + SmartYokeFactory instance = SmartYokeFactory.instance(); + SmsResponse smsResponse = instance.createSms(smartYokeConfig).sendMessage("18317890354", "649651"); + log.info("发送结果:{}", smsResponse); + } + +} diff --git a/sms4j-spring-boot-starter/src/main/java/org/dromara/sms4j/starter/adepter/ConfigCombineMapAdeptor.java b/sms4j-spring-boot-starter/src/main/java/org/dromara/sms4j/starter/adepter/ConfigCombineMapAdeptor.java index 34bdf581890e946cdc0ac934366a847e69738409..d7bd4b227a9e9f9eed9447bd7823fef09c114f12 100644 --- a/sms4j-spring-boot-starter/src/main/java/org/dromara/sms4j/starter/adepter/ConfigCombineMapAdeptor.java +++ b/sms4j-spring-boot-starter/src/main/java/org/dromara/sms4j/starter/adepter/ConfigCombineMapAdeptor.java @@ -1,6 +1,8 @@ package org.dromara.sms4j.starter.adepter; import cn.hutool.core.bean.BeanUtil; +import org.dromara.sms4j.core.datainterface.SmsBlendsBeanConfig; +import org.dromara.sms4j.core.datainterface.SmsBlendsSelectedConfig; import org.dromara.sms4j.core.datainterface.SmsReadConfig; import org.dromara.sms4j.provider.config.BaseConfig; @@ -10,6 +12,12 @@ import java.util.List; import java.util.Map; import java.util.Set; +/** + * ConfigCombineMapAdeptor + *

继承HashMap,相当于代理了get方法,再get时如果没有取到指定key的value,那么遍历map的特殊value对象再比对对象的属性和指定key是否一致,一致则把对象转换为原返回类型的信息 + * @author :Sh1yu + * 2023/8/1 12:06 + **/ public class ConfigCombineMapAdeptor extends HashMap { @Override public M get(Object key) { @@ -19,14 +27,18 @@ public class ConfigCombineMapAdeptor extends HashMap { for (Object insideMapKey : configKeySet) { if (((String)insideMapKey).startsWith(SmsReadConfig.class.getSimpleName())){ Map smsBlendsConfigInsideMap = (Map) this.get(insideMapKey); - SmsReadConfig config = (SmsReadConfig) smsBlendsConfigInsideMap.get(insideMapKey); - BaseConfig supplierConfig = config.getSupplierConfig((String)key); - List supplierConfigList = config.getSupplierConfigList(); - if (null == supplierConfigList){ - supplierConfigList = new ArrayList<>(); + Object config = smsBlendsConfigInsideMap.get(insideMapKey); + List supplierConfigList = new ArrayList<>(); + if (config instanceof SmsBlendsBeanConfig){ + SmsBlendsBeanConfig beanConfig = (SmsBlendsBeanConfig)config; + supplierConfigList = beanConfig.getSupplierConfigList(); } - if (null != supplierConfig){ - supplierConfigList.add(supplierConfig); + if (config instanceof SmsBlendsSelectedConfig){ + SmsBlendsSelectedConfig selectedConfig = (SmsBlendsSelectedConfig)config; + BaseConfig supplierConfig = selectedConfig.getSupplierConfig((String)key); + if (null != supplierConfig){ + supplierConfigList.add(supplierConfig); + } } for (BaseConfig baseConfig : supplierConfigList) { if (key.equals(baseConfig.getConfigId())){ @@ -41,6 +53,4 @@ public class ConfigCombineMapAdeptor extends HashMap { } return (M)o; } - - } diff --git a/sms4j-spring-boot-starter/src/main/java/org/dromara/sms4j/starter/config/SmsBlendsInitializer.java b/sms4j-spring-boot-starter/src/main/java/org/dromara/sms4j/starter/config/SmsBlendsInitializer.java index f784546a700c454219632602b3c82e9e9026e090..9e4a61e2f4b3a20df9b450accf937dfdea2eae2e 100644 --- a/sms4j-spring-boot-starter/src/main/java/org/dromara/sms4j/starter/config/SmsBlendsInitializer.java +++ b/sms4j-spring-boot-starter/src/main/java/org/dromara/sms4j/starter/config/SmsBlendsInitializer.java @@ -1,41 +1,22 @@ package org.dromara.sms4j.starter.config; -import cn.hutool.core.util.StrUtil; -import cn.hutool.json.JSONObject; -import cn.hutool.json.JSONUtil; import lombok.extern.slf4j.Slf4j; -import org.dromara.sms4j.aliyun.config.AlibabaFactory; import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.dao.SmsDao; +import org.dromara.sms4j.api.proxy.SmsMethodInterceptor; +import org.dromara.sms4j.api.strategy.IInterceptorStrategy; import org.dromara.sms4j.api.universal.SupplierConfig; -import org.dromara.sms4j.cloopen.config.CloopenFactory; -import org.dromara.sms4j.comm.constant.Constant; import org.dromara.sms4j.comm.enumerate.ConfigType; -import org.dromara.sms4j.comm.utils.SmsUtils; +import org.dromara.sms4j.core.datainterface.SmsBlendsBeanConfig; +import org.dromara.sms4j.core.datainterface.SmsBlendsSelectedConfig; import org.dromara.sms4j.core.datainterface.SmsReadConfig; import org.dromara.sms4j.core.factory.SmsFactory; -import org.dromara.sms4j.core.proxy.EnvirmentHolder; -import org.dromara.sms4j.core.proxy.SmsProxyFactory; -import org.dromara.sms4j.core.proxy.processor.BlackListProcessor; -import org.dromara.sms4j.core.proxy.processor.BlackListRecordingProcessor; -import org.dromara.sms4j.core.proxy.processor.CoreMethodParamValidateProcessor; -import org.dromara.sms4j.core.proxy.processor.RestrictedProcessor; -import org.dromara.sms4j.core.proxy.processor.SingleBlendRestrictedProcessor; -import org.dromara.sms4j.ctyun.config.CtyunFactory; -import org.dromara.sms4j.dingzhong.config.DingZhongFactory; -import org.dromara.sms4j.emay.config.EmayFactory; -import org.dromara.sms4j.huawei.config.HuaweiFactory; -import org.dromara.sms4j.jdcloud.config.JdCloudFactory; -import org.dromara.sms4j.lianlu.config.LianLuFactory; -import org.dromara.sms4j.netease.config.NeteaseFactory; +import org.dromara.sms4j.core.initalize.AbstractInitalizer; import org.dromara.sms4j.provider.config.SmsConfig; import org.dromara.sms4j.provider.factory.BaseProviderFactory; import org.dromara.sms4j.provider.factory.ProviderFactoryHolder; -import org.dromara.sms4j.qiniu.config.QiNiuFactory; import org.dromara.sms4j.starter.adepter.ConfigCombineMapAdeptor; -import org.dromara.sms4j.tencent.config.TencentFactory; -import org.dromara.sms4j.unisms.config.UniFactory; -import org.dromara.sms4j.yunpian.config.YunPianFactory; -import org.dromara.sms4j.zhutong.config.ZhutongFactory; +import org.dromara.sms4j.starter.container.SmsConfigContainer; import org.springframework.beans.factory.ObjectProvider; import java.util.HashMap; @@ -44,91 +25,95 @@ import java.util.Map; @Slf4j -public class SmsBlendsInitializer { - private final List> factoryList; +public class SmsBlendsInitializer extends AbstractInitalizer { - private final SmsConfig smsConfig; - private final Map> blends; - private final ObjectProvider extendsSmsConfigs; public SmsBlendsInitializer(List> factoryList, SmsConfig smsConfig, Map> blends, - ObjectProvider extendsSmsConfigs){ - this.factoryList = factoryList; - this.smsConfig = smsConfig; - this.blends = blends; - this.extendsSmsConfigs = extendsSmsConfigs; - onApplicationEvent(); + SmsConfigContainer configContainer) { + initializeFactories(factoryList); + registerConfigurations(configContainer); + processConfigurationByType(smsConfig, blends, configContainer); } - public void onApplicationEvent() { + + + /** + * 初始化工厂 + */ + private void initializeFactories(List> factoryList) { this.registerDefaultFactory(); - // 注册短信对象工厂 ProviderFactoryHolder.registerFactory(factoryList); + } - if(ConfigType.YAML.equals(this.smsConfig.getConfigType())) { - //持有初始化配置信息 - Map> blendsInclude = new ConfigCombineMapAdeptor>(); - blendsInclude.putAll(this.blends); - int num = 0; - for (SmsReadConfig smsReadConfig : extendsSmsConfigs) { - String key = SmsReadConfig.class.getSimpleName() + num; - Map insideMap = new HashMap<>(); - insideMap.put(key,smsReadConfig); - blendsInclude.put(key,insideMap); - num++; - } - EnvirmentHolder.frozenEnvirmet(smsConfig, blendsInclude); - //注册执行器实现 - SmsProxyFactory.addProcessor(new RestrictedProcessor()); - SmsProxyFactory.addProcessor(new BlackListProcessor()); - SmsProxyFactory.addProcessor(new BlackListRecordingProcessor()); - SmsProxyFactory.addProcessor(new SingleBlendRestrictedProcessor()); - SmsProxyFactory.addProcessor(new CoreMethodParamValidateProcessor()); - // 解析供应商配置 - for(String configId : blends.keySet()) { - Map configMap = blends.get(configId); - Object supplierObj = configMap.get(Constant.SUPPLIER_KEY); - String supplier = supplierObj == null ? "" : String.valueOf(supplierObj); - supplier = StrUtil.isEmpty(supplier) ? configId : supplier; - BaseProviderFactory providerFactory = (BaseProviderFactory) ProviderFactoryHolder.requireForSupplier(supplier); - if(providerFactory == null) { - log.warn("创建\"{}\"的短信服务失败,未找到供应商为\"{}\"的服务", configId, supplier); - continue; - } - configMap.put("config-id", configId); - SmsUtils.replaceKeysSeperator(configMap, "-", "_"); - JSONObject configJson = new JSONObject(configMap); - org.dromara.sms4j.api.universal.SupplierConfig supplierConfig = JSONUtil.toBean(configJson, providerFactory.getConfigClass()); - SmsFactory.createSmsBlend(supplierConfig); - } - } + /** + * 注册配置 + */ + private void registerConfigurations(SmsConfigContainer configContainer) { + doRegisterSmsDao(configContainer.getSmsDaos().getIfAvailable()); + configContainer.getMethodInterceptors().forEach(this::doRegisterSmsMethodInterceptor); + configContainer.getInterceptorStrategies().forEach(this::doRegisterIInterceptorStrategy); + } + /** + * 初始化拦截器 + */ + private void processConfigurationByType(SmsConfig smsConfig, Map> blends, + SmsConfigContainer configContainer) { + switch (smsConfig.getConfigType()) { + case YAML: + initInterceptor(blends, smsConfig); + doParseChannelConfigWithCreate(blends); + break; + case INTERFACE: + processInterfaceConfiguration(smsConfig, blends, configContainer); + break; + } } /** - * 注册默认工厂实例 + * 初始化拦截器 */ - private void registerDefaultFactory() { - ProviderFactoryHolder.registerFactory(AlibabaFactory.instance()); - ProviderFactoryHolder.registerFactory(CloopenFactory.instance()); - ProviderFactoryHolder.registerFactory(CtyunFactory.instance()); - ProviderFactoryHolder.registerFactory(EmayFactory.instance()); - ProviderFactoryHolder.registerFactory(HuaweiFactory.instance()); - ProviderFactoryHolder.registerFactory(NeteaseFactory.instance()); - ProviderFactoryHolder.registerFactory(TencentFactory.instance()); - ProviderFactoryHolder.registerFactory(UniFactory.instance()); - ProviderFactoryHolder.registerFactory(YunPianFactory.instance()); - ProviderFactoryHolder.registerFactory(ZhutongFactory.instance()); - ProviderFactoryHolder.registerFactory(LianLuFactory.instance()); - ProviderFactoryHolder.registerFactory(DingZhongFactory.instance()); - ProviderFactoryHolder.registerFactory(QiNiuFactory.instance()); - if(SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) { - ProviderFactoryHolder.registerFactory(JdCloudFactory.instance()); + private void processInterfaceConfiguration(SmsConfig smsConfig, Map> blends, + SmsConfigContainer configContainer) { + Map> blendsInclude = createBlendsWithConfigs(blends, configContainer); + initInterceptor(blendsInclude, smsConfig); + + for (SmsBlendsBeanConfig beanConfig : configContainer.getBeanConfigs()) { + SmsFactory.createSmsBlend(beanConfig); } - log.debug("加载内置运营商完成!"); } + /** + * 创建配置并添加到拦截器中 + */ + private Map> createBlendsWithConfigs(Map> originalBlends, + SmsConfigContainer configContainer) { + Map> blendsInclude = new ConfigCombineMapAdeptor<>(); + blendsInclude.putAll(originalBlends); + + int num = 0; + num = addConfigToBlends(blendsInclude, configContainer.getBeanConfigs(), num); + addConfigToBlends(blendsInclude, configContainer.getSelectedConfigs(), num); + + return blendsInclude; + } + + /** + * 添加配置到拦截器中 + */ + private int addConfigToBlends(Map> blendsInclude, + ObjectProvider configProvider, int startIndex) { + int num = startIndex; + for (T config : configProvider) { + String key = SmsReadConfig.class.getSimpleName() + num; + Map insideMap = new HashMap<>(); + insideMap.put(key, config); + blendsInclude.put(key, insideMap); + num++; + } + return num; + } } diff --git a/sms4j-spring-boot-starter/src/main/java/org/dromara/sms4j/starter/config/SupplierConfig.java b/sms4j-spring-boot-starter/src/main/java/org/dromara/sms4j/starter/config/SupplierConfig.java index 14722f0d428fbda6dba5a07a46ea4772b35b17fc..469343595441c709ee4e60821f3cf4741c3147a7 100644 --- a/sms4j-spring-boot-starter/src/main/java/org/dromara/sms4j/starter/config/SupplierConfig.java +++ b/sms4j-spring-boot-starter/src/main/java/org/dromara/sms4j/starter/config/SupplierConfig.java @@ -3,12 +3,18 @@ package org.dromara.sms4j.starter.config; import cn.hutool.core.util.ObjectUtil; import lombok.SneakyThrows; import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.dao.SmsDao; +import org.dromara.sms4j.api.proxy.SmsMethodInterceptor; +import org.dromara.sms4j.api.strategy.IInterceptorStrategy; import org.dromara.sms4j.comm.constant.Constant; import org.dromara.sms4j.comm.enumerate.ConfigType; -import org.dromara.sms4j.core.datainterface.SmsReadConfig; +import org.dromara.sms4j.core.datainterface.SmsBlendsBeanConfig; +import org.dromara.sms4j.core.datainterface.SmsBlendsSelectedConfig; import org.dromara.sms4j.provider.config.SmsConfig; import org.dromara.sms4j.provider.factory.BaseProviderFactory; +import org.dromara.sms4j.starter.container.SmsConfigContainer; import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -34,7 +40,7 @@ public class SupplierConfig { @Bean @ConditionalOnBean({SmsConfig.class}) @SneakyThrows - protected List> factoryList(Map> blends, SmsConfig smsConfig) { + protected List> factoryList(@Qualifier("blends") Map> blends, SmsConfig smsConfig) { //注入自定义实现工厂 List> factoryList = new ArrayList<>(); if (ConfigType.YAML.equals(smsConfig.getConfigType())) { @@ -55,9 +61,20 @@ public class SupplierConfig { @Bean protected SmsBlendsInitializer smsBlendsInitializer(List> factoryList, SmsConfig smsConfig, - Map> blends, - ObjectProvider extendsSmsConfigs) { - return new SmsBlendsInitializer(factoryList, smsConfig, blends, extendsSmsConfigs); + @Qualifier("blends") Map> blends, + ObjectProvider smsDaos, + ObjectProvider beanConfigs, + ObjectProvider selectedConfigs, + ObjectProvider smsMethodInterceptors, + ObjectProvider interceptorStrategies){ + SmsConfigContainer configContainer = SmsConfigContainer.builder() + .beanConfigs(beanConfigs) + .smsDaos(smsDaos) + .selectedConfigs(selectedConfigs) + .interceptorStrategies(interceptorStrategies) + .methodInterceptors(smsMethodInterceptors) + .build(); + return new SmsBlendsInitializer(factoryList, smsConfig, blends,configContainer); } } diff --git a/sms4j-spring-boot-starter/src/main/java/org/dromara/sms4j/starter/container/SmsConfigContainer.java b/sms4j-spring-boot-starter/src/main/java/org/dromara/sms4j/starter/container/SmsConfigContainer.java new file mode 100644 index 0000000000000000000000000000000000000000..1b6bd109339149f78ada747ff55daa7790e46ad2 --- /dev/null +++ b/sms4j-spring-boot-starter/src/main/java/org/dromara/sms4j/starter/container/SmsConfigContainer.java @@ -0,0 +1,28 @@ +package org.dromara.sms4j.starter.container; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import org.dromara.sms4j.api.dao.SmsDao; +import org.dromara.sms4j.api.proxy.SmsMethodInterceptor; +import org.dromara.sms4j.api.strategy.IInterceptorStrategy; +import org.dromara.sms4j.core.datainterface.SmsBlendsBeanConfig; +import org.dromara.sms4j.core.datainterface.SmsBlendsSelectedConfig; +import org.springframework.beans.factory.ObjectProvider; + +/** + * {@code @ClassName} SmsConfigContainer + * {@code @Author} 孙浩 + * {@code @Date} 2026/1/12 15:15 + * {@code @Version} 1.0 + */ +@Builder +@AllArgsConstructor +@Data +public class SmsConfigContainer { + private final ObjectProvider smsDaos; + private final ObjectProvider beanConfigs; + private final ObjectProvider selectedConfigs; + private final ObjectProvider methodInterceptors; + private final ObjectProvider interceptorStrategies; +} diff --git a/sms4j-spring-boot-starter/src/main/java/org/dromara/sms4j/starter/holder/SpringSmsDaoHolder.java b/sms4j-spring-boot-starter/src/main/java/org/dromara/sms4j/starter/holder/SpringSmsDaoHolder.java deleted file mode 100644 index 3ee1cf94915f6ec203e0c8e83f12fb06aeec0ba8..0000000000000000000000000000000000000000 --- a/sms4j-spring-boot-starter/src/main/java/org/dromara/sms4j/starter/holder/SpringSmsDaoHolder.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.dromara.sms4j.starter.holder; - -import org.dromara.sms4j.api.dao.SmsDao; -import org.dromara.sms4j.starter.utils.SmsSpringUtils; - -public class SpringSmsDaoHolder { - public static SmsDao getSmsDao() { - return SmsSpringUtils.getApplicationContext().getBean(SmsDao.class); - } -}