diff --git a/README.md b/README.md index 707cbc6..90479b9 100644 --- a/README.md +++ b/README.md @@ -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?)

作者 @@ -8,9 +9,14 @@ 作者 项目交流 + Bilibili 对线面试官

+最近我已经在**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 - -**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。一个**讲人话的面试系列**,八股文不再是背诵。 -![](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) 想要获取这份电子书,**点击关注**下方公众号,回复「**对线**」得到我的联系方式即可进群获取电子书 diff --git a/austin-common/src/main/java/com/java3y/austin/common/constant/AustinConstant.java b/austin-common/src/main/java/com/java3y/austin/common/constant/AustinConstant.java index 2794c3a..cb23a55 100644 --- a/austin-common/src/main/java/com/java3y/austin/common/constant/AustinConstant.java +++ b/austin-common/src/main/java/com/java3y/austin/common/constant/AustinConstant.java @@ -38,7 +38,7 @@ public class AustinConstant { * 消息发送给全部人的标识 * (企业微信 应用消息) * (钉钉自定义机器人) - * + * (钉钉工作消息) */ public static final String SEND_ALL = "@all"; diff --git a/austin-common/src/main/java/com/java3y/austin/common/constant/SendAccountConstant.java b/austin-common/src/main/java/com/java3y/austin/common/constant/SendAccountConstant.java index 5f3c807..664ff07 100644 --- a/austin-common/src/main/java/com/java3y/austin/common/constant/SendAccountConstant.java +++ b/austin-common/src/main/java/com/java3y/austin/common/constant/SendAccountConstant.java @@ -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; + + } diff --git a/austin-common/src/main/java/com/java3y/austin/common/dto/account/YunPianSmsAccount.java b/austin-common/src/main/java/com/java3y/austin/common/dto/account/YunPianSmsAccount.java new file mode 100644 index 0000000..361fe3c --- /dev/null +++ b/austin-common/src/main/java/com/java3y/austin/common/dto/account/YunPianSmsAccount.java @@ -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; +} diff --git a/austin-common/src/main/java/com/java3y/austin/common/dto/model/DingDingContentModel.java b/austin-common/src/main/java/com/java3y/austin/common/dto/model/DingDingContentModel.java deleted file mode 100644 index 18ac2f4..0000000 --- a/austin-common/src/main/java/com/java3y/austin/common/dto/model/DingDingContentModel.java +++ /dev/null @@ -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 - * 钉钉 自定义机器人 + 工作通知 - *

- * https://open.dingtalk.com/document/group/custom-robot-access - *

- * 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; - - // ... -} diff --git a/austin-common/src/main/java/com/java3y/austin/common/dto/model/DingDingRobotContentModel.java b/austin-common/src/main/java/com/java3y/austin/common/dto/model/DingDingRobotContentModel.java new file mode 100644 index 0000000..02d7db8 --- /dev/null +++ b/austin-common/src/main/java/com/java3y/austin/common/dto/model/DingDingRobotContentModel.java @@ -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 + * 钉钉 自定义机器人 + *

+ * https://open.dingtalk.com/document/group/custom-robot-access + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class DingDingRobotContentModel extends ContentModel { + + /** + * 发送类型 + */ + private String sendType; + + /** + * 钉钉机器人:【文本消息】内容,【markdown消息】内容,【ActionCard消息】内容 + */ + private String content; + + /** + * 钉钉机器人:【markdown消息】标题,【FeedCard消息】标题,【ActionCard消息】标题 + */ + private String title; + + /** + * 钉钉机器人:【ActionCard消息】按钮布局 + */ + private String btnOrientation; + + /** + * 钉钉机器人:【ActionCard消息】按钮的文案和跳转链接的json + * [{\"title\":\"别点我\",\"actionURL\":\"https://www.baidu.com/\"},{\"title\":\"没关系,还是点我把\",\"actionURL\":\"https://www.baidu.com/\\t\"}] + */ + private String btns; + + + /** + * 钉钉机器人:【链接消息】点击消息跳转的URL,【FeedCard消息】点击消息跳转的URL + */ + private String url; + + /** + * 钉钉机器人:【链接消息】图片URL,【FeedCard消息】图片URL + */ + 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; +} diff --git a/austin-common/src/main/java/com/java3y/austin/common/dto/model/DingDingWorkContentModel.java b/austin-common/src/main/java/com/java3y/austin/common/dto/model/DingDingWorkContentModel.java new file mode 100644 index 0000000..c0dd520 --- /dev/null +++ b/austin-common/src/main/java/com/java3y/austin/common/dto/model/DingDingWorkContentModel.java @@ -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 + * 钉钉 工作通知 + *

+ * 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; + + /** + * 【文本消息】内容,【markdown消息】内容,【ActionCard消息】内容 + */ + private String content; + + /** + * 【markdown消息】标题,【ActionCard消息】标题 + */ + private String title; + + /** + * 【ActionCard消息】按钮布局 + */ + private String btnOrientation; + + /** + * 【ActionCard消息】按钮的文案和跳转链接的json + * [{"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; + +} diff --git a/austin-common/src/main/java/com/java3y/austin/common/enums/ChannelType.java b/austin-common/src/main/java/com/java3y/austin/common/enums/ChannelType.java index 2329673..ea8b736 100644 --- a/austin-common/src/main/java/com/java3y/austin/common/enums/ChannelType.java +++ b/austin-common/src/main/java/com/java3y/austin/common/enums/ChannelType.java @@ -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"), ; /** 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/SendMessageType.java b/austin-common/src/main/java/com/java3y/austin/common/enums/SendMessageType.java index 3f9ce31..791bbda 100644 --- a/austin-common/src/main/java/com/java3y/austin/common/enums/SendMessageType.java +++ b/austin-common/src/main/java/com/java3y/austin/common/enums/SendMessageType.java @@ -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; + + + /** + * 通过code获取钉钉机器人的Type值 + * + * @param code + * @return + */ + public static String getDingDingRobotTypeByCode(String code) { + for (SendMessageType value : SendMessageType.values()) { + if (value.getCode().equals(code)) { + return value.getDingDingRobotType(); + } + } + return null; + } + + /** + * 通过code获取钉钉工作通知的Type值 + * + * @param code + * @return + */ + public static String getDingDingWorkTypeByCode(String code) { + for (SendMessageType value : SendMessageType.values()) { + if (value.getCode().equals(code)) { + return value.getDingDingWorkType(); + } + } + return null; + } + + } 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..8bbdf67 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 @@ -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 ""; + } + + } diff --git a/austin-handler/src/main/java/com/java3y/austin/handler/deduplication/limit/SlideWindowLimitService.java b/austin-handler/src/main/java/com/java3y/austin/handler/deduplication/limit/SlideWindowLimitService.java index 392462d..f727faa 100644 --- a/austin-handler/src/main/java/com/java3y/austin/handler/deduplication/limit/SlideWindowLimitService.java +++ b/austin-handler/src/main/java/com/java3y/austin/handler/deduplication/limit/SlideWindowLimitService.java @@ -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 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); diff --git a/austin-handler/src/main/java/com/java3y/austin/handler/domain/dingding/DingDingRobotParam.java b/austin-handler/src/main/java/com/java3y/austin/handler/domain/dingding/DingDingRobotParam.java index 3012916..c5f6c01 100644 --- a/austin-handler/src/main/java/com/java3y/austin/handler/domain/dingding/DingDingRobotParam.java +++ b/austin-handler/src/main/java/com/java3y/austin/handler/domain/dingding/DingDingRobotParam.java @@ -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 diff --git a/austin-handler/src/main/java/com/java3y/austin/handler/domain/push/PushParam.java b/austin-handler/src/main/java/com/java3y/austin/handler/domain/push/PushParam.java index 5ab85ca..31d1c3c 100644 --- a/austin-handler/src/main/java/com/java3y/austin/handler/domain/push/PushParam.java +++ b/austin-handler/src/main/java/com/java3y/austin/handler/domain/push/PushParam.java @@ -7,8 +7,10 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import java.util.Set; - +/** + * @author 3y + * push的参数 + */ @NoArgsConstructor @AllArgsConstructor @Data diff --git a/austin-handler/src/main/java/com/java3y/austin/handler/domain/sms/MessageTypeSmsConfig.java b/austin-handler/src/main/java/com/java3y/austin/handler/domain/sms/MessageTypeSmsConfig.java new file mode 100644 index 0000000..d831854 --- /dev/null +++ b/austin-handler/src/main/java/com/java3y/austin/handler/domain/sms/MessageTypeSmsConfig.java @@ -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; + +} diff --git a/austin-handler/src/main/java/com/java3y/austin/handler/domain/sms/SmsParam.java b/austin-handler/src/main/java/com/java3y/austin/handler/domain/sms/SmsParam.java index bcf9f1e..74eee4f 100644 --- a/austin-handler/src/main/java/com/java3y/austin/handler/domain/sms/SmsParam.java +++ b/austin-handler/src/main/java/com/java3y/austin/handler/domain/sms/SmsParam.java @@ -28,10 +28,4 @@ public class SmsParam { * 发送文案 */ private String content; - - /** - * 发送账号 - */ - private Integer sendAccount; - } diff --git a/austin-handler/src/main/java/com/java3y/austin/handler/domain/sms/YunPianSendResult.java b/austin-handler/src/main/java/com/java3y/austin/handler/domain/sms/YunPianSendResult.java new file mode 100644 index 0000000..8a02a47 --- /dev/null +++ b/austin-handler/src/main/java/com/java3y/austin/handler/domain/sms/YunPianSendResult.java @@ -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 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; + } +} diff --git a/austin-handler/src/main/java/com/java3y/austin/handler/handler/impl/DingDingRobotHandler.java b/austin-handler/src/main/java/com/java3y/austin/handler/handler/impl/DingDingRobotHandler.java index bc4d702..2c92c98 100644 --- a/austin-handler/src/main/java/com/java3y/austin/handler/handler/impl/DingDingRobotHandler.java +++ b/austin-handler/src/main/java/com/java3y/austin/handler/handler/impl/DingDingRobotHandler.java @@ -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 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 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; } /** diff --git a/austin-handler/src/main/java/com/java3y/austin/handler/handler/impl/DingDingWorkNoticeHandler.java b/austin-handler/src/main/java/com/java3y/austin/handler/handler/impl/DingDingWorkNoticeHandler.java index 3ddee90..11b5b87 100644 --- a/austin-handler/src/main/java/com/java3y/austin/handler/handler/impl/DingDingWorkNoticeHandler.java +++ b/austin-handler/src/main/java/com/java3y/austin/handler/handler/impl/DingDingWorkNoticeHandler.java @@ -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; + /** * 钉钉消息自定义机器人 消息处理器 *

@@ -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)); diff --git a/austin-handler/src/main/java/com/java3y/austin/handler/handler/impl/MiniProgramAccountHandler.java b/austin-handler/src/main/java/com/java3y/austin/handler/handler/impl/MiniProgramAccountHandler.java index 013fd15..f02044a 100644 --- a/austin-handler/src/main/java/com/java3y/austin/handler/handler/impl/MiniProgramAccountHandler.java +++ b/austin-handler/src/main/java/com/java3y/austin/handler/handler/impl/MiniProgramAccountHandler.java @@ -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; diff --git a/austin-handler/src/main/java/com/java3y/austin/handler/handler/impl/OfficialAccountHandler.java b/austin-handler/src/main/java/com/java3y/austin/handler/handler/impl/OfficialAccountHandler.java index 7e6707b..1246043 100644 --- a/austin-handler/src/main/java/com/java3y/austin/handler/handler/impl/OfficialAccountHandler.java +++ b/austin-handler/src/main/java/com/java3y/austin/handler/handler/impl/OfficialAccountHandler.java @@ -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; diff --git a/austin-handler/src/main/java/com/java3y/austin/handler/handler/impl/SmsHandler.java b/austin-handler/src/main/java/com/java3y/austin/handler/handler/impl/SmsHandler.java index e833a3e..46a2d90 100644 --- a/austin-handler/src/main/java/com/java3y/austin/handler/handler/impl/SmsHandler.java +++ b/austin-handler/src/main/java/com/java3y/austin/handler/handler/impl/SmsHandler.java @@ -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 recordList = smsScript.send(smsParam); - if (!CollUtil.isEmpty(recordList)) { - smsRecordDao.saveAll(recordList); + /** + * 1、动态配置做流量负载 + * 2、发送短信 + */ + MessageTypeSmsConfig[] messageTypeSmsConfigs = loadBalance(getMessageTypeSmsConfig(taskInfo.getMsgType())); + for (MessageTypeSmsConfig messageTypeSmsConfig : messageTypeSmsConfigs) { + List 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 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; + } + + /** + * 每种类型都会有其下发渠道账号的配置(流量占比也会配置里面) + *

+ * 样例: + * key:msg_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%流量,YunPianSmsScript占20%流量 + * 营销类短信只有一个发送渠道 YunPianSmsScript + * 验证码短信只有一个发送渠道 TencentSmsScript + * + * @param msgType + * @return + */ + private List 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 result = JSON.parseArray(JSON.toJSONString(array), MessageTypeSmsConfig.class); + return result; + } + } + return null; + } + /** * 如果有输入链接,则把链接拼在文案后 *

diff --git a/austin-handler/src/main/java/com/java3y/austin/handler/receipt/SmsReceipt.java b/austin-handler/src/main/java/com/java3y/austin/handler/receipt/SmsReceipt.java new file mode 100644 index 0000000..53cfda4 --- /dev/null +++ b/austin-handler/src/main/java/com/java3y/austin/handler/receipt/SmsReceipt.java @@ -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) { + } + } + }); + } +} 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..704422e --- /dev/null +++ b/austin-handler/src/main/java/com/java3y/austin/handler/receipt/TencentSmsReceipt.java @@ -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 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); + } + + +} diff --git a/austin-handler/src/main/java/com/java3y/austin/handler/receipt/YunPianSmsReceipt.java b/austin-handler/src/main/java/com/java3y/austin/handler/receipt/YunPianSmsReceipt.java new file mode 100644 index 0000000..1e6442d --- /dev/null +++ b/austin-handler/src/main/java/com/java3y/austin/handler/receipt/YunPianSmsReceipt.java @@ -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() { + + } + +} diff --git a/austin-handler/src/main/java/com/java3y/austin/handler/script/BaseSmsScript.java b/austin-handler/src/main/java/com/java3y/austin/handler/script/BaseSmsScript.java new file mode 100644 index 0000000..931cb5c --- /dev/null +++ b/austin-handler/src/main/java/com/java3y/austin/handler/script/BaseSmsScript.java @@ -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); + } +} diff --git a/austin-handler/src/main/java/com/java3y/austin/handler/script/SmsScript.java b/austin-handler/src/main/java/com/java3y/austin/handler/script/SmsScript.java index 94560ec..35d6e98 100644 --- a/austin-handler/src/main/java/com/java3y/austin/handler/script/SmsScript.java +++ b/austin-handler/src/main/java/com/java3y/austin/handler/script/SmsScript.java @@ -17,8 +17,8 @@ public interface SmsScript { * 发送短信 * @param smsParam * @return 渠道商接口返回值 - * @throws Exception + */ - List send(SmsParam smsParam) throws Exception; + List send(SmsParam smsParam); } diff --git a/austin-handler/src/main/java/com/java3y/austin/handler/script/SmsScriptHandler.java b/austin-handler/src/main/java/com/java3y/austin/handler/script/SmsScriptHandler.java new file mode 100644 index 0000000..7b285e8 --- /dev/null +++ b/austin-handler/src/main/java/com/java3y/austin/handler/script/SmsScriptHandler.java @@ -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(); +} diff --git a/austin-handler/src/main/java/com/java3y/austin/handler/script/SmsScriptHolder.java b/austin-handler/src/main/java/com/java3y/austin/handler/script/SmsScriptHolder.java new file mode 100644 index 0000000..b02244e --- /dev/null +++ b/austin-handler/src/main/java/com/java3y/austin/handler/script/SmsScriptHolder.java @@ -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 handlers = new HashMap<>(8); + + public void putHandler(String scriptName, SmsScript handler) { + handlers.put(scriptName, handler); + } + public SmsScript route(String scriptName) { + return handlers.get(scriptName); + } +} diff --git a/austin-handler/src/main/java/com/java3y/austin/handler/script/impl/TencentSmsScript.java b/austin-handler/src/main/java/com/java3y/austin/handler/script/impl/TencentSmsScript.java index f3bb434..3412560 100644 --- a/austin-handler/src/main/java/com/java3y/austin/handler/script/impl/TencentSmsScript.java +++ b/austin-handler/src/main/java/com/java3y/austin/handler/script/impl/TencentSmsScript.java @@ -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 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 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; + } } diff --git a/austin-handler/src/main/java/com/java3y/austin/handler/script/impl/YunPianSmsScript.java b/austin-handler/src/main/java/com/java3y/austin/handler/script/impl/YunPianSmsScript.java new file mode 100644 index 0000000..c4ac233 --- /dev/null +++ b/austin-handler/src/main/java/com/java3y/austin/handler/script/impl/YunPianSmsScript.java @@ -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 2022年5月23日 + * 发送短信接入文档: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 send(SmsParam smsParam) { + + try { + YunPianSmsAccount account = accountUtils.getAccount(SendAccountConstant.YUN_PIAN_SMS_CODE, SendAccountConstant.SMS_ACCOUNT_KEY, SendAccountConstant.SMS_PREFIX, YunPianSmsAccount.class); + Map 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 assembleParam(SmsParam smsParam, YunPianSmsAccount account) { + Map 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 assembleSmsRecord(SmsParam smsParam, YunPianSendResult response, YunPianSmsAccount account) { + if (response == null || ArrayUtil.isEmpty(response.getData())) { + return null; + } + + List 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; + } + + +} + diff --git a/austin-handler/src/main/java/com/java3y/austin/handler/script/MiniProgramAccountService.java b/austin-handler/src/main/java/com/java3y/austin/handler/wechat/MiniProgramAccountService.java similarity index 89% rename from austin-handler/src/main/java/com/java3y/austin/handler/script/MiniProgramAccountService.java rename to austin-handler/src/main/java/com/java3y/austin/handler/wechat/MiniProgramAccountService.java index 7a4b6da..a0ef4b3 100644 --- a/austin-handler/src/main/java/com/java3y/austin/handler/script/MiniProgramAccountService.java +++ b/austin-handler/src/main/java/com/java3y/austin/handler/wechat/MiniProgramAccountService.java @@ -1,4 +1,4 @@ -package com.java3y.austin.handler.script; +package com.java3y.austin.handler.wechat; import com.java3y.austin.handler.domain.wechat.WeChatMiniProgramParam; diff --git a/austin-handler/src/main/java/com/java3y/austin/handler/script/OfficialAccountService.java b/austin-handler/src/main/java/com/java3y/austin/handler/wechat/OfficialAccountService.java similarity index 91% rename from austin-handler/src/main/java/com/java3y/austin/handler/script/OfficialAccountService.java rename to austin-handler/src/main/java/com/java3y/austin/handler/wechat/OfficialAccountService.java index 8451869..4014db2 100644 --- a/austin-handler/src/main/java/com/java3y/austin/handler/script/OfficialAccountService.java +++ b/austin-handler/src/main/java/com/java3y/austin/handler/wechat/OfficialAccountService.java @@ -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; diff --git a/austin-handler/src/main/java/com/java3y/austin/handler/script/impl/MiniProgramAccountServiceImpl.java b/austin-handler/src/main/java/com/java3y/austin/handler/wechat/impl/MiniProgramAccountServiceImpl.java similarity index 97% rename from austin-handler/src/main/java/com/java3y/austin/handler/script/impl/MiniProgramAccountServiceImpl.java rename to austin-handler/src/main/java/com/java3y/austin/handler/wechat/impl/MiniProgramAccountServiceImpl.java index ddb2e21..6c400bf 100644 --- a/austin-handler/src/main/java/com/java3y/austin/handler/script/impl/MiniProgramAccountServiceImpl.java +++ b/austin-handler/src/main/java/com/java3y/austin/handler/wechat/impl/MiniProgramAccountServiceImpl.java @@ -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; diff --git a/austin-handler/src/main/java/com/java3y/austin/handler/script/impl/OfficialAccountServiceImpl.java b/austin-handler/src/main/java/com/java3y/austin/handler/wechat/impl/OfficialAccountServiceImpl.java similarity index 96% rename from austin-handler/src/main/java/com/java3y/austin/handler/script/impl/OfficialAccountServiceImpl.java rename to austin-handler/src/main/java/com/java3y/austin/handler/wechat/impl/OfficialAccountServiceImpl.java index a0f68fc..7766713 100644 --- a/austin-handler/src/main/java/com/java3y/austin/handler/script/impl/OfficialAccountServiceImpl.java +++ b/austin-handler/src/main/java/com/java3y/austin/handler/wechat/impl/OfficialAccountServiceImpl.java @@ -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; diff --git a/austin-service-api-impl/src/main/java/com/java3y/austin/service/api/impl/action/AfterParamCheckAction.java b/austin-service-api-impl/src/main/java/com/java3y/austin/service/api/impl/action/AfterParamCheckAction.java index 8c97488..0e30b6f 100644 --- a/austin-service-api-impl/src/main/java/com/java3y/austin/service/api/impl/action/AfterParamCheckAction.java +++ b/austin-service-api-impl/src/main/java/com/java3y/austin/service/api/impl/action/AfterParamCheckAction.java @@ -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 { - 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 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 context) { SendTaskModel sendTaskModel = context.getProcessModel(); List 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 { } /** - * 如果指定类型是手机号,且渠道是发送短信,检测输入手机号是否合法 - * + * 如果指定类型是手机号,检测输入手机号是否合法 + * 如果指定类型是邮件,检测输入邮件是否合法 * @param taskInfo */ - private void filterIllegalPhoneNum(List taskInfo) { + private void filterIllegalReceiver(List 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 iterator = taskInfo.iterator(); + filter(taskInfo, CHANNEL_REGEX_EXP.get(idType)); + } - // 利用正则找出不合法的手机号 - while (iterator.hasNext()) { - TaskInfo task = iterator.next(); - Set illegalPhone = task.getReceiver().stream() - .filter(phone -> !ReUtil.isMatch(PHONE_REGEX_EXP, phone)) - .collect(Collectors.toSet()); + /** + * 利用正则过滤掉不合法的接收者 + * + * @param taskInfo + * @param regexExp + */ + private void filter(List taskInfo, String regexExp) { + Iterator iterator = taskInfo.iterator(); + while (iterator.hasNext()) { + TaskInfo task = iterator.next(); + Set 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(); } } } diff --git a/austin-service-api-impl/src/main/java/com/java3y/austin/service/api/impl/action/PreParamCheckAction.java b/austin-service-api-impl/src/main/java/com/java3y/austin/service/api/impl/action/PreParamCheckAction.java index 2c1d152..4e48e07 100644 --- a/austin-service-api-impl/src/main/java/com/java3y/austin/service/api/impl/action/PreParamCheckAction.java +++ b/austin-service-api-impl/src/main/java/com/java3y/austin/service/api/impl/action/PreParamCheckAction.java @@ -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 { + /** + * 最大的人数 + */ + private static final Integer BATCH_RECEIVER_SIZE = 100; + @Override public void process(ProcessContext context) { SendTaskModel sendTaskModel = context.getProcessModel(); @@ -30,13 +36,13 @@ public class PreParamCheckAction implements BusinessProcess { Long messageTemplateId = sendTaskModel.getMessageTemplateId(); List 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 resultMessageParamList = messageParamList.stream() .filter(messageParam -> !StrUtil.isBlank(messageParam.getReceiver())) .collect(Collectors.toList()); @@ -44,7 +50,13 @@ public class PreParamCheckAction implements BusinessProcess { 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; + } + } } diff --git a/austin-service-api/src/main/java/com/java3y/austin/service/api/domain/MessageParam.java b/austin-service-api/src/main/java/com/java3y/austin/service/api/domain/MessageParam.java index 95aa2f8..509efa2 100644 --- a/austin-service-api/src/main/java/com/java3y/austin/service/api/domain/MessageParam.java +++ b/austin-service-api/src/main/java/com/java3y/austin/service/api/domain/MessageParam.java @@ -23,6 +23,7 @@ public class MessageParam { /** * @Description: 接收者 * 多个用,逗号号分隔开 + * 【不能大于100个】 * 必传 */ private String receiver; 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-support/src/main/java/com/java3y/austin/support/utils/AccountUtils.java b/austin-support/src/main/java/com/java3y/austin/support/utils/AccountUtils.java index 5d08a57..b72b952 100644 --- a/austin-support/src/main/java/com/java3y/austin/support/utils/AccountUtils.java +++ b/austin-support/src/main/java/com/java3y/austin/support/utils/AccountUtils.java @@ -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 getAccount(Integer sendAccount, String apolloKey, String prefix, Class clazz) { String accountValues = config.getProperty(apolloKey, AustinConstant.APOLLO_DEFAULT_VALUE_JSON_ARRAY); @@ -42,4 +42,7 @@ public class AccountUtils { return null; } + + + } diff --git a/austin-support/src/main/java/com/java3y/austin/support/utils/SnowFlakeIdUtils.java b/austin-support/src/main/java/com/java3y/austin/support/utils/SnowFlakeIdUtils.java deleted file mode 100644 index 925ea8b..0000000 --- a/austin-support/src/main/java/com/java3y/austin/support/utils/SnowFlakeIdUtils.java +++ /dev/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; //上一次时间戳 - - - /** - * 根据指定的数据中心ID和机器标志ID生成指定的*** - * - * @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; - - } - -} 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/controller/MessageTemplateController.java b/austin-web/src/main/java/com/java3y/austin/web/controller/MessageTemplateController.java index e856127..6c7940f 100644 --- a/austin-web/src/main/java/com/java3y/austin/web/controller/MessageTemplateController.java +++ b/austin-web/src/main/java/com/java3y/austin/web/controller/MessageTemplateController.java @@ -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 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> result = ConvertMap.flatList(messageTemplateService.queryList(messageTemplateParam), FLAT_FIELD_NAME); + List> 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 result = ConvertMap.flatSingle(messageTemplateService.queryById(id), FLAT_FIELD_NAME); + Map result = ConvertMap.flatSingle(messageTemplateService.queryById(id)); return BasicResultVO.success(result); } 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..5a9b6b1 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进行查询 diff --git a/austin-web/src/main/java/com/java3y/austin/web/utils/ConvertMap.java b/austin-web/src/main/java/com/java3y/austin/web/utils/ConvertMap.java index 239bd24..883027f 100644 --- a/austin-web/src/main/java/com/java3y/austin/web/utils/ConvertMap.java +++ b/austin-web/src/main/java/com/java3y/austin/web/utils/ConvertMap.java @@ -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 FLAT_FIELD_NAME = Arrays.asList("msgContent"); + + /** + * 需要格式化为jsonArray返回的字段 + * (前端是一个JSONArray传递进来) + */ + private static final List PARSE_JSON_ARRAY = Arrays.asList("feedCards", "btns"); + + /** + * 钉钉工作消息OA实际的映射 + */ + private static final List DING_DING_OA_FIELD = Arrays.asList("dingDingOaHead", "dingDingOaBody"); + /** + * 钉钉OA字段名实际的映射 + */ + private static final Map 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"); + } /** * 将List对象转换成Map(无嵌套) * * @param param - * @param fieldName 需要 reduce 的属性名 * @return */ - public static List> flatList(List param, List fieldName) { + public static List> flatList(List param) { List> result = new ArrayList<>(); for (T t : param) { - Map map = flatSingle(t, fieldName); + Map map = flatSingle(t); result.add(map); } return result; - } /** * 将单个对象转换成Map(无嵌套) + *

+ * 主要兼容amis的回显(前端不用amis可忽略) * * @param obj - * @param fieldName 需要 reduce 的属性名 * @return */ - public static Map flatSingle(Object obj, List fieldName) { + public static Map flatSingle(Object obj) { Map 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; - } } 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..2506f6e 100644 --- a/pom.xml +++ b/pom.xml @@ -74,14 +74,14 @@ com.alibaba fastjson - 1.2.78 + 1.2.83 com.tencentcloudapi tencentcloud-sdk-java - 3.1.390 + 3.1.510