Merge pull request !3 from 风如歌/master
This commit is contained in:
风如歌 2023-03-29 07:50:10 +00:00 committed by Gitee
commit 445db7ebae
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
47 changed files with 1100 additions and 18014 deletions

View File

@ -1,13 +1,14 @@
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">sms-aggregation v1.0.0</h1>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">sms-aggregation v1.0.2</h1>
<h2 align="center" style="margin: 30px 0 30px; font-weight: bold;">短信聚合工具</h2>
<h4 align="center" style="margin: 30px 0 30px; font-weight: bold;">让发送短信变更简单</h4>
<h4 align="center" style="margin: 30px 0 30px; font-weight: bold;">让发送短信变更简单</h4>
<p align="center">
<a href="https://gitee.com/the-wind-is-like-a-song/sms_aggregation/stargazers"><img src="https://gitee.com/the-wind-is-like-a-song/sms_aggregation/badge/star.svg?theme=gvp"></a>
<a href="https://gitee.com/the-wind-is-like-a-song/sms_aggregation/master/LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-green"></a>
<a href="https://gitee.com/the-wind-is-like-a-song/sms_aggregation"><img src="https://img.shields.io/badge/version-v1.0.0-blue"></a>
<a href="https://gitee.com/the-wind-is-like-a-song/sms_aggregation"><img src="https://img.shields.io/badge/version-v1.0.2-blue"></a>
</p>
## 前言
在日常的开发过程中,短信的发送经常使用(尤其是中小型的外包公司),毕竟不是每个公司都有阿里腾讯一样的实力,
也不是每个都像银行联通等公司一样有内部的短信规程。第三方的短信往往是最常见的解决方案,但是市面上第三方短信服务商众多,
各家都有不同的方式和标准,每次需要使用时候,都需要花费时间去阅读文档和编写相应的工具,为一个短信浪费了太多的精力和时间。
@ -16,40 +17,46 @@
[gitee](https://gitee.com/the-wind-is-like-a-song/sms_aggregation)
[github](https://github.com/fengruge/sms_aggregation)
#### [在线文档](https://apidoc.gitee.com/the-wind-is-like-a-song/sms_aggregation)
#### [官方文档](http://wind.kim)
#### [JavaDoc文档](https://apidoc.gitee.com/the-wind-is-like-a-song/sms_aggregation)
## 支持厂商一览
目前刚刚发布第一版本,支持尚少,后续会集成更多的厂商
- **阿里云国内短信**
- **腾讯云国内短信**
- **合一短信**
- **云片短信**
## 在SpringBoot环境集成
1. maven引入
```xml
<dependency>
```xml
<dependency>
<groupId>kim.wind</groupId>
<artifactId>sms-aggregation-spring-boot-starter</artifactId>
<version> version </version>
</dependency>
```
</dependency>
```
2. 设置配置文件
```yaml
sms:
# 短信服务商
supplier: alibaba
# 是否开启短信发送限制 默认false
restricted: true
# 以下设置仅在开启短信发送限制后生效
# 是否使用redis进行缓存 默认false
redisCache: true
# 单账号每日最大发送量
accountMax: 20
# 单账号每分钟最大发送
minuteMax: 2
```
```yaml
sms:
# 短信服务商
supplier: alibaba
# 是否开启短信发送限制 默认false
restricted: true
# 以下设置仅在开启短信发送限制后生效
# 是否使用redis进行缓存 默认false
redisCache: true
# 单账号每日最大发送量
accountMax: 20
# 单账号每分钟最大发送
minuteMax: 2
```
阿里云配置示意
```yaml
sms:
@ -69,9 +76,11 @@ sms:
#请求地址 默认为dysmsapi.aliyuncs.com 如无特殊改变可以不用设置
requestUrl: dysmsapi.aliyuncs.com
```
3. 方法使用
```java
public class Demo{
```java
public class Demo{
//此处作为演示使用推荐使用构造注入或set注入
@Autowired
private final SmsBlend sms;
@ -81,13 +90,43 @@ public class Demo{
SmsResponse smsResponse = sms.sendMessage("18888888888","测试固定模板短信");
System.out.println(smsResponse);
}
}
```
}
## 配置详解
#### 线程池配置
每一家厂商都对于异步短信有不同的支持,有些甚至没有,为了统一存在一个异步短信,我们配置了一个线程池用于执行异步短信任务,线程池默认配置如下:
```yaml
sms:
#核心线程池大小
corePoolSize: 10
#最大线程数
maxPoolSize: 30
#队列容量
queueCapacity: 50
#活跃时间
keepAliveSeconds: 60
# 线程名字前缀
threadNamePrefix: sms-executor-
#设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean
shutdownStrategy: true
```
以上线程池为默认的配置如果有需要可以跟随自己的需求在yml文件进行配置
```
## 参与贡献
1. Fork 本仓库
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request
4. 新建 Pull Request 到 dev分支
```
### 分支介绍
1. master 正式版分支最终发布到maven中央仓库的版本
2. dev 开发分支贡献的代码将合并到这里无误后合并至preview
3. preview 预览版分支,新的版本和测试性功能将在这里发布

193
pom.xml
View File

@ -4,8 +4,8 @@
<modelVersion>4.0.0</modelVersion>
<groupId>kim.wind</groupId>
<artifactId>sms_aggregation</artifactId>
<version>1.0.0</version>
<name>sms_aggregation</name>
<version>1.0.2</version>
<name>sms-aggregation</name>
<packaging>pom</packaging>
<description>sms_aggregation</description>
<url>https://gitee.com/the-wind-is-like-a-song/sms_aggregation</url>
@ -48,10 +48,12 @@
<properties>
<java.version>1.8</java.version>
<spring.boot.version>2.7.10</spring.boot.version>
<modules.version>1.0.0</modules.version>
<modules.version>1.0.2</modules.version>
<aliyun.version>2.0.23</aliyun.version>
<json.version>2.0.15</json.version>
<okhttp.version>3.14.9</okhttp.version>
<unisms.version>0.0.4</unisms.version>
<tencent.version>3.1.622</tencent.version>
</properties>
<dependencyManagement>
@ -101,12 +103,14 @@
<version>${modules.version}</version>
</dependency>
<!--通用模块-->
<dependency>
<groupId>kim.wind</groupId>
<artifactId>sms-aggregation-comm</artifactId>
<version>${modules.version}</version>
</dependency>
<!--api模块-->
<dependency>
<groupId>kim.wind</groupId>
<artifactId>sms-aggregation-api</artifactId>
@ -155,6 +159,20 @@
<scope>provided</scope>
</dependency>
<!--合一短信依赖-->
<dependency>
<groupId>com.apistd.uni</groupId>
<artifactId>uni-sdk</artifactId>
<version>${unisms.version}</version>
</dependency>
<!-- 腾讯云短信-->
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java</artifactId>
<version>${tencent.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
@ -165,6 +183,7 @@
<optional>true</optional>
</dependency>
<!--配置文件提示-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
@ -186,90 +205,90 @@
<build>
<plugins>
<!-- Source -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Javadoc -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<configuration>
<show>private</show>
<nohelp>true</nohelp>
<charset>UTF-8</charset>
<encoding>UTF-8</encoding>
<docencoding>UTF-8</docencoding>
<additionalparam>-Xdoclint:none</additionalparam>
<!-- TODO 临时解决不规范的javadoc生成报错,后面要规范化后把这行去掉 -->
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- GPG -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<!--Compiler -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<fork>true</fork>
<verbose>true</verbose>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<!--Release -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
</archive>
</configuration>
</plugin>
<plugins>
<!-- Source -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Javadoc -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<configuration>
<show>private</show>
<nohelp>true</nohelp>
<charset>UTF-8</charset>
<encoding>UTF-8</encoding>
<docencoding>UTF-8</docencoding>
<additionalparam>-Xdoclint:none</additionalparam>
<!-- TODO 临时解决不规范的javadoc生成报错,后面要规范化后把这行去掉 -->
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- GPG -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<!--Compiler -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<fork>true</fork>
<verbose>true</verbose>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<!--Release -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</plugins>
</build>
</project>

View File

@ -5,13 +5,13 @@
<parent>
<groupId>kim.wind</groupId>
<artifactId>sms_aggregation</artifactId>
<version>1.0.0</version>
<version>1.0.2</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>sms-aggregation-aliyun</artifactId>
<name>sms-aggregation-aliyun</name>
<description>sms-aggregation-aliyun</description>
<version>1.0.0</version>
<version>1.0.2</version>
<properties>
<java.version>1.8</java.version>
</properties>

View File

@ -26,6 +26,13 @@ import java.util.List;
import java.util.TimerTask;
import java.util.concurrent.Executor;
/**
* <p>类名: AlibabaSmsImpl
* <p>说明 阿里云短信实现
*
* @author :Wind
* 2023/3/26 17:16
**/
@EnableConfigurationProperties({AlibabaSmsConfig.class})
@Slf4j
public class AlibabaSmsImpl implements SmsBlend {
@ -132,6 +139,14 @@ public class AlibabaSmsImpl implements SmsBlend {
});
}
@Override
@Restricted
public void sendMessageAsync(String phone, String message) {
pool.execute(() -> {
sendMessage(phone, message);
});
}
@Override
@Restricted
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages, CallBack callBack) {
@ -141,6 +156,14 @@ public class AlibabaSmsImpl implements SmsBlend {
});
}
@Override
@Restricted
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages) {
pool.execute(()->{
sendMessage(phone,templateId,messages);
});
}
@Override
@Restricted
public void delayedMessage(String phone, String message, Long delayedTime) {
@ -162,4 +185,26 @@ public class AlibabaSmsImpl implements SmsBlend {
}
},delayedTime);
}
@Override
@Restricted
public void delayMassTexting(List<String> phones, String message, Long delayedTime) {
this.delayed.schedule(new TimerTask() {
@Override
public void run() {
massTexting(phones,message);
}
},delayedTime);
}
@Override
@Restricted
public void delayMassTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
this.delayed.schedule(new TimerTask() {
@Override
public void run() {
massTexting(phones,templateId,messages);
}
},delayedTime);
}
}

View File

@ -5,13 +5,13 @@
<parent>
<groupId>kim.wind</groupId>
<artifactId>sms_aggregation</artifactId>
<version>1.0.0</version>
<version>1.0.2</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>sms-aggregation-api</artifactId>
<name>sms-aggregation-api</name>
<description>sms-aggregation-api</description>
<version>1.0.0</version>
<version>1.0.2</version>
<properties>
<java.version>1.8</java.version>

View File

@ -58,6 +58,15 @@ public interface SmsBlend {
void sendMessageAsync(String phone, String message, CallBack callBack);
/**
* <p>说明异步发送短信不关注发送结果
* sendMessageAsync
* @param phone 要发送的号码
* @param message 发送内容
* @author :Wind
*/
void sendMessageAsync(String phone, String message);
/**
* <p>说明异步短信发送使用自定义模板发送短信
* sendMessage
@ -70,7 +79,16 @@ public interface SmsBlend {
void sendMessageAsync(String phone, String templateId, LinkedHashMap<String,String> messages, CallBack callBack);
/**
* <p>说明
* <p>说明异步短信发送使用自定义模板发送短信不关注发送结果
* sendMessageAsync
* @param templateId 模板id
* @param messages key为模板变量名称 value为模板变量值
* @author :Wind
*/
void sendMessageAsync(String phone, String templateId, LinkedHashMap<String,String> messages);
/**
* <p>说明使用固定模板发送延时短信
* delayedMessage
* @param phone 接收短信的手机号
* @param message 要发送的短信
@ -89,4 +107,23 @@ public interface SmsBlend {
* @author :Wind
*/
void delayedMessage(String phone ,String templateId, LinkedHashMap<String,String> messages,Long delayedTime);
/**
* <p>说明群发延迟短信
* delayMassTexting
* @param phones 要群体发送的手机号码
* @author :Wind
*/
void delayMassTexting(List<String> phones, String message,Long delayedTime);
/**
* <p>说明使用自定义模板发送群体延迟短信
* delayMassTexting
* @param phones 要群体发送的手机号码
* @param templateId 模板id
* @param messages key为模板变量名称 value为模板变量值
* @param delayedTime 延迟的时间
* @author :Wind
*/
void delayMassTexting(List<String> phones,String templateId, LinkedHashMap<String, String> messages,Long delayedTime);
}

View File

@ -5,13 +5,13 @@
<parent>
<groupId>kim.wind</groupId>
<artifactId>sms_aggregation</artifactId>
<version>1.0.0</version>
<version>1.0.2</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>sms-aggregation-comm</artifactId>
<name>sms-aggregation-comm</name>
<description>sms-aggregation-comm</description>
<version>1.0.0</version>
<version>1.0.2</version>
<properties>
<java.version>1.8</java.version>
</properties>

View File

@ -6,6 +6,13 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* <p>类名: Restricted
* <p>说明 发送短信限制
*
* @author :Wind
* 2023/3/26 17:12
**/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Restricted {

View File

@ -0,0 +1,17 @@
package kim.wind.sms.comm.config;
public class SmsBanner {
private static final String banner =
" _____ __ __ _____ _____ _____ _____ ______ _____ _______ _____ ____ _ _ \n" +
" / ____| | \\/ | / ____| /\\ / ____| / ____| | __ \\ | ____| / ____| /\\ |__ __| |_ _| / __ \\ | \\ | |\n" +
" | (___ | \\ / | | (___ / \\ | | __ | | __ | |__) | | |__ | | __ / \\ | | | | | | | | | \\| |\n" +
" \\___ \\ | |\\/| | \\___ \\ / /\\ \\ | | |_ | | | |_ | | _ / | __| | | |_ | / /\\ \\ | | | | | | | | | . ` |\n" +
" ____) | | | | | ____) | / ____ \\ | |__| | | |__| | | | \\ \\ | |____ | |__| | / ____ \\ | | _| |_ | |__| | | |\\ |\n" +
" |_____/ |_| |_| |_____/ /_/ \\_\\ \\_____| \\_____| |_| \\_\\ |______| \\_____| /_/ \\_\\ |_| |_____| \\____/ |_| \\_|\n" +
" \n" +
" V1.0.2";
public static void PrintBanner() {
System.out.println(banner);
}
}

View File

@ -1,6 +1,7 @@
package kim.wind.sms.comm.utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
@ -12,7 +13,11 @@ import java.util.concurrent.TimeUnit;
@Slf4j
public class RedisUtils {
private final RedisTemplate<String, Object> redisTemplate;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public RedisUtils() {
}
public RedisUtils(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;

View File

@ -1,5 +1,7 @@
package kim.wind.sms.comm.utils;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Random;
public class SmsUtil {
@ -8,46 +10,54 @@ public class SmsUtil {
/**
* <p>说明生成一个指定长度的随机字符串包含大小写英文字母和数字
* @name: getRandomString
* <p>说明生成一个指定长度的随机字符串包含大小写英文字母和数字但不包含符号
*
* @param len 要生成的字符串的长度
* getRandomString
* @author :Wind
*/
public static String getRandomString(int len){
*/
public static String getRandomString(int len) {
String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < len; i++) {
int number = random.nextInt(62);
sb.append(str.charAt(number));
StringBuilder sb = new StringBuilder();
try {
Random random = SecureRandom.getInstanceStrong();
for (int i = 0; i < len; i++) {
int number = random.nextInt(62);
sb.append(str.charAt(number));
}
} catch (NoSuchAlgorithmException e){
throw new RuntimeException(e);
}
return sb.toString();
}
/**
* <p>说明获取一个长度为6的随机字符串
* @name: getRandomString
* @param
*getRandomString
* @author :Wind
*/
public static String getRandomString(){
*/
public static String getRandomString() {
return getRandomString(6);
}
/**
* <p>说明生成一个指定长度的只有数字组成的随机字符串
* @name: getRandomInt
* @param len 要生成的长度
* getRandomInt
* @author :Wind
*/
public static String getRandomInt(int len){
*/
public static String getRandomInt(int len) {
String str = "0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
StringBuilder sb = new StringBuilder();
try {
Random random = SecureRandom.getInstanceStrong();
for (int i = 0; i < len; i++) {
int number = random.nextInt(10);
sb.append(str.charAt(number));
}
} catch (NoSuchAlgorithmException e){
throw new RuntimeException(e);
}
return sb.toString();
}
@ -55,7 +65,7 @@ public class SmsUtil {
* 指定元素是否为null或者空字符串
* @param str 指定元素
* @return 是否为null或者空字符串
* @author :Wind
* @author :Wind
*/
public static boolean isEmpty(Object str) {
return str == null || "".equals(str);
@ -65,7 +75,7 @@ public class SmsUtil {
* 指定元素是否不为 (null或者空字符串)
* @param str 指定元素
* @return 是否为null或者空字符串
* @author :Wind
* @author :Wind
*/
public static boolean isNotEmpty(Object str) {
return !isEmpty(str);

View File

@ -5,13 +5,13 @@
<parent>
<groupId>kim.wind</groupId>
<artifactId>sms_aggregation</artifactId>
<version>1.0.0</version>
<version>1.0.2</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>sms-aggregation-spring-boot-starter</artifactId>
<name>sms-aggregation-spring-boot-starter</name>
<description>sms-aggregation-spring-boot-starter</description>
<version>1.0.0</version>
<version>1.0.2</version>
<packaging>jar</packaging>
<properties>

View File

@ -1,17 +1,20 @@
package kim.wind.sms.starter.config;
import com.example.sms.unisms.service.UniSmsImpl;
import kim.wind.sms.aliyun.service.AlibabaSmsImpl;
import kim.wind.sms.api.SmsBlend;
import kim.wind.sms.comm.config.SmsBanner;
import kim.wind.sms.comm.delayedTime.DelayedTime;
import kim.wind.sms.comm.utils.RedisUtils;
import kim.wind.sms.comm.utils.SpringUtil;
import kim.wind.sms.tencent.service.TencentSmsImpl;
import kim.wind.sms.yunpian.service.YunPianSmsImpl;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@ -27,6 +30,8 @@ public class SmsMainConfig {
/** 短信服务商*/
@Value("${sms.supplier}")
private String supplier;
/** 打印banner*/
private String isPrint = "true";
/** 是否开启短信限制*/
private String restricted;
@ -69,6 +74,19 @@ public class SmsMainConfig {
switch (supplier){
case "alibaba":
smsBlend = new AlibabaSmsImpl();
break;
case "uniSms":
smsBlend = new UniSmsImpl();
break;
case "yunpian":
smsBlend = new YunPianSmsImpl();
break;
case "tencent":
smsBlend = new TencentSmsImpl();
break;
}
if ("true".equals(isPrint)){
SmsBanner.PrintBanner();
}
return smsBlend;
}
@ -79,8 +97,8 @@ public class SmsMainConfig {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(100);
executor.setKeepAliveSeconds(60);
executor.setQueueCapacity(queueCapacity);
executor.setKeepAliveSeconds(keepAliveSeconds);
executor.setThreadNamePrefix(threadNamePrefix);
executor.setWaitForTasksToCompleteOnShutdown(true);
// 线程池对拒绝任务的处理策略,当线程池没有处理能力的时候该策略会直接在 execute 方法的调用线程中运行被拒绝的任务如果执行程序已关闭则会丢弃该任务
@ -99,12 +117,14 @@ public class SmsMainConfig {
/** 如果启用了redis作为缓存则注入redis工具类*/
@Bean
@ConditionalOnProperty(prefix = "sms", name = "redisCache", havingValue = "true")
public RedisUtils redisUtils(RedisTemplate<String, Object> redisTemplate){
return new RedisUtils(redisTemplate);
public RedisUtils redisUtils(){
return new RedisUtils();
}
/** 注入一个定时器*/
@Bean
public DelayedTime delayedTime(){
return new DelayedTime();
}
}

View File

@ -5,18 +5,30 @@
<parent>
<groupId>kim.wind</groupId>
<artifactId>sms_aggregation</artifactId>
<version>1.0.0</version>
<version>1.0.2</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>sms-aggregation-tencent</artifactId>
<name>sms-aggregation-tencent</name>
<description>sms-aggregation-tencent</description>
<version>1.0.0</version>
<version>1.0.2</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependencies>
<dependency>
<groupId>kim.wind</groupId>
<artifactId>sms-aggregation-comm</artifactId>
</dependency>
<dependency>
<groupId>kim.wind</groupId>
<artifactId>sms-aggregation-api</artifactId>
</dependency>
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java</artifactId>
</dependency>
</dependencies>

View File

@ -0,0 +1,52 @@
package kim.wind.sms.tencent.config;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.sms.v20210111.SmsClient;
import lombok.Data;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "sms.tencent") //指定配置文件注入属性前缀
@Data
@ConditionalOnProperty(prefix = "sms", name = "supplier", havingValue = "tencent")
public class TencentSmsConfig {
/** 应用accessKey*/
private String accessKeyId;
/**
* 访问键秘钥
*/
private String accessKeySecret;
/**
* 短信签名
*/
private String signature;
/**
* 模板Id
*/
private String templateId;
/** 短信sdkAppId*/
private String sdkAppId;
/** 地域信息默认为 ap-guangzhou*/
private String territory ="ap-guangzhou";
/**请求超时时间 */
private Integer connTimeout = 60;
@Bean
public SmsClient tencentBean() {
Credential cred = new Credential(accessKeyId, accessKeySecret);
HttpProfile httpProfile = new HttpProfile();
httpProfile.setReqMethod("POST");
httpProfile.setConnTimeout(connTimeout);
httpProfile.setEndpoint("sms.tencentcloudapi.com");
ClientProfile clientProfile = new ClientProfile();
clientProfile.setSignMethod("HmacSHA256");
clientProfile.setHttpProfile(httpProfile);
return new SmsClient(cred, territory,clientProfile);
}
}

View File

@ -0,0 +1,208 @@
package kim.wind.sms.tencent.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.sms.v20210111.SmsClient;
import com.tencentcloudapi.sms.v20210111.models.SendSmsRequest;
import com.tencentcloudapi.sms.v20210111.models.SendSmsResponse;
import kim.wind.sms.api.SmsBlend;
import kim.wind.sms.api.callback.CallBack;
import kim.wind.sms.comm.annotation.Restricted;
import kim.wind.sms.comm.delayedTime.DelayedTime;
import kim.wind.sms.comm.entity.SmsResponse;
import kim.wind.sms.comm.exception.SmsBlendException;
import kim.wind.sms.tencent.config.TencentSmsConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import java.util.*;
import java.util.concurrent.Executor;
public class TencentSmsImpl implements SmsBlend {
@Autowired
private TencentSmsConfig tencentSmsConfig;
@Autowired
private SmsClient client;
@Autowired
@Qualifier("smsExecutor")
private Executor pool;
@Autowired
private DelayedTime delayed;
@Override
@Restricted
public SmsResponse sendMessage(String phone, String message) {
String[] split = message.split("&");
LinkedHashMap<String, String> map = new LinkedHashMap<>();
for (int i = 0; i < split.length; i++) {
map.put(String.valueOf(i),split[i]);
}
return sendMessage(phone, tencentSmsConfig.getTemplateId(),map);
}
@Override
@Restricted
public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap<String, String> messages) {
SmsResponse smsResponse = new SmsResponse();
try {
SendSmsRequest req = new SendSmsRequest();
req.setSignName(tencentSmsConfig.getSignature());
req.setTemplateId(templateId);
req.setSmsSdkAppId(tencentSmsConfig.getSdkAppId());
List<String> list = new ArrayList<>();
for (Map.Entry<String, String> entry : messages.entrySet()) {
list.add(entry.getValue());
}
String[] s = new String[list.size()];
req.setTemplateParamSet(list.toArray(s));
req.setPhoneNumberSet(new String[]{"+86" + phone});
SendSmsResponse res = client.SendSms(req);
String s1 = SendSmsResponse.toJsonString(res);
JSONObject jsonObject = JSON.parseObject(s1);
if (!"Ok".equals(jsonObject.getString("Code"))) {
smsResponse.setErrMessage(jsonObject.getString("Message"));
}
smsResponse.setMessage(jsonObject.getString("Message"));
smsResponse.setBizId(res.getRequestId());
smsResponse.setData(jsonObject);
} catch (TencentCloudSDKException e) {
throw new SmsBlendException(e.getMessage());
}
return smsResponse;
}
@Override
@Restricted
public SmsResponse massTexting(List<String> phones, String message) {
String[] split = message.split("&");
LinkedHashMap<String, String> map = new LinkedHashMap<>();
for (int i = 0; i < split.length; i++) {
map.put(String.valueOf(i),split[i]);
}
return massTexting(phones,tencentSmsConfig.getTemplateId(),map);
}
@Override
@Restricted
public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) {
SmsResponse smsResponse = new SmsResponse();
try {
SendSmsRequest req = new SendSmsRequest();
req.setSignName(tencentSmsConfig.getSignature());
req.setTemplateId(templateId);
req.setSmsSdkAppId(tencentSmsConfig.getSdkAppId());
List<String> list = new ArrayList<>();
for (Map.Entry<String, String> entry : messages.entrySet()) {
list.add(entry.getValue());
}
String[] s = new String[list.size()];
req.setTemplateParamSet(list.toArray(s));
req.setPhoneNumberSet(arrayToString(phones));
SendSmsResponse res = client.SendSms(req);
String s1 = SendSmsResponse.toJsonString(res);
JSONObject jsonObject = JSON.parseObject(s1);
if (!"Ok".equals(jsonObject.getString("Code"))) {
smsResponse.setErrMessage(jsonObject.getString("Message"));
}
smsResponse.setMessage(jsonObject.getString("Message"));
smsResponse.setBizId(res.getRequestId());
smsResponse.setData(jsonObject);
} catch (TencentCloudSDKException e) {
throw new SmsBlendException(e.getMessage());
}
return smsResponse;
}
@Override
@Restricted
public void sendMessageAsync(String phone, String message, CallBack callBack) {
pool.execute(() -> {
SmsResponse smsResponse = sendMessage(phone, message);
callBack.callBack(smsResponse);
});
}
@Override
@Restricted
public void sendMessageAsync(String phone, String message) {
pool.execute(() -> {
sendMessage(phone, message);
});
}
@Override
@Restricted
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages, CallBack callBack) {
pool.execute(()->{
SmsResponse smsResponse = sendMessage(phone,templateId,messages);
callBack.callBack(smsResponse);
});
}
@Override
@Restricted
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages) {
pool.execute(()->{
sendMessage(phone,templateId,messages);
});
}
@Override
@Restricted
public void delayedMessage(String phone, String message, Long delayedTime) {
this.delayed.schedule(new TimerTask() {
@Override
public void run() {
sendMessage(phone,message);
}
},delayedTime);
}
@Override
@Restricted
public void delayedMessage(String phone, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
this.delayed.schedule(new TimerTask() {
@Override
public void run() {
sendMessage(phone,templateId,messages);
}
},delayedTime);
}
@Override
@Restricted
public void delayMassTexting(List<String> phones, String message, Long delayedTime) {
this.delayed.schedule(new TimerTask() {
@Override
public void run() {
massTexting(phones,message);
}
},delayedTime);
}
@Override
@Restricted
public void delayMassTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
this.delayed.schedule(new TimerTask() {
@Override
public void run() {
massTexting(phones,templateId,messages);
}
},delayedTime);
}
private String[] arrayToString(List<String> list){
String[] strs = new String[list.size()];
List<String> toStr = new ArrayList<>();
for (String s : list) {
toStr.add("+86"+s);
}
return toStr.toArray(strs);
}
}

View File

@ -5,19 +5,33 @@
<parent>
<groupId>kim.wind</groupId>
<artifactId>sms_aggregation</artifactId>
<version>1.0.0</version>
<version>1.0.2</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>sms-aggregation-unisms</artifactId>
<name>sms-aggregation-unisms</name>
<description>sms-aggregation-unisms</description>
<version>1.0.0</version>
<version>1.0.2</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.apistd.uni</groupId>
<artifactId>uni-sdk</artifactId>
</dependency>
<dependency>
<groupId>kim.wind</groupId>
<artifactId>sms-aggregation-comm</artifactId>
</dependency>
<dependency>
<groupId>kim.wind</groupId>
<artifactId>sms-aggregation-api</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,38 @@
package com.example.sms.unisms.config;
import com.apistd.uni.Uni;
import lombok.Data;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "sms.uni-sms") //指定配置文件注入属性前缀
@Data
@ConditionalOnProperty(prefix = "sms", name = "supplier", havingValue = "uni-sms")
public class UniSmsConfig {
/** 访问键标识*/
private String accessKeyId;
/** 访问键秘钥 简易模式不需要配置*/
private String accessKeySecret;
/** 是否为简易模式*/
private String isSimple = "true";
/** 短信签名*/
private String signature;
/** 模板Id*/
private String templateId;
/** 模板变量名称*/
private String templateName;
/** 自动注入短信配置*/
@Bean
public void buildSms(){
if ("true".equals(isSimple)){
Uni.init(accessKeyId);
}else {
Uni.init(accessKeyId,accessKeySecret);
}
}
}

View File

@ -0,0 +1,179 @@
package com.example.sms.unisms.service;
import com.apistd.uni.UniResponse;
import com.apistd.uni.sms.UniMessage;
import com.apistd.uni.sms.UniSMS;
import com.example.sms.unisms.config.UniSmsConfig;
import kim.wind.sms.api.SmsBlend;
import kim.wind.sms.api.callback.CallBack;
import kim.wind.sms.comm.annotation.Restricted;
import kim.wind.sms.comm.delayedTime.DelayedTime;
import kim.wind.sms.comm.entity.SmsResponse;
import kim.wind.sms.comm.exception.SmsBlendException;
import kim.wind.sms.comm.utils.HTTPUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.TimerTask;
import java.util.concurrent.Executor;
/**
* <p>类名: UniSmsImpl
* <p>说明 uniSms短信实现
*
* @author :Wind
* 2023/3/26 17:10
**/
@EnableConfigurationProperties({UniSmsConfig.class})
@Slf4j
public class UniSmsImpl implements SmsBlend {
@Autowired
private UniSmsConfig config;
@Autowired
@Qualifier("smsExecutor")
private Executor pool;
@Autowired
private DelayedTime delayed;
@Override
@Restricted
public SmsResponse sendMessage(String phone, String message) {
if ("".equals(config.getTemplateId()) && "".equals(config.getTemplateName())){
throw new SmsBlendException("配置文件模板id和模板变量不能为空");
}
LinkedHashMap<String, String>map = new LinkedHashMap<>();
map.put(config.getTemplateName(),message);
return sendMessage(phone, config.getTemplateId(),map);
}
@Override
@Restricted
public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap<String, String> messages) {
UniMessage uniMes = UniSMS.buildMessage().setSignature(config.getSignature()).setTo(phone)
.setTemplateId(templateId)
.setTemplateData(messages);
return getSmsResponse(uniMes);
}
@Override
@Restricted
public SmsResponse massTexting(List<String> phones, String message) {
if ("".equals(config.getTemplateId()) && "".equals(config.getTemplateName())){
throw new SmsBlendException("配置文件模板id和模板变量不能为空");
}
LinkedHashMap<String, String>map = new LinkedHashMap<>();
map.put(config.getTemplateName(),message);
return massTexting(phones, config.getTemplateId(),map);
}
@Override
@Restricted
public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) {
if (phones.size()>1000){
throw new SmsBlendException("单次发送超过最大发送上限建议每次群发短信人数低于1000");
}
String[] s = new String[phones.size()];
UniMessage uniMes = UniSMS.buildMessage().setSignature(config.getSignature()).setTo(phones.toArray(s))
.setTemplateId(templateId)
.setTemplateData(messages);
return getSmsResponse(uniMes);
}
@Override
@Restricted
public void sendMessageAsync(String phone, String message, CallBack callBack) {
pool.execute(()->{
SmsResponse smsResponse = sendMessage(phone, message);
callBack.callBack(smsResponse);
});
}
@Override
public void sendMessageAsync(String phone, String message) {
pool.execute(()->{
sendMessage(phone, message);
});
}
@Override
@Restricted
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages, CallBack callBack) {
pool.execute(()->{
SmsResponse smsResponse = sendMessage(phone,templateId,messages);
callBack.callBack(smsResponse);
});
}
@Override
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages) {
pool.execute(()->{
sendMessage(phone,templateId,messages);
});
}
@Override
@Restricted
public void delayedMessage(String phone, String message, Long delayedTime) {
this.delayed.schedule(new TimerTask() {
@Override
public void run() {
sendMessage(phone,message);
}
},delayedTime);
}
@Override
@Restricted
public void delayedMessage(String phone, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
this.delayed.schedule(new TimerTask() {
@Override
public void run() {
sendMessage(phone,templateId,messages);
}
},delayedTime);
}
@Override
public void delayMassTexting(List<String> phones, String message, Long delayedTime) {
this.delayed.schedule(new TimerTask() {
@Override
public void run() {
massTexting(phones,message);
}
},delayedTime);
}
@Override
public void delayMassTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
this.delayed.schedule(new TimerTask() {
@Override
public void run() {
massTexting(phones,templateId,messages);
}
},delayedTime);
}
private SmsResponse getSmsResponse(UniMessage uniMes) {
SmsResponse smsResponse = new SmsResponse();
try {
UniResponse send = uniMes.send();
smsResponse.setCode(send.status);
smsResponse.setErrorCode(send.code);
smsResponse.setMessage(send.message);
smsResponse.setBizId(send.requestId);
smsResponse.setData(HTTPUtils.getJSONObject(send));
}catch(Exception e){
smsResponse.setErrMessage(e.getMessage());
}
return smsResponse;
}
}

View File

@ -5,20 +5,27 @@
<parent>
<groupId>kim.wind</groupId>
<artifactId>sms_aggregation</artifactId>
<version>1.0.0</version>
<version>1.0.2</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>sms-aggregation-yunpian</artifactId>
<name>sms-aggregation-yunpian</name>
<description>sms-aggregation-yunpian</description>
<version>1.0.0</version>
<version>1.0.2</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>kim.wind</groupId>
<artifactId>sms-aggregation-comm</artifactId>
</dependency>
<dependency>
<groupId>kim.wind</groupId>
<artifactId>sms-aggregation-api</artifactId>
</dependency>
</dependencies>

View File

@ -0,0 +1,16 @@
package kim.wind.sms.yunpian.config;
import lombok.Data;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "sms.yunpian") //指定配置文件注入属性前缀
@Data
@ConditionalOnProperty(prefix = "sms", name = "supplier", havingValue = "yunpian")
public class YunPianSmsConfig {
/** 账号唯一标识*/
private String apikey;
}

View File

@ -0,0 +1,215 @@
package kim.wind.sms.yunpian.service;
import com.alibaba.fastjson.JSONObject;
import kim.wind.sms.api.SmsBlend;
import kim.wind.sms.api.callback.CallBack;
import kim.wind.sms.comm.annotation.Restricted;
import kim.wind.sms.comm.delayedTime.DelayedTime;
import kim.wind.sms.comm.entity.SmsResponse;
import kim.wind.sms.comm.exception.SmsBlendException;
import kim.wind.sms.comm.utils.HTTPUtils;
import kim.wind.sms.yunpian.config.YunPianSmsConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import java.util.*;
import java.util.concurrent.Executor;
public class YunPianSmsImpl implements SmsBlend {
@Autowired
@Qualifier("smsExecutor")
private Executor pool;
@Autowired
private DelayedTime delayed;
@Autowired
private HTTPUtils http ;
@Autowired
private YunPianSmsConfig config;
@Override
@Restricted
public SmsResponse sendMessage(String phone, String message) {
Map<String,String> body = new HashMap<>();
body.put("apikey",config.getApikey());
body.put("mobile",phone);
return getSmsResponse(message, body);
}
@Override
@Restricted
public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap<String, String> messages) {
Map<String,String> body = new HashMap<>();
body.put("apikey",config.getApikey());
body.put("mobile",phone);
body.put("tpl_id",templateId);
body.put("tpl_value",formattingMap(messages));
Map<String,String> map = new HashMap<>();
map.put("Accept","application/json;charset=utf-8");
HTTPUtils.OKResponse sync = http.setBaseURL("https://sms.yunpian.com/v2").builder()
.headers(map)
.postOrBody("/sms/tpl_single_send.json", body)
.sync();
SmsResponse smsResponse = new SmsResponse();
smsResponse.setCode(sync.getCode());
JSONObject jsonObject = HTTPUtils.getJSONObject(sync);
smsResponse.setData(jsonObject);
return smsResponse;
}
@Override
@Restricted
public SmsResponse massTexting(List<String> phones, String message) {
if (phones.size()>1000){
throw new SmsBlendException("单次发送超过最大发送上限建议每次群发短信人数低于1000");
}
Map<String,String> body = new HashMap<>();
body.put("apikey",config.getApikey());
body.put("mobile",listToString(phones));
return getSmsResponse(message, body);
}
@Override
@Restricted
public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) {
if (phones.size()>1000){
throw new SmsBlendException("单次发送超过最大发送上限建议每次群发短信人数低于1000");
}
Map<String,String> body = new HashMap<>();
body.put("apikey",config.getApikey());
body.put("mobile",listToString(phones));
body.put("tpl_id",templateId);
body.put("tpl_value",formattingMap(messages));
Map<String,String> map = new HashMap<>();
map.put("Accept","application/json;charset=utf-8");
HTTPUtils.OKResponse sync = http.setBaseURL("https://sms.yunpian.com/v2").builder()
.headers(map)
.postOrBody("/tpl_batch_send.json", body)
.sync();
SmsResponse smsResponse = new SmsResponse();
smsResponse.setCode(sync.getCode());
JSONObject jsonObject = HTTPUtils.getJSONObject(sync);
smsResponse.setData(jsonObject);
return smsResponse;
}
@Override
@Restricted
public void sendMessageAsync(String phone, String message, CallBack callBack) {
pool.execute(() -> {
SmsResponse smsResponse = sendMessage(phone, message);
callBack.callBack(smsResponse);
});
}
@Override
@Restricted
public void sendMessageAsync(String phone, String message) {
pool.execute(() -> sendMessage(phone, message));
}
@Override
@Restricted
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages, CallBack callBack) {
pool.execute(()->{
SmsResponse smsResponse = sendMessage(phone,templateId,messages);
callBack.callBack(smsResponse);
});
}
@Override
@Restricted
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages) {
pool.execute(()->{
sendMessage(phone,templateId,messages);
});
}
@Override
@Restricted
public void delayedMessage(String phone, String message, Long delayedTime) {
this.delayed.schedule(new TimerTask() {
@Override
public void run() {
sendMessage(phone,message);
}
},delayedTime);
}
@Override
@Restricted
public void delayedMessage(String phone, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
this.delayed.schedule(new TimerTask() {
@Override
public void run() {
sendMessage(phone,templateId,messages);
}
},delayedTime);
}
@Override
@Restricted
public void delayMassTexting(List<String> phones, String message, Long delayedTime) {
this.delayed.schedule(new TimerTask() {
@Override
public void run() {
massTexting(phones,message);
}
},delayedTime);
}
@Override
@Restricted
public void delayMassTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
this.delayed.schedule(new TimerTask() {
@Override
public void run() {
massTexting(phones,templateId,messages);
}
},delayedTime);
}
private String formattingMap(Map<String,String> messages){
StringBuilder str = new StringBuilder();
for (Map.Entry<String,String> entry : messages.entrySet()) {
str.append("#");
str.append(entry.getKey());
str.append("#=");
str.append(entry.getValue());
str.append("&");
}
str.deleteCharAt(str.length()-1);
return str.toString();
}
private String listToString(List<String> list){
StringBuilder str = new StringBuilder();
for (int i = 0; i < list.size(); i++) {
if (i == list.size() - 1) {
str.append(list.get(i));
} else {
str.append(list.get(i));
str.append(",");
}
}
return str.toString();
}
private SmsResponse getSmsResponse(String message, Map<String, String> body) {
body.put("text",message);
Map<String,String> map = new HashMap<>();
map.put("Accept","application/json;charset=utf-8");
HTTPUtils.OKResponse sync = http.setBaseURL("http://sms.yunpian.com/v2").builder()
.headers(map)
.postOrBody("/sms/single_send.json", body)
.sync();
SmsResponse smsResponse = new SmsResponse();
smsResponse.setCode(sync.getCode());
JSONObject jsonObject = HTTPUtils.getJSONObject(sync);
smsResponse.setData(jsonObject);
return smsResponse;
}
}

View File

@ -1,3 +0,0 @@
> 1%
last 2 versions
not dead

View File

@ -1,23 +0,0 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@ -1,19 +0,0 @@
# smsdoc
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

View File

@ -1,5 +0,0 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}

View File

@ -1,19 +0,0 @@
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"baseUrl": "./",
"moduleResolution": "node",
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,25 +0,0 @@
{
"name": "smsdoc",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
},
"dependencies": {
"core-js": "^3.8.3",
"element-ui": "^2.15.13",
"vue": "^2.6.14",
"vue-router": "^3.5.1",
"vuex": "^3.6.2"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-router": "~5.0.0",
"@vue/cli-plugin-vuex": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"sass": "^1.32.7",
"sass-loader": "^12.0.0",
"vue-template-compiler": "^2.6.14"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -1,17 +0,0 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

View File

@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1679670746744" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2786" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M837.470354 1024H186.501825c-45.735872 0-98.259401-10.019873-98.259401-87.593084V406.161697a32.322171 32.322171 0 0 1 9.535041-22.948742L463.987665 19.75014a68.199781 68.199781 0 0 1 95.996849 0l366.2102 363.462815a32.322171 32.322171 0 0 1 9.53504 22.948742v530.245219c0 56.725411-15.676253 87.593084-98.2594 87.593084zM152.886767 420.221841v517.15474c0 21.171022 0 22.948742 33.615058 22.948742h650.968529a114.420486 114.420486 0 0 0 32.322171-3.070607 183.589933 183.589933 0 0 0 0-19.878135V420.221841L514.410252 65.647623a3.555439 3.555439 0 0 0-4.848326 0z" fill="#3D3D3D" p-id="2787"></path><path d="M538.813491 239.217682a23.756796 23.756796 0 0 0-32.322171 0l-239.184067 236.759905v345.362399c0 28.766732 12.120814 36.039221 42.988488 36.039221H734.685849c42.988488 0 42.988488-11.635982 42.988488-36.039221V475.977587z" fill="#F683A2" p-id="2788"></path><path d="M811.774227 941.255242h-129.288684a32.322171 32.322171 0 0 1 0-64.644343h129.288684a32.322171 32.322171 0 0 1 0 64.644343z" fill="#3D3D3D" p-id="2789"></path></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1,18 +0,0 @@
<template>
<div id="app">
<router-view />
</div>
</template>
<style>
* {
margin: 0;
padding: 0;
}
a {
text-decoration: none;
color: #333;
outline: none;
cursor: pointer;
}
</style>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1679670746744" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2786" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M837.470354 1024H186.501825c-45.735872 0-98.259401-10.019873-98.259401-87.593084V406.161697a32.322171 32.322171 0 0 1 9.535041-22.948742L463.987665 19.75014a68.199781 68.199781 0 0 1 95.996849 0l366.2102 363.462815a32.322171 32.322171 0 0 1 9.53504 22.948742v530.245219c0 56.725411-15.676253 87.593084-98.2594 87.593084zM152.886767 420.221841v517.15474c0 21.171022 0 22.948742 33.615058 22.948742h650.968529a114.420486 114.420486 0 0 0 32.322171-3.070607 183.589933 183.589933 0 0 0 0-19.878135V420.221841L514.410252 65.647623a3.555439 3.555439 0 0 0-4.848326 0z" fill="#3D3D3D" p-id="2787"></path><path d="M538.813491 239.217682a23.756796 23.756796 0 0 0-32.322171 0l-239.184067 236.759905v345.362399c0 28.766732 12.120814 36.039221 42.988488 36.039221H734.685849c42.988488 0 42.988488-11.635982 42.988488-36.039221V475.977587z" fill="#F683A2" p-id="2788"></path><path d="M811.774227 941.255242h-129.288684a32.322171 32.322171 0 0 1 0-64.644343h129.288684a32.322171 32.322171 0 0 1 0 64.644343z" fill="#3D3D3D" p-id="2789"></path></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -1,59 +0,0 @@
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>
For a guide and recipes on how to configure / customize this project,<br>
check out the
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
</p>
<h3>Installed CLI Plugins</h3>
<ul>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router" target="_blank" rel="noopener">router</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-vuex" target="_blank" rel="noopener">vuex</a></li>
</ul>
<h3>Essential Links</h3>
<ul>
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
</ul>
<h3>Ecosystem</h3>
<ul>
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
</ul>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>

View File

@ -1,12 +0,0 @@
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')

View File

@ -1,22 +0,0 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'home',
component: ()=>import('../views/index.vue')
},
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router

View File

@ -1,17 +0,0 @@
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
getters: {
},
mutations: {
},
actions: {
},
modules: {
}
})

View File

@ -1,3 +0,0 @@
<template>
<div class="about"></div>
</template>

View File

@ -1,18 +0,0 @@
<template>
<div class="logo">
<img alt="Vue logo" src="../assets/logo.png" />
</div>
</template>
<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
export default {
name: 'HomeView',
components: {
HelloWorld,
},
}
</script>
<style></style>

View File

@ -1,132 +0,0 @@
<template>
<div>
<div class="header">
<div class="header-left">
<img class="logo" src="../assets/logo.png" alt="" />
<span class="sms">sms aggregation</span>
</div>
<div class="header-right">
<input type="text" />
<a href=""><img src="../assets/首页2.png" alt="" />首页</a>
<a href=""><img src="../assets/项目2.png" />文档</a>
<a href=""><img src="../assets/项目2.png" />插件</a>
<a href=""><img src="../assets/项目2.png" />案例</a>
<a href=""><img src="../assets/项目2.png" />支持</a>
<a href=""><img src="../assets/项目2.png" />更新记录</a>
<a href=""><img src="../assets/项目2.png" />开发团队</a>
<a href=""><img src="../assets/项目2.png" />参与贡献</a>
<a href=""><img src="../assets/项目2.png" />推荐</a>
<a href=""><img src="../assets/项目2.png" />源码</a>
</div>
</div>
<div class="main">
<img class="biglogo" src="../assets/logo.png" alt="" />
<h1>sms aggregation</h1>
<p>聚合式短信发送工具,降低开发难度,统一使用标准</p>
<button>开始使用</button>
</div>
<div class="gongneng">
<div><h3>容易上手</h3></div>
<div><h3>简单优雅</h3></div>
<div><h3>拓展灵活</h3></div>
</div>
<div>
<h2>特别赞助</h2>
</div>
<div>
<h2>特性</h2>
</div>
<div>
<h2>最新版本</h2>
</div>
<div>
<h2>代码托管</h2></h2>
</div>
<div>
<h2>知识星球</h2>
</div>
<div>
<h2>开源社区平台</h2>
</div>
<div>
<h2>友情链接</h2>
</div>
<div class="footer">
<p>
© 2022 wind 冀ICP备2021004949号-3 | 图标引用自阿里矢量图库个人使用
如侵删
</p>
</div>
</div>
</template>
<script></script>
<style>
a {
margin-left: 10px;
margin-right: 5px;
/* line-height: 50px; */
display: flex;
justify-content: center;
align-items: center;
}
.header {
height: 50px;
display: flex;
justify-content: space-between;
width: 100%;
background: rgb(240, 240, 240);
line-height: 50px;
}
.header-left {
display: flex;
justify-content: center;
align-items: center;
}
.header-right {
display: flex;
justify-content: center;
align-items: center;
}
.sms {
font-size: 20px;
font-weight: 1000;
}
.logo {
width: 50px;
}
img {
width: 16px;
}
input {
height: 16px;
border-radius: 50px;
}
.biglogo {
width: 300px;
/* display: block;
margin: 0 auto;
margin-top: 100px; */
}
.main {
width: 500px;
height: 500px;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
margin: 0 auto;
margin-top: 100px;
}
.gongneng {
margin-top: 100px;
display: flex;
justify-content: space-around;
}
.footer {
text-align: center;
}
</style>

View File

@ -1,4 +0,0 @@
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true
})