91
README.md
@ -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
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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>
|
||||
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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>
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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>
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
> 1%
|
||||
last 2 versions
|
||||
not dead
|
||||
23
sms-doc/smsdoc/.gitignore
vendored
@ -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?
|
||||
@ -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/).
|
||||
@ -1,5 +0,0 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/cli-plugin-babel/preset'
|
||||
]
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "esnext",
|
||||
"baseUrl": "./",
|
||||
"moduleResolution": "node",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
},
|
||||
"lib": [
|
||||
"esnext",
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"scripthost"
|
||||
]
|
||||
}
|
||||
}
|
||||
17456
sms-doc/smsdoc/package-lock.json
generated
@ -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"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 4.2 KiB |
@ -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>
|
||||
@ -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 |
@ -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>
|
||||
|
Before Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
@ -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 |
|
Before Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
@ -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>
|
||||
@ -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')
|
||||
@ -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
|
||||
@ -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: {
|
||||
}
|
||||
})
|
||||
@ -1,3 +0,0 @@
|
||||
<template>
|
||||
<div class="about"></div>
|
||||
</template>
|
||||
@ -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>
|
||||
@ -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>
|
||||
@ -1,4 +0,0 @@
|
||||
const { defineConfig } = require('@vue/cli-service')
|
||||
module.exports = defineConfig({
|
||||
transpileDependencies: true
|
||||
})
|
||||