diff --git a/README.md b/README.md
index 707cbc6..e2121ba 100644
--- a/README.md
+++ b/README.md
@@ -56,7 +56,11 @@ austin项目**核心流程**:`austin-api`接收到发送消息请求,直接
目前引用的中间件教程的安装姿势均基于`Centos 7.6`(**完全部署所有的服务,大概8G内存**),austin项目**强依赖**`MySQL`/`Redis`/`Kafka`/`apollo`,**弱依赖**`prometheus`/`graylog`/`flink`/`xxl-job`。如果缺少相关的组件可戳:[安装相关组件教程](INSTALL.md)。
-实在想要拉下clone项目后不部署环境直接启动,我这提供了[会员服务](https://mp.weixin.qq.com/s?__biz=MzI4Njg5MDA5NA==&mid=2247505577&idx=1&sn=5114f8f583755899c2946fbea0b22e4b&chksm=ebd497a8dca31ebe8f98344483a00c860863dfc3586e51eed95b25988151427fee8101311f4f&token=735778370&lang=zh_CN#rd)
+
+
+> 实在想要`clone`项目后不用自己部署环境直接在本地启动`debug`,我这提供了[会员服务](https://mp.weixin.qq.com/s?__biz=MzI4Njg5MDA5NA==&mid=2247505577&idx=1&sn=5114f8f583755899c2946fbea0b22e4b&chksm=ebd497a8dca31ebe8f98344483a00c860863dfc3586e51eed95b25988151427fee8101311f4f&token=735778370&lang=zh_CN#rd),**直连**部署好的服务器
+
+
**1**、austin使用的MySQL版本**5.7x**。如果目前使用的MySQL版本8.0,注意改变`pom.xml`所依赖的版本
@@ -100,6 +104,22 @@ curl -XPOST "127.0.0.1:8080/send" -H 'Content-Type: application/json' -d '{"co
**14**、正常使用**系统监控**需要部署`promethus`和`grafana`,根据[部署文档](INSTALL.md)配置`grafana`图表
+## 会员服务
+
+收费课程是以**项目**为主,代码在Gitee和GitHub上都是开源的,项目没有商业版,后面也不会有。那么,付费跟我自己去拉Git仓库拉代码下来看有什么区别?
+
+1、有很多人的自学能力和基础确实不太行,不知道怎么开始学习,从哪开始看起,学习项目的过程中会走很多弯路,很容易就迷茫了。付费最跟自学最主要的区别就是**我的服务会更周到**。
+
+我会告诉你怎么开始学这个开源项目,哪些是重点需要掌握的,如何利用最短的时间把握整个系统架构和编码的设计,把时间节省下来去做其他事情。
+
+2、一个生产环境的系统肯定会依赖各种中间件,《消息推送平台-Austin》也是一样的。我专门买了两台服务器已经搭建好必要的依赖,付费的可以**使用我的远程服务器**,在**本地就可以直接启动运行体验和学习**
+
+3、项目在编写的过程中也经历多次的重构迭代,迭代的内容我是不会将以往文章内容重新修正发布,但语雀的文档内容一定是**及时同步**,文档跟代码是保持一致的
+
+4、除了项目,还可以问我些学习经验、学习路线、简历编写、面试经验等等问题,技术和学习上的知识**知无不言**
+
+详情可以看戳:[我开通了付费渠道](https://mp.weixin.qq.com/s?__biz=MzI4Njg5MDA5NA==&mid=2247505577&idx=1&sn=5114f8f583755899c2946fbea0b22e4b&chksm=ebd497a8dca31ebe8f98344483a00c860863dfc3586e51eed95b25988151427fee8101311f4f&token=319992632&lang=zh_CN#rd)
+
## 里程碑
- [x] Maven+SpringBoot项目搭建
@@ -142,22 +162,12 @@ curl -XPOST "127.0.0.1:8080/send" -H 'Content-Type: application/json' -d '{"co
-
-**Java3y**公众号在持续更新austin系列文章,**保姆级**讲解搭建项目的过程(包括技术选型以及一些业务的探讨)以及相关环境的搭建。**扫下面的码直接关注,带你了解整个项目**
-
-
-如果你需要用这个项目写在简历上,**强烈建议关注公众号看实现细节的思路**。如果⽂档中有任何的不懂的问题,都可以直接来找我询问,我乐意帮助你们!公众号下有我的联系方式
-
-[会员服务](https://mp.weixin.qq.com/s?__biz=MzI4Njg5MDA5NA==&mid=2247505577&idx=1&sn=5114f8f583755899c2946fbea0b22e4b&chksm=ebd497a8dca31ebe8f98344483a00c860863dfc3586e51eed95b25988151427fee8101311f4f&token=735778370&lang=zh_CN#rd)
-
-
-
## 如何准备面试?
**对线面试官**公众号持续更新**面试系列**文章(对线面试官系列),深受各大开发的好评,已有不少的同学通过对线面试官系列得到BATTMD等一线大厂的的offer。一个**讲人话的面试系列**,八股文不再是背诵。
-
+
想要获取这份电子书,**点击关注**下方公众号,回复「**对线**」得到我的联系方式即可进群获取电子书
diff --git a/austin-common/src/main/java/com/java3y/austin/common/enums/RespStatusEnum.java b/austin-common/src/main/java/com/java3y/austin/common/enums/RespStatusEnum.java
index 40985c7..26f61f5 100644
--- a/austin-common/src/main/java/com/java3y/austin/common/enums/RespStatusEnum.java
+++ b/austin-common/src/main/java/com/java3y/austin/common/enums/RespStatusEnum.java
@@ -26,6 +26,7 @@ public enum RespStatusEnum {
*/
CLIENT_BAD_PARAMETERS("A0001", "客户端参数错误"),
TEMPLATE_NOT_FOUND("A0002", "找不到模板或模板已被删除"),
+ TOO_MANY_RECEIVER("A0003", "传入的接收者大于100个"),
/**
* 系统
diff --git a/austin-common/src/main/java/com/java3y/austin/common/enums/SmsStatus.java b/austin-common/src/main/java/com/java3y/austin/common/enums/SmsStatus.java
index 2ee30ba..285280c 100644
--- a/austin-common/src/main/java/com/java3y/austin/common/enums/SmsStatus.java
+++ b/austin-common/src/main/java/com/java3y/austin/common/enums/SmsStatus.java
@@ -21,4 +21,19 @@ public enum SmsStatus {
private String description;
+ /**
+ * 根据状态获取描述信息
+ * @param code
+ * @return
+ */
+ public static String getDescriptionByStatus(Integer code) {
+ for (SmsStatus value : SmsStatus.values()) {
+ if (value.getCode().equals(code)) {
+ return value.getDescription();
+ }
+ }
+ return "";
+ }
+
+
}
diff --git a/austin-handler/src/main/java/com/java3y/austin/handler/receipt/TencentSmsReceipt.java b/austin-handler/src/main/java/com/java3y/austin/handler/receipt/TencentSmsReceipt.java
new file mode 100644
index 0000000..e59f67a
--- /dev/null
+++ b/austin-handler/src/main/java/com/java3y/austin/handler/receipt/TencentSmsReceipt.java
@@ -0,0 +1,115 @@
+package com.java3y.austin.handler.receipt;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.date.DateUtil;
+import com.alibaba.fastjson.JSON;
+import com.google.common.base.Throwables;
+import com.java3y.austin.common.constant.SendAccountConstant;
+import com.java3y.austin.common.dto.account.TencentSmsAccount;
+import com.java3y.austin.common.enums.SmsStatus;
+import com.java3y.austin.support.config.SupportThreadPoolConfig;
+import com.java3y.austin.support.dao.SmsRecordDao;
+import com.java3y.austin.support.domain.SmsRecord;
+import com.java3y.austin.support.utils.AccountUtils;
+import com.tencentcloudapi.common.Credential;
+import com.tencentcloudapi.common.exception.TencentCloudSDKException;
+import com.tencentcloudapi.common.profile.ClientProfile;
+import com.tencentcloudapi.common.profile.HttpProfile;
+import com.tencentcloudapi.sms.v20210111.SmsClient;
+import com.tencentcloudapi.sms.v20210111.models.*;
+import lombok.extern.slf4j.Slf4j;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+
+/**
+ * 拉取短信回执信息
+ *
+ * @author 3y
+ */
+@Component
+@Slf4j
+public class TencentSmsReceipt {
+
+
+ @Autowired
+ private AccountUtils accountUtils;
+
+ @Autowired
+ private SmsRecordDao smsRecordDao;
+
+ @PostConstruct
+ private void init() {
+
+ // 获取腾讯云账号信息
+ TencentSmsAccount account = accountUtils.getAccount(10, SendAccountConstant.SMS_ACCOUNT_KEY, SendAccountConstant.SMS_PREFIX, TencentSmsAccount.class);
+
+ SupportThreadPoolConfig.getPendingSingleThreadPool().execute(() -> {
+
+ while (true) {
+ try {
+ SmsClient client = getSmsClient(account);
+
+ // 每次拉取10条
+ PullSmsSendStatusRequest req = new PullSmsSendStatusRequest();
+ req.setLimit(10L);
+ req.setSmsSdkAppId(account.getSmsSdkAppId());
+
+ PullSmsSendStatusResponse resp = client.PullSmsSendStatus(req);
+ List smsRecordList = new ArrayList<>();
+ if (resp != null && resp.getPullSmsSendStatusSet() != null && resp.getPullSmsSendStatusSet().length > 0) {
+ log.debug("receipt sms:{}", JSON.toJSONString(resp.getPullSmsSendStatusSet()));
+ for (PullSmsSendStatus pullSmsSendStatus : resp.getPullSmsSendStatusSet()) {
+ SmsRecord smsRecord = SmsRecord.builder()
+ .sendDate(Integer.valueOf(DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)))
+ .messageTemplateId(0L)
+ .phone(Long.valueOf(pullSmsSendStatus.getSubscriberNumber()))
+ .supplierId(account.getSupplierId())
+ .supplierName(account.getSupplierName())
+ .msgContent("")
+ .seriesId(pullSmsSendStatus.getSerialNo())
+ .chargingNum(0)
+ .status("SUCCESS".equals(pullSmsSendStatus.getReportStatus()) ? SmsStatus.RECEIVE_SUCCESS.getCode() : SmsStatus.RECEIVE_FAIL.getCode())
+ .reportContent(pullSmsSendStatus.getDescription())
+ .updated(Math.toIntExact(pullSmsSendStatus.getUserReceiveTime()))
+ .created(Math.toIntExact(DateUtil.currentSeconds()))
+ .build();
+ smsRecordList.add(smsRecord);
+ }
+ }
+ if (!CollUtil.isEmpty(smsRecordList)) {
+ smsRecordDao.saveAll(smsRecordList);
+ }
+ Thread.sleep(200);
+ } catch (Exception e) {
+ log.error("TencentSmsReceipt#init fail!{}", Throwables.getStackTraceAsString(e));
+ }
+ }
+
+ });
+
+ }
+
+ /**
+ * 构造smsClient
+ * @param account
+ * @return
+ */
+ private SmsClient getSmsClient(TencentSmsAccount account) {
+ Credential cred = new Credential(account.getSecretId(), account.getSecretKey());
+ HttpProfile httpProfile = new HttpProfile();
+ httpProfile.setEndpoint(account.getUrl());
+ ClientProfile clientProfile = new ClientProfile();
+ clientProfile.setHttpProfile(httpProfile);
+ return new SmsClient(cred, account.getRegion(), clientProfile);
+ }
+
+
+}
diff --git a/austin-support/src/main/java/com/java3y/austin/support/dao/SmsRecordDao.java b/austin-support/src/main/java/com/java3y/austin/support/dao/SmsRecordDao.java
index c312996..4211d88 100644
--- a/austin-support/src/main/java/com/java3y/austin/support/dao/SmsRecordDao.java
+++ b/austin-support/src/main/java/com/java3y/austin/support/dao/SmsRecordDao.java
@@ -4,12 +4,21 @@ package com.java3y.austin.support.dao;
import com.java3y.austin.support.domain.SmsRecord;
import org.springframework.data.repository.CrudRepository;
+import java.util.List;
+
/**
* 短信记录的Dao
- * @author 3y
*
+ * @author 3y
*/
public interface SmsRecordDao extends CrudRepository {
-
+ /**
+ * 通过日期和手机号找到发送记录
+ *
+ * @param phone
+ * @param sendDate
+ * @return
+ */
+ List findByPhoneAndSendDate(Long phone, Integer sendDate);
}
diff --git a/austin-web/src/main/java/com/java3y/austin/web/controller/DataController.java b/austin-web/src/main/java/com/java3y/austin/web/controller/DataController.java
index 12503b7..6477ceb 100644
--- a/austin-web/src/main/java/com/java3y/austin/web/controller/DataController.java
+++ b/austin-web/src/main/java/com/java3y/austin/web/controller/DataController.java
@@ -1,12 +1,12 @@
package com.java3y.austin.web.controller;
import cn.hutool.core.util.StrUtil;
-import com.alibaba.fastjson.JSON;
import com.java3y.austin.common.enums.RespStatusEnum;
import com.java3y.austin.common.vo.BasicResultVO;
import com.java3y.austin.web.service.DataService;
import com.java3y.austin.web.vo.DataParam;
import com.java3y.austin.web.vo.amis.EchartsVo;
+import com.java3y.austin.web.vo.amis.SmsTimeLineVo;
import com.java3y.austin.web.vo.amis.UserTimeLineVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@@ -46,10 +46,16 @@ public class DataController {
return new BasicResultVO<>(RespStatusEnum.SUCCESS, echartsVo);
}
- public static void main(String[] args) {
- EchartsVo.TitleVO titleVO = EchartsVo.TitleVO.builder().text("销售情况").build();
- EchartsVo echartsVo = EchartsVo.builder().title(titleVO).build();
+ @PostMapping("/sms")
+ @ApiOperation("/获取短信下发数据")
+ public BasicResultVO getSmsData(@RequestBody DataParam dataParam) {
+ if (dataParam == null || dataParam.getDateTime() == null || dataParam.getReceiver() == null) {
+ return new BasicResultVO<>(RespStatusEnum.SUCCESS, new SmsTimeLineVo());
+ }
+
+ SmsTimeLineVo smsTimeLineVo = dataService.getTraceSmsInfo(dataParam);
- System.out.println(JSON.toJSONString(echartsVo));
+ return new BasicResultVO<>(RespStatusEnum.SUCCESS, smsTimeLineVo);
}
+
}
diff --git a/austin-web/src/main/java/com/java3y/austin/web/service/DataService.java b/austin-web/src/main/java/com/java3y/austin/web/service/DataService.java
index 86e1e8e..42b09b2 100644
--- a/austin-web/src/main/java/com/java3y/austin/web/service/DataService.java
+++ b/austin-web/src/main/java/com/java3y/austin/web/service/DataService.java
@@ -1,6 +1,8 @@
package com.java3y.austin.web.service;
+import com.java3y.austin.web.vo.DataParam;
import com.java3y.austin.web.vo.amis.EchartsVo;
+import com.java3y.austin.web.vo.amis.SmsTimeLineVo;
import com.java3y.austin.web.vo.amis.UserTimeLineVo;
/**
@@ -28,4 +30,12 @@ public interface DataService {
EchartsVo getTraceMessageTemplateInfo(String businessId);
+ /**
+ * 获取短信下发记录
+ *
+ * @param dataParam
+ * @return
+ */
+ SmsTimeLineVo getTraceSmsInfo(DataParam dataParam);
+
}
diff --git a/austin-web/src/main/java/com/java3y/austin/web/service/impl/DataServiceImpl.java b/austin-web/src/main/java/com/java3y/austin/web/service/impl/DataServiceImpl.java
index 010ddf5..15f3727 100644
--- a/austin-web/src/main/java/com/java3y/austin/web/service/impl/DataServiceImpl.java
+++ b/austin-web/src/main/java/com/java3y/austin/web/service/impl/DataServiceImpl.java
@@ -11,13 +11,18 @@ import com.java3y.austin.common.constant.AustinConstant;
import com.java3y.austin.common.domain.SimpleAnchorInfo;
import com.java3y.austin.common.enums.AnchorState;
import com.java3y.austin.common.enums.ChannelType;
+import com.java3y.austin.common.enums.SmsStatus;
import com.java3y.austin.support.dao.MessageTemplateDao;
+import com.java3y.austin.support.dao.SmsRecordDao;
import com.java3y.austin.support.domain.MessageTemplate;
+import com.java3y.austin.support.domain.SmsRecord;
import com.java3y.austin.support.utils.RedisUtils;
import com.java3y.austin.support.utils.TaskInfoUtils;
import com.java3y.austin.web.constants.AmisVoConstant;
import com.java3y.austin.web.service.DataService;
+import com.java3y.austin.web.vo.DataParam;
import com.java3y.austin.web.vo.amis.EchartsVo;
+import com.java3y.austin.web.vo.amis.SmsTimeLineVo;
import com.java3y.austin.web.vo.amis.UserTimeLineVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -39,6 +44,10 @@ public class DataServiceImpl implements DataService {
@Autowired
private MessageTemplateDao messageTemplateDao;
+ @Autowired
+ private SmsRecordDao smsRecordDao;
+
+
@Override
public UserTimeLineVo getTraceUserInfo(String receiver) {
List userInfoList = redisUtils.lRange(receiver, 0, -1);
@@ -134,6 +143,44 @@ public class DataServiceImpl implements DataService {
}
+ @Override
+ public SmsTimeLineVo getTraceSmsInfo(DataParam dataParam) {
+
+ ArrayList itemsVOS = new ArrayList<>();
+ SmsTimeLineVo smsTimeLineVo = SmsTimeLineVo.builder().items(itemsVOS).build();
+
+ Integer sendDate = Integer.valueOf(DateUtil.format(new Date(dataParam.getDateTime() * 1000L)
+ , DatePattern.PURE_DATE_PATTERN));
+ List smsRecordList = smsRecordDao.findByPhoneAndSendDate(Long.valueOf(dataParam.getReceiver()), sendDate);
+
+ if (CollUtil.isEmpty(smsRecordList)) {
+ return smsTimeLineVo;
+ }
+
+ Map> maps = smsRecordList.stream().collect(Collectors.groupingBy((o) -> o.getPhone() + o.getSeriesId()));
+
+ for (Map.Entry> entry : maps.entrySet()) {
+ SmsTimeLineVo.ItemsVO itemsVO = SmsTimeLineVo.ItemsVO.builder().build();
+ for (SmsRecord smsRecord : entry.getValue()) {
+ // 发送记录 messageTemplateId >0 ,回执记录 messageTemplateId =0
+ if (smsRecord.getMessageTemplateId() > 0) {
+ itemsVO.setBusinessId(String.valueOf(smsRecord.getMessageTemplateId()));
+ itemsVO.setContent(smsRecord.getMsgContent());
+ itemsVO.setSendType(SmsStatus.getDescriptionByStatus(smsRecord.getStatus()));
+ itemsVO.setSendTime(DateUtil.format(new Date(Long.valueOf(smsRecord.getCreated()*1000L)), DatePattern.NORM_DATETIME_PATTERN));
+
+ } else {
+ itemsVO.setReceiveType(SmsStatus.getDescriptionByStatus(smsRecord.getStatus()));
+ itemsVO.setReceiveContent(smsRecord.getReportContent());
+ itemsVO.setReceiveTime(DateUtil.format(new Date(Long.valueOf(smsRecord.getUpdated()*1000L)), DatePattern.NORM_DATETIME_PATTERN));
+ }
+ }
+ itemsVOS.add(itemsVO);
+ }
+
+ return smsTimeLineVo;
+ }
+
/**
* 如果传入的是模板ID,则生成【当天】的businessId进行查询
* 如果传入的是businessId,则按默认的businessId进行查询
@@ -150,4 +197,14 @@ public class DataServiceImpl implements DataService {
}
return businessId;
}
+
+ public static void main(String[] args) {
+
+ Long time = 1653140847 * 1000L;
+
+ String format = DateUtil.format(new Date(time), DatePattern.NORM_DATETIME_PATTERN);
+
+ System.out.println(format
+ );
+ }
}
diff --git a/austin-web/src/main/java/com/java3y/austin/web/vo/DataParam.java b/austin-web/src/main/java/com/java3y/austin/web/vo/DataParam.java
index 1f3da93..416bb29 100644
--- a/austin-web/src/main/java/com/java3y/austin/web/vo/DataParam.java
+++ b/austin-web/src/main/java/com/java3y/austin/web/vo/DataParam.java
@@ -16,8 +16,9 @@ import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
public class DataParam {
+
/**
- * 传入userId查看用户的链路信息
+ * 查看用户的链路信息
*/
private String receiver;
@@ -30,4 +31,12 @@ public class DataParam {
private String businessId;
+ /**
+ * 日期时间(检索短信的条件使用)
+ */
+ private Long dateTime;
+
+
+
+
}
diff --git a/austin-web/src/main/java/com/java3y/austin/web/vo/amis/SmsTimeLineVo.java b/austin-web/src/main/java/com/java3y/austin/web/vo/amis/SmsTimeLineVo.java
new file mode 100644
index 0000000..b008ed7
--- /dev/null
+++ b/austin-web/src/main/java/com/java3y/austin/web/vo/amis/SmsTimeLineVo.java
@@ -0,0 +1,67 @@
+package com.java3y.austin.web.vo.amis;
+
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * @author 3y
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class SmsTimeLineVo {
+
+ /**
+ * items
+ */
+ private List items;
+
+ /**
+ * ItemsVO
+ */
+ @Data
+ @Builder
+ public static class ItemsVO {
+ /**
+ * 业务ID
+ */
+ private String businessId;
+ /**
+ * detail 发送内容
+ */
+ private String content;
+
+ /**
+ * 发送状态
+ */
+ private String sendType;
+
+ /**
+ * 回执状态
+ */
+ private String receiveType;
+
+ /**
+ * 回执报告
+ */
+ private String receiveContent;
+
+ /**
+ * 发送时间
+ */
+ private String sendTime;
+
+ /**
+ * 回执时间
+ */
+ private String receiveTime;
+
+
+ }
+}
diff --git a/pom.xml b/pom.xml
index 68c2ffa..7b500bd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -81,7 +81,7 @@
com.tencentcloudapi
tencentcloud-sdk-java
- 3.1.390
+ 3.1.510