Merge branch 'master' into vip

pull/9/head
3y 3 years ago
commit 9eea4e256f

@ -1,4 +1,5 @@
![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2ccd794db76e482680f72d60959cf368~tplv-k3u1fbpfcp-zoom-1.image)
![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/108bca55a5364a73b3fd50b8bde304d1~tplv-k3u1fbpfcp-watermark.image?)
<p align="center">
<a href="#"><img src="https://img.shields.io/badge/Author-3y-orange.svg" alt="作者"></a>
@ -8,9 +9,14 @@
<a href="https://github.com/ZhongFuCheng3y/austin"><img src="https://img.shields.io/github/stars/ZhongFuCheng3y/austin.svg?style=flat&label=GithubStars"></a>
<a href="https://github.com/ZhongFuCheng3y/austin-admin"><img src="https://img.shields.io/badge/austin前端-GitHub-green.svg" alt="作者"></a>
<a href="#项目交流"><img src="https://img.shields.io/badge/项目-交流-red.svg" alt="项目交流"></a>
<a href="https://space.bilibili.com/198434865/channel/collectiondetail?sid=435119"><img src="https://img.shields.io/badge/项目-视频-green.svg" alt="Bilibili"></a>
<a href="#如何准备面试"><img src="https://img.shields.io/badge/如何准备-面试-yellow.svg" alt="对线面试官"></a>
</p>
最近我已经在**bilibili**更新Austin的视频了哟**求关注和三连**!这是我更新的动力!!
[https://space.bilibili.com/198434865/channel/collectiondetail?sid=435119](https://space.bilibili.com/198434865/channel/collectiondetail?sid=435119)
## 项目介绍
@ -56,7 +62,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 +110,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项目搭建
@ -128,12 +154,14 @@ curl -XPOST "127.0.0.1:8080/send" -H 'Content-Type: application/json' -d '{"co
- [x] 接入微信服务号渠道(已有pull request代码)
- [x] 接入微信小程序渠道(已有pull request代码)
- [x] 接入PUSH渠道
- [x] 接入云片短信渠道,并短信支持流量配置,拉取腾讯云短信回执
- [x] 完成接入钉钉机器人渠道所有类型的消息
- [ ] 总体架构已完成,持续做基础建设和优化代码
**近期更新时间**5月9
**近期更新时间**6月3
**近期更新功能**接入个推PUSH安卓发送推送消息
**近期更新功能**完成接入钉钉机器人渠道所有类型的消息
## 项目交流
@ -142,22 +170,12 @@ curl -XPOST "127.0.0.1:8080/send" -H 'Content-Type: application/json' -d '{"co
<img align="center" src='https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5eae548196934599a7cb3637aedf381d~tplv-k3u1fbpfcp-zoom-1.image' width=300px height=300px />
**Java3y**公众号在持续更新austin系列文章**保姆级**讲解搭建项目的过程(包括技术选型以及一些业务的探讨)以及相关环境的搭建。**扫下面的码直接关注,带你了解整个项目**
如果你需要用这个项目写在简历上,**强烈建议关注公众号看实现细节的思路**。如果⽂档中有任何的不懂的问题,都可以直接来找我询问,我乐意帮助你们!公众号下有我的联系方式
[会员服务](https://mp.weixin.qq.com/s?__biz=MzI4Njg5MDA5NA==&mid=2247505577&idx=1&sn=5114f8f583755899c2946fbea0b22e4b&chksm=ebd497a8dca31ebe8f98344483a00c860863dfc3586e51eed95b25988151427fee8101311f4f&token=735778370&lang=zh_CN#rd)
<img align="center" src='https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4e109cdb8d064c1e87541d7b6c17957d~tplv-k3u1fbpfcp-zoom-1.image' width=300px height=300px />
## 如何准备面试?
**对线面试官**公众号持续更新**面试系列**文章对线面试官系列深受各大开发的好评已有不少的同学通过对线面试官系列得到BATTMD等一线大厂的的offer。一个**讲人话的面试系列**,八股文不再是背诵。
![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f48cee2bbd44476f93dfcdd8aaf8a4eb~tplv-k3u1fbpfcp-watermark.image?)
![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c4a6cae132244355b9da6bd74d38d1ee~tplv-k3u1fbpfcp-zoom-1.image)
想要获取这份电子书,**点击关注**下方公众号,回复「**对线**」得到我的联系方式即可进群获取电子书

@ -38,7 +38,7 @@ public class AustinConstant {
*
* ( )
* ()
*
* ()
*/
public static final String SEND_ALL = "@all";

@ -73,4 +73,11 @@ public class SendAccountConstant {
public static final String SMS_PREFIX = "sms_";
/**
* code
*/
public static final Integer TENCENT_SMS_CODE = 10;
public static final Integer YUN_PIAN_SMS_CODE = 20;
}

@ -0,0 +1,45 @@
package com.java3y.austin.common.dto.account;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
*
*
*
* [{"sms_20":{"url":"https://sms.yunpian.com/v2/sms/tpl_batch_send.json","apikey":"ca55d4c8544444444444622221b5cd7","tpl_id":"533332222282","supplierId":20,"supplierName":"云片"}}]
*
* @author 3y
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class YunPianSmsAccount {
/**
* apikey
*/
private String apikey;
/**
* tplId
*/
private String tplId;
/**
* api
*/
private String url;
/**
* Id
*/
private Integer supplierId;
/**
*
*/
private String supplierName;
}

@ -1,38 +0,0 @@
package com.java3y.austin.common.dto.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author 3y
* +
* <p>
* https://open.dingtalk.com/document/group/custom-robot-access
* <p>
* https://open.dingtalk.com/document/orgapp-server/asynchronous-sending-of-enterprise-session-messages
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class DingDingContentModel extends ContentModel {
/**
*
*/
private String sendType;
/**
*
*/
private String content;
/**
* 使ID
*/
private String mediaId;
// ...
}

@ -0,0 +1,63 @@
package com.java3y.austin.common.dto.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author 3y
*
* <p>
* https://open.dingtalk.com/document/group/custom-robot-access
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class DingDingRobotContentModel extends ContentModel {
/**
*
*/
private String sendType;
/**
* markdownActionCard
*/
private String content;
/**
* markdownFeedCardActionCard
*/
private String title;
/**
* ActionCard
*/
private String btnOrientation;
/**
* ActionCardjson
* [{\"title\":\"别点我\",\"actionURL\":\"https://www.baidu.com/\"},{\"title\":\"没关系,还是点我把\",\"actionURL\":\"https://www.baidu.com/\\t\"}]
*/
private String btns;
/**
* URLFeedCardURL
*/
private String url;
/**
* URLFeedCardURL
*/
private String picUrl;
/**
* FeedCard
* "[{\"picUrl\":\"https://img.alicdn.com/tfs/TB1NwmBEL9TBuNjy1zbXXXpepXa-2400-1218.png\",\"title\":\"{$title1}\",\"url\":\"https://www.dingtalk.com/\"},{\"picUrl\":\"https://img.alicdn.com/tfs/TB1NwmBEL9TBuNjy1zbXXXpepXa-2400-1218.png\\t\",\"title\":\"时代的火车向前开2\",\"url\":\"https://www.dingtalk.com/\"}]"}
*/
private String feedCards;
}

@ -0,0 +1,75 @@
package com.java3y.austin.common.dto.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author 3y
*
* <p>
* https://open.dingtalk.com/document/orgapp-server/asynchronous-sending-of-enterprise-session-messages
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class DingDingWorkContentModel extends ContentModel {
/**
*
*/
private String sendType;
/**
* markdownActionCard
*/
private String content;
/**
* markdownActionCard
*/
private String title;
/**
* ActionCard
*/
private String btnOrientation;
/**
* ActionCardjson
* [{"title":"一个按钮","action_url":"https://www.taobao.com"},{"title":"两个按钮","action_url":"https://www.tmall.com"}]
*/
private String btns;
/**
* URL
*/
private String url;
/**
* 使ID
*/
private String mediaId;
/**
*
*/
private String duration;
/**
* OA
* {"bgcolor":"FFBBBBBB","text":"头部标题"}
*/
private String dingDingOaHead;
/**
* OA
* {"title":"正文标题","form":[{"key":"姓名:","value":"张三"},{"key":"年龄:","value":"20"},{"key":"身高:","value":"1.8米"},{"key":"体重:","value":"130斤"},{"key":"学历:","value":"本科"},{"key":"爱好:","value":"打球、听音乐"}],"rich":{"num":"15.6","unit":"元"},"content":"大段文本大段文本大段文本大段文本大段文本大段文本","image":"@lADOADmaWMzazQKA","file_count":"3","author":"李四 "}
*/
private String dingDingOaBody;
}

@ -24,8 +24,8 @@ public enum ChannelType {
OFFICIAL_ACCOUNT(50, "OfficialAccounts(服务号)", OfficialAccountsContentModel.class, "official_accounts"),
MINI_PROGRAM(60, "miniProgram(小程序)", MiniProgramContentModel.class, "mini_program"),
ENTERPRISE_WE_CHAT(70, "EnterpriseWeChat(企业微信)", EnterpriseWeChatContentModel.class, "enterprise_we_chat"),
DING_DING_ROBOT(80, "dingDingRobot(钉钉机器人)", DingDingContentModel.class, "ding_ding_robot"),
DING_DING_WORK_NOTICE(90, "dingDingWorkNotice(钉钉工作通知)", DingDingContentModel.class, "ding_ding_work_notice"),
DING_DING_ROBOT(80, "dingDingRobot(钉钉机器人)", DingDingRobotContentModel.class, "ding_ding_robot"),
DING_DING_WORK_NOTICE(90, "dingDingWorkNotice(钉钉工作通知)", DingDingWorkContentModel.class, "ding_ding_work_notice"),
;
/**

@ -26,6 +26,7 @@ public enum RespStatusEnum {
*/
CLIENT_BAD_PARAMETERS("A0001", "客户端参数错误"),
TEMPLATE_NOT_FOUND("A0002", "找不到模板或模板已被删除"),
TOO_MANY_RECEIVER("A0003", "传入的接收者大于100个"),
/**
*

@ -14,19 +14,64 @@ import lombok.ToString;
@AllArgsConstructor
public enum SendMessageType {
TEXT(10, "文本"),
VOICE(20, "语音"),
VIDEO(30, "视频"),
NEWS(40, "图文"),
TEXT_CARD(50, "文本卡片"),
FILE(60, "文件"),
MINI_PROGRAM_NOTICE(70, "小程序通知"),
MARKDOWN(80, "markdown"),
TEMPLATE_CARD(90, "模板卡片"),
IMAGE(100, "图片"),
TEXT("10", "文本", "text", "text"),
VOICE("20", "语音", null, "voice"),
VIDEO("30", "视频", null, null),
NEWS("40", "图文", "feedCard", null),
TEXT_CARD("50", "文本卡片", null, null),
FILE("60", "文件", null, "file"),
MINI_PROGRAM_NOTICE("70", "小程序通知", null, null),
MARKDOWN("80", "markdown", "markdown", "markdown"),
TEMPLATE_CARD("90", "模板卡片", null, null),
IMAGE("100", "图片", null, "image"),
LINK("110", "链接消息", "link", "link"),
ACTION_CARD("120", "跳转卡片消息", "actionCard", "action_card"),
OA("130", "OA消息", null, "oa"),
;
private Integer code;
private String code;
private String description;
/**
*
*/
private String dingDingRobotType;
/**
*
*/
private String dingDingWorkType;
/**
* codeType
*
* @param code
* @return
*/
public static String getDingDingRobotTypeByCode(String code) {
for (SendMessageType value : SendMessageType.values()) {
if (value.getCode().equals(code)) {
return value.getDingDingRobotType();
}
}
return null;
}
/**
* codeType
*
* @param code
* @return
*/
public static String getDingDingWorkTypeByCode(String code) {
for (SendMessageType value : SendMessageType.values()) {
if (value.getCode().equals(code)) {
return value.getDingDingWorkType();
}
}
return null;
}
}

@ -15,10 +15,26 @@ public enum SmsStatus {
SEND_SUCCESS(10,"调用渠道接口发送成功"),
RECEIVE_SUCCESS(20,"用户收到短信(收到渠道短信回执,状态成功)"),
RECEIVE_FAIL(30, "用户收不到短信(收到渠道短信回执,状态失败)");
RECEIVE_FAIL(30, "用户收不到短信(收到渠道短信回执,状态失败)"),
SEND_FAIL(40, "调用渠道接口发送失败");
private Integer code;
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 "";
}
}

@ -1,10 +1,10 @@
package com.java3y.austin.handler.deduplication.limit;
import cn.hutool.core.util.IdUtil;
import com.java3y.austin.common.domain.TaskInfo;
import com.java3y.austin.handler.deduplication.DeduplicationParam;
import com.java3y.austin.handler.deduplication.service.AbstractDeduplicationService;
import com.java3y.austin.support.utils.RedisUtils;
import com.java3y.austin.support.utils.SnowFlakeIdUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.script.DefaultRedisScript;
@ -29,7 +29,6 @@ public class SlideWindowLimitService extends AbstractLimitService {
@Autowired
private RedisUtils redisUtils;
private SnowFlakeIdUtils snowFlakeIdUtils = new SnowFlakeIdUtils(1, 1);
private DefaultRedisScript<Long> redisScript;
@ -55,7 +54,7 @@ public class SlideWindowLimitService extends AbstractLimitService {
long nowTime = System.currentTimeMillis();
for (String receiver : taskInfo.getReceiver()) {
String key = LIMIT_TAG + deduplicationSingleKey(service, taskInfo, receiver);
String scoreValue = String.valueOf(snowFlakeIdUtils.nextId());
String scoreValue = String.valueOf(IdUtil.getSnowflake().nextId());
String score = String.valueOf(nowTime);
if (redisUtils.execLimitLua(redisScript, Arrays.asList(key), String.valueOf(param.getDeduplicationTime() * 1000), score, String.valueOf(param.getCountNum()), scoreValue)) {
filterReceiver.add(receiver);

@ -90,6 +90,7 @@ public class DingDingRobotParam {
@NoArgsConstructor
@Data
@AllArgsConstructor
@Builder
public static class LinkVO {
/**
* text
@ -115,6 +116,7 @@ public class DingDingRobotParam {
@NoArgsConstructor
@Data
@AllArgsConstructor
@Builder
public static class MarkdownVO {
/**
* title
@ -132,6 +134,7 @@ public class DingDingRobotParam {
@NoArgsConstructor
@Data
@AllArgsConstructor
@Builder
public static class ActionCardVO {
/**
* title
@ -156,6 +159,7 @@ public class DingDingRobotParam {
@NoArgsConstructor
@Data
@AllArgsConstructor
@Builder
public static class BtnsVO {
/**
* title
@ -174,6 +178,7 @@ public class DingDingRobotParam {
@NoArgsConstructor
@Data
@AllArgsConstructor
@Builder
public static class FeedCardVO {
/**
* links
@ -186,6 +191,7 @@ public class DingDingRobotParam {
@NoArgsConstructor
@Data
@AllArgsConstructor
@Builder
public static class LinksVO {
/**
* title

@ -7,8 +7,10 @@ import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Set;
/**
* @author 3y
* push
*/
@NoArgsConstructor
@AllArgsConstructor
@Data

@ -0,0 +1,30 @@
package com.java3y.austin.handler.domain.sms;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
*
*
* @author 3y
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class MessageTypeSmsConfig {
/**
* ()
*/
private Integer weights;
/**
* script
*/
private String scriptName;
}

@ -28,10 +28,4 @@ public class SmsParam {
*
*/
private String content;
/**
*
*/
private Integer sendAccount;
}

@ -0,0 +1,86 @@
package com.java3y.austin.handler.domain.sms;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
*
* @author 3y
*/
@NoArgsConstructor
@Data
public class YunPianSendResult {
/**
* totalCount
*/
@JSONField(name = "total_count")
private Integer totalCount;
/**
* totalFee
*/
@JSONField(name = "total_fee")
private String totalFee;
/**
* unit
*/
@JSONField(name = "unit")
private String unit;
/**
* data
*/
@JSONField(name = "data")
private List<DataDTO> data;
/**
* DataDTO
*/
@NoArgsConstructor
@Data
public static class DataDTO {
/**
* httpStatusCode
*/
@JSONField(name = "http_status_code")
private Integer httpStatusCode;
/**
* code
*/
@JSONField(name = "code")
private Integer code;
/**
* msg
*/
@JSONField(name = "msg")
private String msg;
/**
* count
*/
@JSONField(name = "count")
private Integer count;
/**
* fee
*/
@JSONField(name = "fee")
private Integer fee;
/**
* unit
*/
@JSONField(name = "unit")
private String unit;
/**
* mobile
*/
@JSONField(name = "mobile")
private String mobile;
/**
* sid
*/
@JSONField(name = "sid")
private String sid;
}
}

@ -9,8 +9,9 @@ import com.java3y.austin.common.constant.AustinConstant;
import com.java3y.austin.common.constant.SendAccountConstant;
import com.java3y.austin.common.domain.TaskInfo;
import com.java3y.austin.common.dto.account.DingDingRobotAccount;
import com.java3y.austin.common.dto.model.DingDingContentModel;
import com.java3y.austin.common.dto.model.DingDingRobotContentModel;
import com.java3y.austin.common.enums.ChannelType;
import com.java3y.austin.common.enums.SendMessageType;
import com.java3y.austin.handler.domain.dingding.DingDingRobotParam;
import com.java3y.austin.handler.domain.dingding.DingDingRobotResult;
import com.java3y.austin.handler.handler.BaseHandler;
@ -25,6 +26,7 @@ import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
/**
*
@ -71,9 +73,31 @@ public class DingDingRobotHandler extends BaseHandler implements Handler {
}
// 消息类型以及内容相关
DingDingContentModel contentModel = (DingDingContentModel) taskInfo.getContentModel();
return DingDingRobotParam.builder().at(atVo).msgtype("text")
.text(DingDingRobotParam.TextVO.builder().content(contentModel.getContent()).build()).build();
DingDingRobotContentModel contentModel = (DingDingRobotContentModel) taskInfo.getContentModel();
DingDingRobotParam param = DingDingRobotParam.builder().at(atVo)
.msgtype(SendMessageType.getDingDingRobotTypeByCode(contentModel.getSendType()))
.build();
if (SendMessageType.TEXT.getCode().equals(contentModel.getSendType())) {
param.setText(DingDingRobotParam.TextVO.builder().content(contentModel.getContent()).build());
}
if (SendMessageType.MARKDOWN.getCode().equals(contentModel.getSendType())) {
param.setMarkdown(DingDingRobotParam.MarkdownVO.builder().title(contentModel.getTitle()).text(contentModel.getContent()).build());
}
if (SendMessageType.LINK.getCode().equals(contentModel.getSendType())) {
param.setLink(DingDingRobotParam.LinkVO.builder().title(contentModel.getTitle()).text(contentModel.getContent()).messageUrl(contentModel.getUrl()).picUrl(contentModel.getPicUrl()).build());
}
if (SendMessageType.NEWS.getCode().equals(contentModel.getSendType())) {
List<DingDingRobotParam.FeedCardVO.LinksVO> linksVOS = JSON.parseArray(contentModel.getFeedCards(), DingDingRobotParam.FeedCardVO.LinksVO.class);
DingDingRobotParam.FeedCardVO feedCardVO = DingDingRobotParam.FeedCardVO.builder().links(linksVOS).build();
param.setFeedCard(feedCardVO);
}
if (SendMessageType.ACTION_CARD.getCode().equals(contentModel.getSendType())) {
List<DingDingRobotParam.ActionCardVO.BtnsVO> btnsVOS = JSON.parseArray(contentModel.getBtns(), DingDingRobotParam.ActionCardVO.BtnsVO.class);
DingDingRobotParam.ActionCardVO actionCardVO = DingDingRobotParam.ActionCardVO.builder().title(contentModel.getTitle()).text(contentModel.getContent()).btnOrientation(contentModel.getBtnOrientation()).btns(btnsVOS).build();
param.setActionCard(actionCardVO);
}
return param;
}
/**

@ -11,8 +11,11 @@ import com.java3y.austin.common.constant.AustinConstant;
import com.java3y.austin.common.constant.SendAccountConstant;
import com.java3y.austin.common.domain.TaskInfo;
import com.java3y.austin.common.dto.account.DingDingWorkNoticeAccount;
import com.java3y.austin.common.dto.model.DingDingContentModel;
import com.java3y.austin.common.dto.model.DingDingRobotContentModel;
import com.java3y.austin.common.dto.model.DingDingWorkContentModel;
import com.java3y.austin.common.enums.ChannelType;
import com.java3y.austin.common.enums.SendMessageType;
import com.java3y.austin.handler.domain.dingding.DingDingRobotParam;
import com.java3y.austin.handler.handler.BaseHandler;
import com.java3y.austin.handler.handler.Handler;
import com.java3y.austin.support.utils.AccountUtils;
@ -22,6 +25,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.util.List;
/**
*
* <p>
@ -73,7 +78,7 @@ public class DingDingWorkNoticeHandler extends BaseHandler implements Handler {
*/
private OapiMessageCorpconversationAsyncsendV2Request assembleParam(DingDingWorkNoticeAccount account, TaskInfo taskInfo) {
OapiMessageCorpconversationAsyncsendV2Request req = new OapiMessageCorpconversationAsyncsendV2Request();
DingDingContentModel contentModel = (DingDingContentModel) taskInfo.getContentModel();
DingDingWorkContentModel contentModel = (DingDingWorkContentModel) taskInfo.getContentModel();
try {
// 接收者相关
if (AustinConstant.SEND_ALL.equals(CollUtil.getFirst(taskInfo.getReceiver()))) {
@ -83,13 +88,64 @@ public class DingDingWorkNoticeHandler extends BaseHandler implements Handler {
}
req.setAgentId(Long.parseLong(account.getAgentId()));
// 内容相关
OapiMessageCorpconversationAsyncsendV2Request.Msg message = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
message.setMsgtype("text");
OapiMessageCorpconversationAsyncsendV2Request.Text textObj = new OapiMessageCorpconversationAsyncsendV2Request.Text();
textObj.setContent(contentModel.getContent());
message.setText(textObj);
message.setMsgtype(SendMessageType.getDingDingWorkTypeByCode(contentModel.getSendType()));
// 根据类型设置入参
if (SendMessageType.TEXT.getCode().equals(contentModel.getSendType())) {
OapiMessageCorpconversationAsyncsendV2Request.Text textObj = new OapiMessageCorpconversationAsyncsendV2Request.Text();
textObj.setContent(contentModel.getContent());
message.setText(textObj);
}
if (SendMessageType.IMAGE.getCode().equals(contentModel.getSendType())) {
OapiMessageCorpconversationAsyncsendV2Request.Image image = new OapiMessageCorpconversationAsyncsendV2Request.Image();
image.setMediaId(contentModel.getMediaId());
message.setImage(image);
}
if (SendMessageType.VOICE.getCode().equals(contentModel.getSendType())) {
OapiMessageCorpconversationAsyncsendV2Request.Voice voice = new OapiMessageCorpconversationAsyncsendV2Request.Voice();
voice.setMediaId(contentModel.getMediaId());
voice.setDuration(contentModel.getDuration());
message.setVoice(voice);
}
if (SendMessageType.FILE.getCode().equals(contentModel.getSendType())) {
OapiMessageCorpconversationAsyncsendV2Request.File file = new OapiMessageCorpconversationAsyncsendV2Request.File();
file.setMediaId(contentModel.getMediaId());
message.setFile(file);
}
if (SendMessageType.LINK.getCode().equals(contentModel.getSendType())) {
OapiMessageCorpconversationAsyncsendV2Request.Link link = new OapiMessageCorpconversationAsyncsendV2Request.Link();
link.setText(contentModel.getContent());
link.setTitle(contentModel.getTitle());
link.setPicUrl(contentModel.getMediaId());
link.setMessageUrl(contentModel.getUrl());
message.setLink(link);
}
if (SendMessageType.MARKDOWN.getCode().equals(contentModel.getSendType())) {
OapiMessageCorpconversationAsyncsendV2Request.Markdown markdown = new OapiMessageCorpconversationAsyncsendV2Request.Markdown();
markdown.setText(contentModel.getContent());
markdown.setTitle(contentModel.getTitle());
message.setMarkdown(markdown);
}
if (SendMessageType.ACTION_CARD.getCode().equals(contentModel.getSendType())) {
OapiMessageCorpconversationAsyncsendV2Request.ActionCard actionCard = new OapiMessageCorpconversationAsyncsendV2Request.ActionCard();
actionCard.setTitle(contentModel.getTitle());
actionCard.setMarkdown(contentModel.getContent());
actionCard.setBtnOrientation(contentModel.getBtnOrientation());
actionCard.setBtnJsonList(JSON.parseArray(contentModel.getBtns(), OapiMessageCorpconversationAsyncsendV2Request.BtnJsonList.class));
message.setActionCard(actionCard);
}
if (SendMessageType.OA.getCode().equals(contentModel.getSendType())) {
OapiMessageCorpconversationAsyncsendV2Request.OA oa = new OapiMessageCorpconversationAsyncsendV2Request.OA();
oa.setMessageUrl(contentModel.getUrl());
oa.setHead(JSON.parseObject(contentModel.getDingDingOaHead(), OapiMessageCorpconversationAsyncsendV2Request.Head.class));
oa.setBody(JSON.parseObject(contentModel.getDingDingOaBody(), OapiMessageCorpconversationAsyncsendV2Request.Body.class));
message.setOa(oa);
}
req.setMsg(message);
} catch (Exception e) {
log.error("assembleParam fail:{},params:{}", Throwables.getStackTraceAsString(e), JSON.toJSONString(taskInfo));

@ -4,14 +4,11 @@ import com.alibaba.fastjson.JSON;
import com.google.common.base.Throwables;
import com.java3y.austin.common.domain.TaskInfo;
import com.java3y.austin.common.dto.model.MiniProgramContentModel;
import com.java3y.austin.common.dto.model.OfficialAccountsContentModel;
import com.java3y.austin.common.enums.ChannelType;
import com.java3y.austin.handler.domain.wechat.WeChatMiniProgramParam;
import com.java3y.austin.handler.domain.wechat.WeChatOfficialParam;
import com.java3y.austin.handler.handler.BaseHandler;
import com.java3y.austin.handler.handler.Handler;
import com.java3y.austin.handler.script.MiniProgramAccountService;
import com.java3y.austin.handler.script.OfficialAccountService;
import com.java3y.austin.handler.wechat.MiniProgramAccountService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@ -8,7 +8,7 @@ import com.java3y.austin.common.enums.ChannelType;
import com.java3y.austin.handler.domain.wechat.WeChatOfficialParam;
import com.java3y.austin.handler.handler.BaseHandler;
import com.java3y.austin.handler.handler.Handler;
import com.java3y.austin.handler.script.OfficialAccountService;
import com.java3y.austin.handler.wechat.OfficialAccountService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@ -3,14 +3,19 @@ package com.java3y.austin.handler.handler.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfig;
import com.google.common.base.Throwables;
import com.java3y.austin.common.constant.AustinConstant;
import com.java3y.austin.common.domain.TaskInfo;
import com.java3y.austin.common.dto.model.SmsContentModel;
import com.java3y.austin.common.enums.ChannelType;
import com.java3y.austin.handler.domain.sms.MessageTypeSmsConfig;
import com.java3y.austin.handler.domain.sms.SmsParam;
import com.java3y.austin.handler.handler.BaseHandler;
import com.java3y.austin.handler.handler.Handler;
import com.java3y.austin.handler.script.SmsScript;
import com.java3y.austin.handler.script.SmsScriptHolder;
import com.java3y.austin.support.dao.SmsRecordDao;
import com.java3y.austin.support.domain.SmsRecord;
import lombok.extern.slf4j.Slf4j;
@ -18,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Random;
/**
*
@ -36,7 +42,10 @@ public class SmsHandler extends BaseHandler implements Handler {
private SmsRecordDao smsRecordDao;
@Autowired
private SmsScript smsScript;
private SmsScriptHolder smsScriptHolder;
@ApolloConfig("boss.austin")
private Config config;
@Override
@ -45,14 +54,20 @@ public class SmsHandler extends BaseHandler implements Handler {
.phones(taskInfo.getReceiver())
.content(getSmsContent(taskInfo))
.messageTemplateId(taskInfo.getMessageTemplateId())
.sendAccount(taskInfo.getSendAccount())
.build();
try {
List<SmsRecord> recordList = smsScript.send(smsParam);
if (!CollUtil.isEmpty(recordList)) {
smsRecordDao.saveAll(recordList);
/**
* 1
* 2
*/
MessageTypeSmsConfig[] messageTypeSmsConfigs = loadBalance(getMessageTypeSmsConfig(taskInfo.getMsgType()));
for (MessageTypeSmsConfig messageTypeSmsConfig : messageTypeSmsConfigs) {
List<SmsRecord> recordList = smsScriptHolder.route(messageTypeSmsConfig.getScriptName()).send(smsParam);
if (CollUtil.isNotEmpty(recordList)) {
smsRecordDao.saveAll(recordList);
return true;
}
}
return true;
} catch (Exception e) {
log.error("SmsHandler#handler fail:{},params:{}",
Throwables.getStackTraceAsString(e), JSON.toJSONString(smsParam));
@ -60,6 +75,72 @@ public class SmsHandler extends BaseHandler implements Handler {
return false;
}
/**
*
*
*
* @param messageTypeSmsConfigs
*/
private MessageTypeSmsConfig[] loadBalance(List<MessageTypeSmsConfig> messageTypeSmsConfigs) {
int total = 0;
for (MessageTypeSmsConfig channelConfig : messageTypeSmsConfigs) {
total += channelConfig.getWeights();
}
// 生成一个随机数[1,total],看落到哪个区间
Random random = new Random();
int index = random.nextInt(total) + 1;
MessageTypeSmsConfig supplier = null;
MessageTypeSmsConfig supplierBack = null;
for (int i = 0; i < messageTypeSmsConfigs.size(); ++i) {
if (index <= messageTypeSmsConfigs.get(i).getWeights()) {
supplier = messageTypeSmsConfigs.get(i);
// 取下一个供应商
int j = (i + 1) % messageTypeSmsConfigs.size();
if (i == j) {
return new MessageTypeSmsConfig[]{supplier};
}
supplierBack = messageTypeSmsConfigs.get(j);
return new MessageTypeSmsConfig[]{supplier, supplierBack};
}
index -= messageTypeSmsConfigs.get(i).getWeights();
}
return null;
}
/**
* ()
* <p>
*
* keymsg_type_sms_config
* value[{"message_type_10":[{"weights":80,"scriptName":"TencentSmsScript"},{"weights":20,"scriptName":"YunPianSmsScript"}]},{"message_type_20":[{"weights":20,"scriptName":"YunPianSmsScript"}]},{"message_type_30":[{"weights":20,"scriptName":"TencentSmsScript"}]},{"message_type_40":[{"weights":20,"scriptName":"TencentSmsScript"}]}]
* TencentSmsScript 80%YunPianSmsScript20%
* YunPianSmsScript
* TencentSmsScript
*
* @param msgType
* @return
*/
private List<MessageTypeSmsConfig> getMessageTypeSmsConfig(Integer msgType) {
String apolloKey = "msg_type_sms_config";
String messagePrefix = "message_type_";
String property = config.getProperty(apolloKey, AustinConstant.APOLLO_DEFAULT_VALUE_JSON_ARRAY);
JSONArray jsonArray = JSON.parseArray(property);
for (int i = 0; i < jsonArray.size(); i++) {
JSONArray array = jsonArray.getJSONObject(i).getJSONArray(messagePrefix + msgType);
if (CollUtil.isNotEmpty(array)) {
List<MessageTypeSmsConfig> result = JSON.parseArray(JSON.toJSONString(array), MessageTypeSmsConfig.class);
return result;
}
}
return null;
}
/**
*
* <p>

@ -0,0 +1,57 @@
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.domain.SmsRecord;
import com.tencentcloudapi.sms.v20210111.SmsClient;
import com.tencentcloudapi.sms.v20210111.models.PullSmsSendStatus;
import com.tencentcloudapi.sms.v20210111.models.PullSmsSendStatusRequest;
import com.tencentcloudapi.sms.v20210111.models.PullSmsSendStatusResponse;
import lombok.extern.slf4j.Slf4j;
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 SmsReceipt {
@Autowired
private TencentSmsReceipt tencentSmsReceipt;
@Autowired
private YunPianSmsReceipt yunPianSmsReceipt;
@PostConstruct
private void init() {
SupportThreadPoolConfig.getPendingSingleThreadPool().execute(() -> {
while (true) {
// TODO 回执这里自行打开(免得报错)
// tencentSmsReceipt.pull();
// yunPianSmsReceipt.pull();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
}
});
}
}

@ -0,0 +1,108 @@
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.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.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;
/**
*
*/
public void pull() {
// 获取腾讯云账号信息
TencentSmsAccount account = accountUtils.getAccount(10, SendAccountConstant.SMS_ACCOUNT_KEY, SendAccountConstant.SMS_PREFIX, TencentSmsAccount.class);
try {
SmsClient client = getSmsClient(account);
// 每次拉取10条
PullSmsSendStatusRequest req = new PullSmsSendStatusRequest();
req.setLimit(10L);
req.setSmsSdkAppId(account.getSmsSdkAppId());
PullSmsSendStatusResponse resp = client.PullSmsSendStatus(req);
List<SmsRecord> 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);
}
} 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);
}
}

@ -0,0 +1,25 @@
package com.java3y.austin.handler.receipt;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
*
*
* @author 3y
*/
@Component
@Slf4j
public class YunPianSmsReceipt {
/**
*
*/
public void pull() {
}
}

@ -0,0 +1,42 @@
package com.java3y.austin.handler.script;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.PostConstruct;
import java.lang.annotation.Annotation;
/**
* sms
*
* @author 3y
*/
@Slf4j
public abstract class BaseSmsScript implements SmsScript {
@Autowired
private SmsScriptHolder smsScriptHolder;
@PostConstruct
public void registerProcessScript() {
if (ArrayUtils.isEmpty(this.getClass().getAnnotations())) {
log.error("BaseSmsScript can not find annotation!");
return;
}
Annotation handlerAnnotations = null;
for (Annotation annotation : this.getClass().getAnnotations()) {
if (annotation instanceof SmsScriptHandler) {
handlerAnnotations = annotation;
break;
}
}
if (handlerAnnotations == null) {
log.error("handler annotations not declared");
return;
}
//注册handler
smsScriptHolder.putHandler(((SmsScriptHandler) handlerAnnotations).value(), this);
}
}

@ -17,8 +17,8 @@ public interface SmsScript {
*
* @param smsParam
* @return
* @throws Exception
*/
List<SmsRecord> send(SmsParam smsParam) throws Exception;
List<SmsRecord> send(SmsParam smsParam);
}

@ -0,0 +1,27 @@
package com.java3y.austin.handler.script;
import org.springframework.stereotype.Component;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
*
* @author 3y
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Component
public @interface SmsScriptHandler {
/**
*
*
* @return
*/
String value();
}

@ -0,0 +1,25 @@
package com.java3y.austin.handler.script;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* sendAccount->SmsScript
*
* @author 3y
*/
@Component
public class SmsScriptHolder {
private Map<String, SmsScript> handlers = new HashMap<>(8);
public void putHandler(String scriptName, SmsScript handler) {
handlers.put(scriptName, handler);
}
public SmsScript route(String scriptName) {
return handlers.get(scriptName);
}
}

@ -4,11 +4,15 @@ import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.IdUtil;
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.handler.domain.sms.SmsParam;
import com.java3y.austin.common.dto.account.TencentSmsAccount;
import com.java3y.austin.handler.script.BaseSmsScript;
import com.java3y.austin.handler.script.SmsScript;
import com.java3y.austin.handler.script.SmsScriptHandler;
import com.java3y.austin.support.domain.SmsRecord;
import com.java3y.austin.support.utils.AccountUtils;
import com.tencentcloudapi.common.Credential;
@ -20,7 +24,6 @@ import com.tencentcloudapi.sms.v20210111.models.SendSmsResponse;
import com.tencentcloudapi.sms.v20210111.models.SendStatus;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Date;
@ -33,9 +36,10 @@ import java.util.List;
* 2. 使SDK
* 3. 使API Explorer
*/
@Service
@Slf4j
public class TencentSmsScript implements SmsScript {
@SmsScriptHandler("TencentSmsScript")
public class TencentSmsScript extends BaseSmsScript implements SmsScript {
private static final Integer PHONE_NUM = 11;
@ -43,12 +47,17 @@ public class TencentSmsScript implements SmsScript {
private AccountUtils accountUtils;
@Override
public List<SmsRecord> send(SmsParam smsParam) throws Exception {
TencentSmsAccount tencentSmsAccount = accountUtils.getAccount(smsParam.getSendAccount(), SendAccountConstant.SMS_ACCOUNT_KEY, SendAccountConstant.SMS_PREFIX, TencentSmsAccount.class);
SmsClient client = init(tencentSmsAccount);
SendSmsRequest request = assembleReq(smsParam, tencentSmsAccount);
SendSmsResponse response = client.SendSms(request);
return assembleSmsRecord(smsParam, response, tencentSmsAccount);
public List<SmsRecord> send(SmsParam smsParam) {
try {
TencentSmsAccount tencentSmsAccount = accountUtils.getAccount(SendAccountConstant.TENCENT_SMS_CODE, SendAccountConstant.SMS_ACCOUNT_KEY, SendAccountConstant.SMS_PREFIX, TencentSmsAccount.class);
SmsClient client = init(tencentSmsAccount);
SendSmsRequest request = assembleReq(smsParam, tencentSmsAccount);
SendSmsResponse response = client.SendSms(request);
return assembleSmsRecord(smsParam, response, tencentSmsAccount);
} catch (Exception e) {
log.error("TencentSmsScript#send fail:{},params:{}", Throwables.getStackTraceAsString(e), JSON.toJSONString(smsParam));
return null;
}
}

@ -0,0 +1,108 @@
package com.java3y.austin.handler.script.impl;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
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.YunPianSmsAccount;
import com.java3y.austin.common.enums.SmsStatus;
import com.java3y.austin.handler.domain.sms.SmsParam;
import com.java3y.austin.handler.domain.sms.YunPianSendResult;
import com.java3y.austin.handler.script.BaseSmsScript;
import com.java3y.austin.handler.script.SmsScript;
import com.java3y.austin.handler.script.SmsScriptHandler;
import com.java3y.austin.support.domain.SmsRecord;
import com.java3y.austin.support.utils.AccountUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.*;
/**
* @author 3y
* @date 2022523
* https://www.yunpian.com/official/document/sms/zh_CN/domestic_list
*/
@Slf4j
@SmsScriptHandler("YunPianSmsScript")
public class YunPianSmsScript extends BaseSmsScript implements SmsScript {
@Autowired
private AccountUtils accountUtils;
@Override
public List<SmsRecord> send(SmsParam smsParam) {
try {
YunPianSmsAccount account = accountUtils.getAccount(SendAccountConstant.YUN_PIAN_SMS_CODE, SendAccountConstant.SMS_ACCOUNT_KEY, SendAccountConstant.SMS_PREFIX, YunPianSmsAccount.class);
Map<String, Object> params = assembleParam(smsParam, account);
String result = HttpRequest.post(account.getUrl())
.header(Header.CONTENT_TYPE.getValue(), "application/x-www-form-urlencoded;charset=utf-8;")
.header(Header.ACCEPT.getValue(), "application/json;charset=utf-8;")
.form(params)
.timeout(2000)
.execute().body();
YunPianSendResult yunPianSendResult = JSON.parseObject(result, YunPianSendResult.class);
return assembleSmsRecord(smsParam, yunPianSendResult, account);
} catch (Exception e) {
log.error("YunPianSmsScript#send fail:{},params:{}", Throwables.getStackTraceAsString(e), JSON.toJSONString(smsParam));
return null;
}
}
/**
*
*
* @param smsParam
* @param account
* @return
*/
private Map<String, Object> assembleParam(SmsParam smsParam, YunPianSmsAccount account) {
Map<String, Object> params = new HashMap<>(8);
params.put("apikey", account.getApikey());
params.put("mobile", StringUtils.join(smsParam.getPhones(), StrUtil.C_COMMA));
params.put("tpl_id", account.getTplId());
params.put("tpl_value", "");
return params;
}
private List<SmsRecord> assembleSmsRecord(SmsParam smsParam, YunPianSendResult response, YunPianSmsAccount account) {
if (response == null || ArrayUtil.isEmpty(response.getData())) {
return null;
}
List<SmsRecord> smsRecordList = new ArrayList<>();
for (YunPianSendResult.DataDTO datum : response.getData()) {
SmsRecord smsRecord = SmsRecord.builder()
.sendDate(Integer.valueOf(DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)))
.messageTemplateId(smsParam.getMessageTemplateId())
.phone(Long.valueOf(datum.getMobile()))
.supplierId(account.getSupplierId())
.supplierName(account.getSupplierName())
.msgContent(smsParam.getContent())
.seriesId(datum.getSid())
.chargingNum(Math.toIntExact(datum.getCount()))
.status("0".equals(datum.getCode()) ? SmsStatus.SEND_SUCCESS.getCode() : SmsStatus.SEND_FAIL.getCode())
.reportContent(datum.getMsg())
.created(Math.toIntExact(DateUtil.currentSeconds()))
.updated(Math.toIntExact(DateUtil.currentSeconds()))
.build();
smsRecordList.add(smsRecord);
}
return smsRecordList;
}
}

@ -1,4 +1,4 @@
package com.java3y.austin.handler.script;
package com.java3y.austin.handler.wechat;
import com.java3y.austin.handler.domain.wechat.WeChatMiniProgramParam;

@ -1,4 +1,4 @@
package com.java3y.austin.handler.script;
package com.java3y.austin.handler.wechat;
import com.java3y.austin.handler.domain.wechat.WeChatOfficialParam;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;

@ -1,4 +1,4 @@
package com.java3y.austin.handler.script.impl;
package com.java3y.austin.handler.wechat.impl;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.WxMaSubscribeService;
@ -9,7 +9,7 @@ import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import com.java3y.austin.common.constant.SendAccountConstant;
import com.java3y.austin.common.dto.account.WeChatMiniProgramAccount;
import com.java3y.austin.handler.domain.wechat.WeChatMiniProgramParam;
import com.java3y.austin.handler.script.MiniProgramAccountService;
import com.java3y.austin.handler.wechat.MiniProgramAccountService;
import com.java3y.austin.support.utils.AccountUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

@ -1,9 +1,9 @@
package com.java3y.austin.handler.script.impl;
package com.java3y.austin.handler.wechat.impl;
import com.java3y.austin.common.constant.SendAccountConstant;
import com.java3y.austin.common.dto.account.WeChatOfficialAccount;
import com.java3y.austin.handler.domain.wechat.WeChatOfficialParam;
import com.java3y.austin.handler.script.OfficialAccountService;
import com.java3y.austin.handler.wechat.OfficialAccountService;
import com.java3y.austin.support.utils.AccountUtils;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.mp.api.WxMpService;

@ -5,7 +5,6 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReUtil;
import com.alibaba.fastjson.JSON;
import com.java3y.austin.common.domain.TaskInfo;
import com.java3y.austin.common.enums.ChannelType;
import com.java3y.austin.common.enums.IdType;
import com.java3y.austin.common.enums.RespStatusEnum;
import com.java3y.austin.common.vo.BasicResultVO;
@ -15,6 +14,7 @@ import com.java3y.austin.support.pipeline.ProcessContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
@ -29,18 +29,23 @@ import java.util.stream.Collectors;
@Service
public class AfterParamCheckAction implements BusinessProcess<SendTaskModel> {
public static final String PHONE_REGEX_EXP = "^((13[0-9])|(14[5,7,9])|(15[0-3,5-9])|(166)|(17[0-9])|(18[0-9])|(19[1,8,9]))\\d{8}$";
public static final String EMAIL_REGEX_EXP = "^[A-Za-z0-9-_\\u4e00-\\u9fa5]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$";
public static final HashMap<Integer, String> CHANNEL_REGEX_EXP = new HashMap<>();
static {
CHANNEL_REGEX_EXP.put(IdType.PHONE.getCode(), PHONE_REGEX_EXP);
CHANNEL_REGEX_EXP.put(IdType.EMAIL.getCode(), EMAIL_REGEX_EXP);
}
@Override
public void process(ProcessContext<SendTaskModel> context) {
SendTaskModel sendTaskModel = context.getProcessModel();
List<TaskInfo> taskInfo = sendTaskModel.getTaskInfo();
// 1. 过滤掉不合法的手机号
filterIllegalPhoneNum(taskInfo);
// 2.
// 1. 过滤掉不合法的手机号、邮件
filterIllegalReceiver(taskInfo);
if (CollUtil.isEmpty(taskInfo)) {
context.setNeedBreak(true).setResponse(BasicResultVO.fail(RespStatusEnum.CLIENT_BAD_PARAMETERS));
@ -48,31 +53,35 @@ public class AfterParamCheckAction implements BusinessProcess<SendTaskModel> {
}
/**
*
*
*
*
* @param taskInfo
*/
private void filterIllegalPhoneNum(List<TaskInfo> taskInfo) {
private void filterIllegalReceiver(List<TaskInfo> taskInfo) {
Integer idType = CollUtil.getFirst(taskInfo.iterator()).getIdType();
Integer sendChannel = CollUtil.getFirst(taskInfo.iterator()).getSendChannel();
if (IdType.PHONE.getCode().equals(idType) && ChannelType.SMS.getCode().equals(sendChannel)) {
Iterator<TaskInfo> iterator = taskInfo.iterator();
filter(taskInfo, CHANNEL_REGEX_EXP.get(idType));
}
// 利用正则找出不合法的手机号
while (iterator.hasNext()) {
TaskInfo task = iterator.next();
Set<String> illegalPhone = task.getReceiver().stream()
.filter(phone -> !ReUtil.isMatch(PHONE_REGEX_EXP, phone))
.collect(Collectors.toSet());
/**
*
*
* @param taskInfo
* @param regexExp
*/
private void filter(List<TaskInfo> taskInfo, String regexExp) {
Iterator<TaskInfo> iterator = taskInfo.iterator();
while (iterator.hasNext()) {
TaskInfo task = iterator.next();
Set<String> illegalPhone = task.getReceiver().stream()
.filter(phone -> !ReUtil.isMatch(regexExp, phone))
.collect(Collectors.toSet());
if (CollUtil.isNotEmpty(illegalPhone)) {
task.getReceiver().removeAll(illegalPhone);
log.error("messageTemplateId:{} find illegal phone!{}", task.getMessageTemplateId(), JSON.toJSONString(illegalPhone));
}
if (CollUtil.isEmpty(task.getReceiver())) {
iterator.remove();
}
if (CollUtil.isNotEmpty(illegalPhone)) {
task.getReceiver().removeAll(illegalPhone);
log.error("messageTemplateId:{} find illegal receiver!{}", task.getMessageTemplateId(), JSON.toJSONString(illegalPhone));
}
if (CollUtil.isEmpty(task.getReceiver())) {
iterator.remove();
}
}
}

@ -11,6 +11,7 @@ import com.java3y.austin.support.pipeline.ProcessContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@ -23,6 +24,11 @@ import java.util.stream.Collectors;
@Service
public class PreParamCheckAction implements BusinessProcess<SendTaskModel> {
/**
*
*/
private static final Integer BATCH_RECEIVER_SIZE = 100;
@Override
public void process(ProcessContext<SendTaskModel> context) {
SendTaskModel sendTaskModel = context.getProcessModel();
@ -30,13 +36,13 @@ public class PreParamCheckAction implements BusinessProcess<SendTaskModel> {
Long messageTemplateId = sendTaskModel.getMessageTemplateId();
List<MessageParam> messageParamList = sendTaskModel.getMessageParamList();
// 没有传入 消息模板Id 或者 messageParam
// 1.没有传入 消息模板Id 或者 messageParam
if (messageTemplateId == null || CollUtil.isEmpty(messageParamList)) {
context.setNeedBreak(true).setResponse(BasicResultVO.fail(RespStatusEnum.CLIENT_BAD_PARAMETERS));
return;
}
// 过滤 receiver=null 的messageParam
// 2.过滤 receiver=null 的messageParam
List<MessageParam> resultMessageParamList = messageParamList.stream()
.filter(messageParam -> !StrUtil.isBlank(messageParam.getReceiver()))
.collect(Collectors.toList());
@ -44,7 +50,13 @@ public class PreParamCheckAction implements BusinessProcess<SendTaskModel> {
context.setNeedBreak(true).setResponse(BasicResultVO.fail(RespStatusEnum.CLIENT_BAD_PARAMETERS));
return;
}
sendTaskModel.setMessageParamList(resultMessageParamList);
// 3.过滤receiver大于100的请求
if (messageParamList.stream().anyMatch(messageParam -> messageParam.getReceiver().split(StrUtil.COMMA).length > BATCH_RECEIVER_SIZE)) {
context.setNeedBreak(true).setResponse(BasicResultVO.fail(RespStatusEnum.TOO_MANY_RECEIVER));
return;
}
}
}

@ -23,6 +23,7 @@ public class MessageParam {
/**
* @Description:
* ,
* 100
*
*/
private String receiver;

@ -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<SmsRecord, Long> {
/**
*
*
* @param phone
* @param sendDate
* @return
*/
List<SmsRecord> findByPhoneAndSendDate(Long phone, Integer sendDate);
}

@ -21,13 +21,13 @@ public class AccountUtils {
private Config config;
/**
* (key:smsAccount)[{"sms_10":{"url":"sms.tencentcloudapi.com","region":"ap-guangzhou","secretId":"AKIDhDUUDfffffMEqBF1WljQq","secretKey":"B4h39yWnfffff7D2btue7JErDJ8gxyi","smsSdkAppId":"140025","templateId":"11897","signName":"Java3y公众号","supplierId":10,"supplierName":"腾讯云"}}]
* (key:emailAccount)[{"email_10":{"host":"smtp.qq.com","port":465,"user":"403686131@qq.com","pass":"","from":"403686131@qq.com"}}]
* (key:enterpriseWechatAccount)[{"enterprise_wechat_10":{"corpId":"wwf87603333e00069c","corpSecret":"-IFWxS2222QxzPIorNVUQn144444D915DM","agentId":10044442,"token":"rXROB3333Kf6i","aesKey":"MKZtoFxHIM44444M7ieag3r9ZPUsl"}}]
* (key:dingDingRobotAccount) [{"ding_ding_robot_10":{"secret":"SEC996d8d9d4768aded74114faae924f229229de444475a1c295d64fedf","webhook":"https://oapi.dingtalk.com/robot/send?access_token=8d03b644ffb6534b203d87333367328b0c3003d164715d2c6c6e56"}}]
* (key:dingDingWorkNoticeAccount) [{"ding_ding_work_notice_10":{"appKey":"dingh6yyyyyyycrlbx","appSecret":"tQpvmkR863333yyyyyHP3QHyyyymy9Ao1yoL1oQX5Nlx_fYLLLlpPJWHvWKbTu","agentId":"152333383622"}}]
* (key:officialAccount) [{"official_10":{"appId":"wxecb4693d2eef1ea7","secret":"6240870f4d91701640d769ba20120821","templateId":"JHUk6eE9T5Ts7a5JO3ZQqkBBrZBGn5C9iIiKNDQsk-Q","url":"http://weixin.qq.com/download","miniProgramId":"xiaochengxuappid12345","path":"index?foo=bar"}}]
* (key:miniProgramAccount) [{"mini_program_10":{"appId":"wxecb4693d2eef1ea7","appSecret":"6240870f4d91701640d769ba20120821","templateId":"JHUk6eE9T5Ts7a5JO3ZQqkBBrZBGn5C9iIiKNDQsk-Q","grantType":"client_credential","miniProgramState":"trial","page":"index?foo=bar"}}]
* (key:smsAccount)[{"sms_10":{"url":"sms.tencentcloudapi.com","region":"ap-guangzhou","secretId":"AKIDhDxxxxxxxx1WljQq","secretKey":"B4hwww39yxxxrrrrgxyi","smsSdkAppId":"1423123125","templateId":"1182097","signName":"Java3y公众号","supplierId":10,"supplierName":"腾讯云"}},{"sms_20":{"url":"https://sms.yunpian.com/v2/sms/tpl_batch_send.json","apikey":"caffff8234234231b5cd7","tpl_id":"523333332","supplierId":20,"supplierName":"云片"}}]
* (key:emailAccount)[{"email_10":{"host":"smtp.qq.com","port":465,"user":"4032222131@qq.com","pass":"","from":"4036333131@qq.com"}}]
* (key:enterpriseWechatAccount)[{"enterprise_wechat_10":{"corpId":"wwf87603333e00069c","corpSecret":"-IFWxS2222QxzPIorNV11144D915DM","agentId":10044442,"token":"rXROB3333Kf6i","aesKey":"MKZtoFxHIM44444M7ieag3r9ZPUsl"}}]
* (key:dingDingRobotAccount) [{"ding_ding_robot_10":{"secret":"SEC9222d4768aded74114faae92229de422222fedf","webhook":"https://oapi.dingtalk.com/robot/send?access_token=8d03b6442222203d87333367328b0c3003d164715d2c6c6e56"}}]
* (key:dingDingWorkNoticeAccount) [{"ding_ding_work_notice_10":{"appKey":"dingh6yyyyyyycrlbx","appSecret":"tQpvmkR863333yyyyyHP3QHyyyymy9Ao1yoL1oQX5NsdfsWHvWKbTu","agentId":"1523123123183622"}}]
* (key:officialAccount) [{"official_10":{"appId":"wxecb4693d2eef1ea7","secret":"624asdfsa1640d769ba20120821","templateId":"JHUk6eE9T5Ts7asdfsadfiKNDQsk-Q","url":"http://weixin.qq.com/download","miniProgramId":"xiaochengxuappid12345","path":"index?foo=bar"}}]
* (key:miniProgramAccount) [{"mini_program_10":{"appId":"wxecb4693d2eef1ea7","appSecret":"6240870f4d91701640d769ba20120821","templateId":"JHUk6eE9T5TasdfCrQsk-Q","grantType":"client_credential","miniProgramState":"trial","page":"index?foo=bar"}}]
*/
public <T> T getAccount(Integer sendAccount, String apolloKey, String prefix, Class<T> clazz) {
String accountValues = config.getProperty(apolloKey, AustinConstant.APOLLO_DEFAULT_VALUE_JSON_ARRAY);
@ -42,4 +42,7 @@ public class AccountUtils {
return null;
}
}

@ -1,108 +0,0 @@
package com.java3y.austin.support.utils;
/**
* id
*
* @author cao
* @date 2022-04-20 13:12
*/
public class SnowFlakeIdUtils {
/**
* (2017-01-01)
*/
private final static long START_TIMESTAMP = 1483200000000L;
/**
*
*/
private final static long SEQUENCE_BIT = 12; //***占用的位数
private final static long MACHINE_BIT = 5; //机器标识占用的位数
private final static long DATA_CENTER_BIT = 5; //数据中心占用的位数
/**
*
*/
private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);
private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
private final static long MAX_DATA_CENTER_NUM = -1L ^ (-1L << DATA_CENTER_BIT);
/**
*
*/
private final static long MACHINE_LEFT = SEQUENCE_BIT;
private final static long DATA_CENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
private final static long TIMESTAMP_LEFT = DATA_CENTER_LEFT + DATA_CENTER_BIT;
private long dataCenterId; //数据中心
private long machineId; //机器标识
private long sequence = 0L; //***
private long lastTimeStamp = -1L; //上一次时间戳
/**
* IDID***
*
* @param dataCenterId ID
* @param machineId ID
*/
public SnowFlakeIdUtils(long dataCenterId, long machineId) {
if (dataCenterId > MAX_DATA_CENTER_NUM || dataCenterId < 0) {
throw new IllegalArgumentException(String.format("DtaCenterId 不能大于 %d 或小于 0", MAX_DATA_CENTER_NUM));
}
if (machineId > MAX_MACHINE_NUM || machineId < 0) {
throw new IllegalArgumentException(String.format("MachineId 不能大于 %d 或小于 0", MAX_MACHINE_NUM));
}
this.dataCenterId = dataCenterId;
this.machineId = machineId;
}
/**
* ID
*
* @return
*/
public synchronized long nextId() {
long currTimeStamp = System.currentTimeMillis();
if (currTimeStamp < lastTimeStamp) {
throw new RuntimeException("当前时间小于上一次记录的时间戳!");
}
if (currTimeStamp == lastTimeStamp) {
//相同毫秒内,***自增
sequence = (sequence + 1) & MAX_SEQUENCE;
//同一毫秒的序列数已经达到最大
if (sequence == 0L) {
currTimeStamp = getNextMill();
}
} else {
//不同毫秒内,***置为0
sequence = 0L;
}
lastTimeStamp = currTimeStamp;
return (currTimeStamp - START_TIMESTAMP) << TIMESTAMP_LEFT //时间戳部分
| dataCenterId << DATA_CENTER_LEFT //数据中心部分
| machineId << MACHINE_LEFT //机器标识部分
| sequence; //***部分
}
/**
*
*
* @return
*/
private long getNextMill() {
long mill = System.currentTimeMillis();
while (mill <= lastTimeStamp) {
mill = System.currentTimeMillis();
}
return mill;
}
}

@ -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);
}
}

@ -43,7 +43,6 @@ import java.util.stream.Collectors;
@Api("发送消息")
@CrossOrigin(origins = "http://localhost:3000", allowCredentials = "true", allowedHeaders = "*")
public class MessageTemplateController {
private static final List<String> FLAT_FIELD_NAME = Arrays.asList("msgContent");
@Autowired
private MessageTemplateService messageTemplateService;
@ -54,7 +53,6 @@ public class MessageTemplateController {
@Value("${austin.business.upload.crowd.path}")
private String dataPath;
/**
* Id
* Id
@ -62,9 +60,7 @@ public class MessageTemplateController {
@PostMapping("/save")
@ApiOperation("/保存数据")
public BasicResultVO saveOrUpdate(@RequestBody MessageTemplate messageTemplate) {
MessageTemplate info = messageTemplateService.saveOrUpdate(messageTemplate);
return BasicResultVO.success(info);
}
@ -74,7 +70,7 @@ public class MessageTemplateController {
@GetMapping("/list")
@ApiOperation("/列表页")
public BasicResultVO queryList(MessageTemplateParam messageTemplateParam) {
List<Map<String, Object>> result = ConvertMap.flatList(messageTemplateService.queryList(messageTemplateParam), FLAT_FIELD_NAME);
List<Map<String, Object>> result = ConvertMap.flatList(messageTemplateService.queryList(messageTemplateParam));
long count = messageTemplateService.count();
MessageTemplateVo messageTemplateVo = MessageTemplateVo.builder().count(count).rows(result).build();
@ -87,7 +83,7 @@ public class MessageTemplateController {
@GetMapping("query/{id}")
@ApiOperation("/根据Id查找")
public BasicResultVO queryById(@PathVariable("id") Long id) {
Map<String, Object> result = ConvertMap.flatSingle(messageTemplateService.queryById(id), FLAT_FIELD_NAME);
Map<String, Object> result = ConvertMap.flatSingle(messageTemplateService.queryById(id));
return BasicResultVO.success(result);
}

@ -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);
}

@ -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<String> userInfoList = redisUtils.lRange(receiver, 0, -1);
@ -134,6 +143,44 @@ public class DataServiceImpl implements DataService {
}
@Override
public SmsTimeLineVo getTraceSmsInfo(DataParam dataParam) {
ArrayList<SmsTimeLineVo.ItemsVO> 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<SmsRecord> smsRecordList = smsRecordDao.findByPhoneAndSendDate(Long.valueOf(dataParam.getReceiver()), sendDate);
if (CollUtil.isEmpty(smsRecordList)) {
return smsTimeLineVo;
}
Map<String, List<SmsRecord>> maps = smsRecordList.stream().collect(Collectors.groupingBy((o) -> o.getPhone() + o.getSeriesId()));
for (Map.Entry<String, List<SmsRecord>> 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;
}
/**
* IDbusinessId
* businessIdbusinessId

@ -6,62 +6,97 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
* for Amis!!! amis!!
* List/Object Map
* https://baidu.gitee.io/amis/zh-CN/components/form/index#%E8%A1%A8%E5%8D%95%E9%A1%B9%E6%95%B0%E6%8D%AE%E5%88%9D%E5%A7%8B%E5%8C%96
*
* @author 3y
* @date 2022/1/23
*/
public class ConvertMap {
/**
* (json
* ()
*/
private static final List<String> FLAT_FIELD_NAME = Arrays.asList("msgContent");
/**
* jsonArray
* (JSONArray)
*/
private static final List<String> PARSE_JSON_ARRAY = Arrays.asList("feedCards", "btns");
/**
* OA
*/
private static final List<String> DING_DING_OA_FIELD = Arrays.asList("dingDingOaHead", "dingDingOaBody");
/**
* OA
*/
private static final Map<String, String> DING_DING_OA_NAME_MAPPING = new HashMap<>();
static {
DING_DING_OA_NAME_MAPPING.put("bgcolor", "dingDingOaHeadBgColor");
DING_DING_OA_NAME_MAPPING.put("text", "dingDingOaHeadTitle");
DING_DING_OA_NAME_MAPPING.put("title", "dingDingOaTitle");
DING_DING_OA_NAME_MAPPING.put("image", "media_id");
DING_DING_OA_NAME_MAPPING.put("author", "dingDingOaAuthor");
DING_DING_OA_NAME_MAPPING.put("content", "dingDingOaContent");
}
/**
* ListMap()
*
* @param param
* @param fieldName reduce
* @return
*/
public static <T> List<Map<String, Object>> flatList(List<T> param, List<String> fieldName) {
public static <T> List<Map<String, Object>> flatList(List<T> param) {
List<Map<String, Object>> result = new ArrayList<>();
for (T t : param) {
Map<String, Object> map = flatSingle(t, fieldName);
Map<String, Object> map = flatSingle(t);
result.add(map);
}
return result;
}
/**
* Map()
* <p>
* amis(amis)
*
* @param obj
* @param fieldName reduce
* @return
*/
public static Map<String, Object> flatSingle(Object obj, List<String> fieldName) {
public static Map<String, Object> flatSingle(Object obj) {
Map<String, Object> result = MapUtil.newHashMap(32);
Field[] fields = ReflectUtil.getFields(obj.getClass());
for (Field field : fields) {
if (fieldName.contains(field.getName())) {
JSONObject jsonObject;
Object value = ReflectUtil.getFieldValue(obj, field);
if (value instanceof String) {
jsonObject = JSON.parseObject((String) value);
} else {
jsonObject = JSONObject.parseObject(JSON.toJSONString(value));
}
if (FLAT_FIELD_NAME.contains(field.getName())) {
String fieldValue = (String) ReflectUtil.getFieldValue(obj, field);
JSONObject jsonObject = JSONObject.parseObject(fieldValue);
for (String key : jsonObject.keySet()) {
result.put(key, jsonObject.getString(key));
/**
* OA
*/
if (DING_DING_OA_FIELD.contains(key)) {
JSONObject object = jsonObject.getJSONObject(key);
for (String objKey : object.keySet()) {
result.put(DING_DING_OA_NAME_MAPPING.get(objKey), object.getString(objKey));
}
} else if (PARSE_JSON_ARRAY.contains(key)) {
/**
* ()
*/
result.put(key, JSON.parseArray(jsonObject.getString(key)));
} else{
result.put(key, jsonObject.getString(key));
}
}
}
result.put(field.getName(), ReflectUtil.getFieldValue(obj, field));
}
return result;
}
}

@ -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;
}

@ -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<SmsTimeLineVo.ItemsVO> 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;
}
}

@ -74,14 +74,14 @@
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
<version>1.2.83</version>
</dependency>
<!--腾讯sdk(目前用在短信上)-->
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java</artifactId>
<version>3.1.390</version>
<version>3.1.510</version>
</dependency>
<!--apollo-->

Loading…
Cancel
Save