diff --git a/ballcat-common/ballcat-common-core/src/main/java/com/hccake/ballcat/common/core/markdown/MarkdownBuilder.java b/ballcat-common/ballcat-common-core/src/main/java/com/hccake/ballcat/common/core/markdown/MarkdownBuilder.java new file mode 100644 index 00000000..052b7daa --- /dev/null +++ b/ballcat-common/ballcat-common-core/src/main/java/com/hccake/ballcat/common/core/markdown/MarkdownBuilder.java @@ -0,0 +1,242 @@ +package com.hccake.ballcat.common.core.markdown; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.StrUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +/** + * 生成 markdown 文本 + * + * @author lingting 2020/6/10 22:43 + */ +public class MarkdownBuilder { + public static final String TITLE_PREFIX = "#"; + public static final String QUOTE_PREFIX = "> "; + public static final String BOLD_PREFIX = "**"; + public static final String ITALIC_PREFIX = "*"; + public static final String UNORDERED_LIST_PREFIX = "- "; + public static final String ORDER_LIST_PREFIX = ". "; + + /** + * 存放内容 + */ + private final List content = new ArrayList<>(); + /** + * 当前操作行文本 + */ + private StringBuilder lineTextBuilder; + + /** + * 添加自定义内容 + * + * @param content 自定义内容 + * @author lingting 2020-06-10 23:14:54 + */ + public MarkdownBuilder append(String content) { + lineTextBuilder.append(content); + return this; + } + + /** + * 有序列表 自动生成 索引 + * + * @param content 文本 + * @author lingting 2020-06-10 23:13:41 + */ + public MarkdownBuilder orderList(String content) { + // 获取最后一个字符串 + String tmp = ""; + if (this.content.size() != 0) { + tmp = this.content.get(this.content.size() - 1); + } + // 索引 + int index = 1; + + // 校验 是否 为有序列表行的正则 + String isOrderListPattern = "^\\d\\. .*"; + if (Pattern.matches(isOrderListPattern, tmp)) { + // 如果是数字开头 + index = Convert.toInt(tmp.substring(0, tmp.indexOf(ORDER_LIST_PREFIX) - 1)); + } + return orderList(index, content); + } + + /** + * 有序列表 + * + * @param index 索引 + * @param content 文本 + * @author lingting 2020-06-10 23:13:41 + */ + public MarkdownBuilder orderList(int index, String content) { + lineBreak(); + lineTextBuilder.append(index).append(ORDER_LIST_PREFIX).append(content); + return this; + } + + /** + * 无序列表 + * - item1 + * - item2 + * + * @author lingting 2020-06-10 23:09:29 + */ + public MarkdownBuilder unorderedList(String content) { + // 换行 + lineBreak(); + lineTextBuilder.append(UNORDERED_LIST_PREFIX).append(content); + return this; + } + + /** + * 图片 + * + * @param url 图片链接 + * @author lingting 2020-06-10 23:03:04 + */ + public MarkdownBuilder pic(String url) { + return pic(StrUtil.EMPTY, url); + } + + /** + * 图片 + * + * @param title 图片标题 + * @param url 图片路径 + * @author lingting 2020-06-10 23:03:11 + */ + public MarkdownBuilder pic(String title, String url) { + lineTextBuilder.append("![").append(title).append("](").append(url).append(")"); + return this; + } + + /** + * 链接 + * + * @param title 标题 + * @param url http 路径 + * @author lingting 2020-06-10 23:01:15 + */ + public MarkdownBuilder link(String title, String url) { + lineTextBuilder.append("[").append(title).append("](").append(url).append(")"); + return this; + } + + /** + * 斜体 + * + * @author lingting 2020-06-10 22:59:26 + */ + public MarkdownBuilder italic(String content) { + lineTextBuilder.append(ITALIC_PREFIX).append(content).append(ITALIC_PREFIX); + return this; + } + + /** + * 加粗 + * + * @author lingting 2020-06-10 22:58:39 + */ + public MarkdownBuilder bold(String content) { + lineTextBuilder.append(BOLD_PREFIX).append(content).append(BOLD_PREFIX); + return this; + } + + /** + * 引用 + * > 文本 + * + * @param content 文本 + * @author lingting 2020-06-10 22:58:04 + */ + public MarkdownBuilder quote(String content) { + forceLineBreak(); + lineTextBuilder.append(QUOTE_PREFIX).append(content); + // 下面得换行两次 + forceLineBreak(); + forceLineBreak(); + return this; + } + + /** + * 强制换行 + * + * @author lingting 2020-06-10 22:56:25 + */ + public MarkdownBuilder forceLineBreak() { + content.add(lineTextBuilder.toString()); + lineTextBuilder = new StringBuilder(); + return this; + } + + /** + * 换行 + * 当已编辑文本长度不为0时换行 + * + * @author lingting 2020-06-10 22:56:25 + */ + public MarkdownBuilder lineBreak() { + if (lineTextBuilder.length() != 0) { + return forceLineBreak(); + } + return this; + } + + /** + * 生成 i 级标题 + * + * @author lingting 2020-06-10 22:55:39 + */ + private MarkdownBuilder title(int i, String content) { + lineTextBuilder = new StringBuilder(); + for (int j = 0; j < i; j++) { + lineTextBuilder.append(TITLE_PREFIX); + } + this.content.add(lineTextBuilder.append(" ").append(content).toString()); + lineTextBuilder = new StringBuilder(); + return this; + } + + public MarkdownBuilder title1(String text) { + return title(1, text); + } + + public MarkdownBuilder title2(String text) { + return title(2, text); + } + + public MarkdownBuilder title3(String text) { + return title(3, text); + } + + public MarkdownBuilder title4(String text) { + return title(4, text); + } + + public MarkdownBuilder title5(String text) { + return title(5, text); + } + + @Override + public String toString() { + return build(); + } + + /** + * 构筑 Markdown 文本 + * + * @author lingting 2020-06-11 22:55:40 + */ + public String build() { + if (lineTextBuilder.length() != 0) { + // 最后一个操作的 如果不为空,也需要添加进入list + content.add(lineTextBuilder.toString()); + } + StringBuilder res = new StringBuilder(); + content.forEach(content -> res.append(content).append("\\n")); + return res.toString(); + } +} diff --git a/ballcat-dependencies/pom.xml b/ballcat-dependencies/pom.xml index 99fd44cb..b16943ad 100644 --- a/ballcat-dependencies/pom.xml +++ b/ballcat-dependencies/pom.xml @@ -1,12 +1,12 @@ - 4.0.0 - com.hccake - ballcat-dependencies - ${revision} - pom + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + com.hccake + ballcat-dependencies + ${revision} + pom Ballcat Dependencies Ballcat Dependencies @@ -35,70 +35,69 @@ - 0.0.2 - 1.1.0 + 0.0.2 + 1.1.0 1.6.8 3.0.0-M1 1.6 - 5.2.5 - 3.3.2 - 1.0.0 - 1.5.2 - 2.2.0 - 2.2.2 - 3.8.0 - 2.1.6 - + 3.3.2 + 1.0.0 + 1.5.2 + 2.2.0 + 2.2.2 + 3.8.0 + 2.1.6 + - - - - com.hccake - ballcat-admin-core - ${revision} - - - com.hccake - ballcat-common-conf - ${revision} - - - com.hccake - ballcat-common-core - ${revision} - - - com.hccake - ballcat-spring-boot-starter-job - ${revision} - - - com.hccake - ballcat-spring-boot-starter-log - ${revision} - - - com.hccake - ballcat-spring-boot-starter-swagger - ${revision} - - - com.hccake - ballcat-spring-boot-starter-storage - ${revision} - - - com.hccake - ballcat-spring-boot-starter-mail - ${revision} - - - com.hccake - ballcat-spring-boot-starter-easyexcel - ${revision} - + + + + com.hccake + ballcat-admin-core + ${revision} + + + com.hccake + ballcat-common-conf + ${revision} + + + com.hccake + ballcat-common-core + ${revision} + + + com.hccake + ballcat-spring-boot-starter-job + ${revision} + + + com.hccake + ballcat-spring-boot-starter-log + ${revision} + + + com.hccake + ballcat-spring-boot-starter-swagger + ${revision} + + + com.hccake + ballcat-spring-boot-starter-storage + ${revision} + + + com.hccake + ballcat-spring-boot-starter-mail + ${revision} + + + com.hccake + ballcat-spring-boot-starter-easyexcel + ${revision} + com.hccake ballcat-spring-boot-starter-redis @@ -106,76 +105,87 @@ com.hccake - mybatis-plus-extend + ballcat-spring-boot-starter-ding-talk + ${revision} + + + + com.hccake + ballcat-extend-ding-talk ${revision} com.hccake - mybatis-plus-mysql-extend + ballcat-extend-mybatis-plus + ${revision} + + + com.hccake + ballcat-extend-mybatis-plus-mysql ${revision} - - - io.swagger - swagger-annotations - ${swagger.core.version} - - - - com.xuxueli - xxl-job-core - ${xxl-job.version} - - - - com.baomidou - mybatis-plus-extension - ${mybatis-plus.version} - - - com.baomidou - mybatis-plus-core - ${mybatis-plus.version} - - - - com.baomidou - mybatis-plus-boot-starter - ${mybatis-plus.version} - - - - com.aliyun.oss - aliyun-sdk-oss - ${oss.aliyun.version} - - - - com.alibaba - easyexcel - ${easyexcel.version} - - - - de.codecentric - spring-boot-admin-starter-server - ${spring-boot-admin.version} - - - - de.codecentric - spring-boot-admin-starter-client - ${spring-boot-admin.version} - - - - cn.hutool - hutool-all - ${hutool.version} - - - + + + io.swagger + swagger-annotations + ${swagger.core.version} + + + + com.xuxueli + xxl-job-core + ${xxl-job.version} + + + + com.baomidou + mybatis-plus-extension + ${mybatis-plus.version} + + + com.baomidou + mybatis-plus-core + ${mybatis-plus.version} + + + + com.baomidou + mybatis-plus-boot-starter + ${mybatis-plus.version} + + + + com.aliyun.oss + aliyun-sdk-oss + ${oss.aliyun.version} + + + + com.alibaba + easyexcel + ${easyexcel.version} + + + + de.codecentric + spring-boot-admin-starter-server + ${spring-boot-admin.version} + + + + de.codecentric + spring-boot-admin-starter-client + ${spring-boot-admin.version} + + + + cn.hutool + hutool-all + ${hutool.version} + + + @@ -188,7 +198,7 @@ - + @@ -213,34 +223,34 @@ - - - org.codehaus.mojo - flatten-maven-plugin - ${flatten-maven-plugin.version} - - true - resolveCiFriendliesOnly - - - - flatten - process-resources - - flatten - - - - flatten.clean - clean - - clean - - - - - - + + + org.codehaus.mojo + flatten-maven-plugin + ${flatten-maven-plugin.version} + + true + resolveCiFriendliesOnly + + + + flatten + process-resources + + flatten + + + + flatten.clean + clean + + clean + + + + + + diff --git a/ballcat-extends/ballcat-extend-ding-talk/pom.xml b/ballcat-extends/ballcat-extend-ding-talk/pom.xml new file mode 100644 index 00000000..d2b1c97d --- /dev/null +++ b/ballcat-extends/ballcat-extend-ding-talk/pom.xml @@ -0,0 +1,20 @@ + + + + ballcat-extends + com.hccake + 0.0.2 + + 4.0.0 + + ballcat-extend-ding-talk + + + + com.hccake + ballcat-common-core + + + \ No newline at end of file diff --git a/ballcat-extends/ballcat-extend-ding-talk/src/main/java/com/hccake/extend/ding/talk/DingTalkResponse.java b/ballcat-extends/ballcat-extend-ding-talk/src/main/java/com/hccake/extend/ding/talk/DingTalkResponse.java new file mode 100644 index 00000000..754f2781 --- /dev/null +++ b/ballcat-extends/ballcat-extend-ding-talk/src/main/java/com/hccake/extend/ding/talk/DingTalkResponse.java @@ -0,0 +1,39 @@ +package com.hccake.extend.ding.talk; + +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import lombok.Getter; +import lombok.Setter; + +/** + * 钉钉返回信息 + * + * @author lingting 2020/6/11 0:23 + */ +@Getter +@Setter +public class DingTalkResponse { + private String errCode; + /** + * 值为ok表示无异常 + */ + private String errMsg; + /** + * 钉钉返回信息 + */ + private String response; + + public static DingTalkResponse getInstance(String res) { + JSONObject json = JSONUtil.parseObj(res); + DingTalkResponse response = new DingTalkResponse(); + response.errCode = json.getStr("errcode"); + response.errMsg = json.getStr("errmsg"); + response.response = res; + return response; + } + + @Override + public String toString() { + return response; + } +} diff --git a/ballcat-extends/ballcat-extend-ding-talk/src/main/java/com/hccake/extend/ding/talk/DingTalkSender.java b/ballcat-extends/ballcat-extend-ding-talk/src/main/java/com/hccake/extend/ding/talk/DingTalkSender.java new file mode 100644 index 00000000..61a02459 --- /dev/null +++ b/ballcat-extends/ballcat-extend-ding-talk/src/main/java/com/hccake/extend/ding/talk/DingTalkSender.java @@ -0,0 +1,84 @@ +package com.hccake.extend.ding.talk; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpUtil; +import com.hccake.extend.ding.talk.message.DingTalkMessage; +import lombok.Data; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.experimental.Accessors; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +/** + * 订单消息发送 + * + * @author lingting 2020/6/10 21:25 + */ +@Data +@Accessors(chain = true) +@RequiredArgsConstructor +public class DingTalkSender { + /** + * 请求路径 + */ + private final String url; + /** + * 密钥 + */ + private String secret; + + /** + * 发送消息 + * 根据参数值判断使用哪种发送方式 + * + * @author lingting 2020-06-11 00:05:51 + */ + @SneakyThrows + public DingTalkResponse sendMessage(DingTalkMessage message) { + if (StrUtil.isEmpty(secret)) { + return sendNormalMessage(message); + } else { + return sendSecretMessage(message); + } + } + + /** + * 未使用 加签 安全设置 直接发送 + * + * @author lingting 2020-06-11 00:09:23 + */ + public DingTalkResponse sendNormalMessage(DingTalkMessage message) { + return DingTalkResponse.getInstance(HttpUtil.post(url, message.toString())); + } + + /** + * 使用 加签 安全设置 发送 + * + * @author lingting 2020-06-11 00:10:38 + */ + @SneakyThrows + public DingTalkResponse sendSecretMessage(DingTalkMessage message) { + return DingTalkResponse.getInstance(HttpUtil.post(secret(), message.toString())); + } + + /** + * 获取签名后的请求路径 + * + * @author lingting 2020-06-11 00:13:55 + */ + @SneakyThrows + public String secret() { + long timestamp = System.currentTimeMillis(); + String stringToSign = timestamp + "\n" + secret; + Mac mac = Mac.getInstance("HmacSHA256"); + mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256")); + byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8)); + String encode = URLEncoder.encode(Base64.encode(signData), "UTF-8"); + return url + "×tamp=" + timestamp + "&sign=" + encode; + } +} diff --git a/ballcat-extends/ballcat-extend-ding-talk/src/main/java/com/hccake/extend/ding/talk/enums/ActionBtnOrientationEnum.java b/ballcat-extends/ballcat-extend-ding-talk/src/main/java/com/hccake/extend/ding/talk/enums/ActionBtnOrientationEnum.java new file mode 100644 index 00000000..353820f4 --- /dev/null +++ b/ballcat-extends/ballcat-extend-ding-talk/src/main/java/com/hccake/extend/ding/talk/enums/ActionBtnOrientationEnum.java @@ -0,0 +1,22 @@ +package com.hccake.extend.ding.talk.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 跳转 ActionCard 类型 消息的按钮排列方式 + * + * @author lingting 2020/6/10 23:44 + */ +@Getter +@AllArgsConstructor +public enum ActionBtnOrientationEnum { + /** + * 按钮排列样式值 说明 + */ + VERTICAL("0", "按钮竖向排列"), + HORIZONTAL("1", "按钮横向排列"), + ; + private final String val; + private final String text; +} diff --git a/ballcat-extends/ballcat-extend-ding-talk/src/main/java/com/hccake/extend/ding/talk/enums/MessageTypeEnum.java b/ballcat-extends/ballcat-extend-ding-talk/src/main/java/com/hccake/extend/ding/talk/enums/MessageTypeEnum.java new file mode 100644 index 00000000..53fa1822 --- /dev/null +++ b/ballcat-extends/ballcat-extend-ding-talk/src/main/java/com/hccake/extend/ding/talk/enums/MessageTypeEnum.java @@ -0,0 +1,24 @@ +package com.hccake.extend.ding.talk.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 钉钉消息类型 + * + * @author lingting 2020/6/10 21:29 + */ +@Getter +@AllArgsConstructor +public enum MessageTypeEnum { + /** + * 消息值 消息说明 + */ + TEXT("text", "文本"), + LINK("link", "链接"), + MARKDOWN("markdown", "markdown"), + ACTION_CARD("actionCard", "跳转 actionCard 类型"), + ; + private final String val; + private final String desc; +} diff --git a/ballcat-extends/ballcat-extend-ding-talk/src/main/java/com/hccake/extend/ding/talk/message/AbstractDingTalkMessage.java b/ballcat-extends/ballcat-extend-ding-talk/src/main/java/com/hccake/extend/ding/talk/message/AbstractDingTalkMessage.java new file mode 100644 index 00000000..7d02d3df --- /dev/null +++ b/ballcat-extends/ballcat-extend-ding-talk/src/main/java/com/hccake/extend/ding/talk/message/AbstractDingTalkMessage.java @@ -0,0 +1,71 @@ +package com.hccake.extend.ding.talk.message; + +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.hccake.extend.ding.talk.enums.MessageTypeEnum; +import lombok.SneakyThrows; + +import java.util.HashSet; +import java.util.Set; + +/** + * 钉钉消息基础类 + * + * @author lingting 2020/6/10 21:28 + */ +public abstract class AbstractDingTalkMessage implements DingTalkMessage { + /** + * at 的人的手机号码 + */ + private final Set atPhones = new HashSet<>(); + /** + * 是否 at 所有人 + */ + private boolean atAll = false; + + public AbstractDingTalkMessage atAll() { + atAll = true; + return this; + } + + /** + * 添加 at 对象的手机号 + * + * @author lingting 2020-06-10 21:57:08 + */ + public AbstractDingTalkMessage addPhone(String phone) { + atPhones.add(phone); + return this; + } + + /** + * 获取消息类型 + * + * @return 返回消息类型 + * @author lingting 2020-06-10 22:12:30 + */ + public abstract MessageTypeEnum getType(); + + /** + * 生成内容json + * + * @return 返回生成的json字符串 + * @author lingting 2020-06-10 22:11:04 + */ + public abstract JSONObject json(); + + @Override + @SneakyThrows + public String toString() { + JSONObject json = new JSONObject(); + json.put("msgtype", getType().getVal()); + json.putAll(json()); + json.put( + "at", + new JSONObject() + .put("isAtAll", atAll) + .put("atMobiles", JSONUtil.toJsonStr(atPhones)) + ); + return json.toString(); + } +} diff --git a/ballcat-extends/ballcat-extend-ding-talk/src/main/java/com/hccake/extend/ding/talk/message/DingTalkActionCardMessage.java b/ballcat-extends/ballcat-extend-ding-talk/src/main/java/com/hccake/extend/ding/talk/message/DingTalkActionCardMessage.java new file mode 100644 index 00000000..9c41dbcc --- /dev/null +++ b/ballcat-extends/ballcat-extend-ding-talk/src/main/java/com/hccake/extend/ding/talk/message/DingTalkActionCardMessage.java @@ -0,0 +1,97 @@ +package com.hccake.extend.ding.talk.message; + +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.hccake.ballcat.common.core.markdown.MarkdownBuilder; +import com.hccake.extend.ding.talk.enums.ActionBtnOrientationEnum; +import com.hccake.extend.ding.talk.enums.MessageTypeEnum; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +import java.util.ArrayList; +import java.util.List; + +/** + * 跳转 ActionCard类型 + * + * @author lingting 2020/6/10 23:39 + */ +@Getter +@Setter +@Accessors(chain = true) +public class DingTalkActionCardMessage extends AbstractDingTalkMessage { + private String title; + /** + * 内容 + */ + private MarkdownBuilder text; + /** + * 按钮排列样式 默认横 + */ + private ActionBtnOrientationEnum orientation = ActionBtnOrientationEnum.HORIZONTAL; + /** + * 单个按钮的标题 + */ + private String singleTitle; + /** + * 点击singleTitle按钮触发的URL + */ + private String singleUrl; + + /** + * 自定义按钮组 如果配置了 按钮组 则 单按钮配置无效 + */ + private List