手写超级好用的钉钉机器人发送消息starter
文章目录
1.前言
由于业务上经常需要使用钉钉发送预警消息或者是发送一些运营数据消息等,平时经常写一些copy的代码,零零散散,那个工程要用就去copy一个过来,这种不易维护,且代码丑陋,重复代码多,且封装复用性差,所以我就说来写一个简单使用的starter,可以支持配置多个钉钉群的机器人的accessToken和secret,发送消息可以根据下标来构建一个对应类型的消息,然后调用一套好用简单的api就可以我完成发送消息,代码封装性和复用性强,哪个项目要用,只要引入依赖和配置以下就可以简单快速实现发送钉钉消息。
2.实现
2.1项目结构
后面经过修改又加了一个DingRobotMsgFeedCardLink类
2.2核心实现分享
EnableDingRobot注解
package com.zlf.starter;
import org.springframework.context.annotation.Import;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 在启动类上加上该注解
*
* @author zlf
* @date 2024/3/14
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DingRobotServiceConfiguration.class)
public @interface EnableDingRobot {
}
DingRobotServiceConfiguration类
package com.zlf.starter;
import com.zlf.config.DingRobotConfig;
import com.zlf.service.DingRobotService;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 钉钉机器人服务配置类
*
* @author zlf
* @date 2024/3/14
*/
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(DingRobotConfig.class)
public class DingRobotServiceConfiguration {
@Bean
public DingRobotService dingRobotService(DingRobotConfig dingRobotConfig) {
return new DingRobotService(dingRobotConfig);
}
}
DingRobotService类
package com.zlf.service;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.zlf.config.DingRobotConfig;
import com.zlf.config.RobotProperties;
import com.zlf.constants.ZlfDingRobotConstant;
import com.zlf.dto.DingRobotMsgDto;
import com.zlf.enums.DingRobotMsgTypeEnum;
import com.zlf.type.DingRobotMsg;
import com.zlf.type.DingRobotMsgActionCardButton;
import com.zlf.type.DingRobotMsgAt;
import com.zlf.type.DingRobotMsgFeedCard;
import com.zlf.type.DingRobotMsgLink;
import com.zlf.type.DingRobotMsgMarkdown;
import com.zlf.type.DingRobotMsgMoreActionCard;
import com.zlf.type.DingRobotMsgSingleActionCard;
import com.zlf.type.DingRobotMsgText;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@Slf4j
public class DingRobotService {
private DingRobotConfig dingRobotConfig;
public DingRobotService(DingRobotConfig dingRobotConfig) {
this.dingRobotConfig = dingRobotConfig;
}
/**
* 根据一个map构建一个markdown的字符串
* Map<String, Map<String, String>> map
* Map<String,String> map
*
* @param map
* @return
*/
public String buildMarkDownContent(Map<String, Object> map) {
DingRobotMsgDto dto = new DingRobotMsgDto(map);
String mdContent = dto.buildMarkdownMsgContent();
return mdContent;
}
public void sendMsgByIndex0(DingRobotMsg msg) {
String msgStr = this.buildMsg1(msg);
this.send(0, msgStr);
}
public void sendMsgByIndex0(DingRobotMsg msg, DingRobotMsgAt at) {
String msgStr = this.buildMsg1(msg, at);
this.send(0, msgStr);
}
public void sendMsgByIndex(int index, DingRobotMsg msg) {
String msgStr = this.buildMsg1(msg);
this.send(index, msgStr);
}
public void sendMsgByIndex(int index, DingRobotMsg msg, DingRobotMsgAt at) {
String msgStr = this.buildMsg0(msg, at);
this.send(index, msgStr);
}
public String buildMsg1(DingRobotMsg msg) {
return this.buildMsg0(msg, null);
}
public String buildMsg1(DingRobotMsg msg, DingRobotMsgAt at) {
return this.buildMsg0(msg, at);
}
public String buildMsg0(DingRobotMsg msg, DingRobotMsgAt at) {
this.checkMsg(msg, at);
HashMap<String, Object> param = new HashMap<>(3);
DingRobotMsgTypeEnum msgTypeEnum = msg.getMsgType();
String msgType = msgTypeEnum.getMsgType();
param.put("msgtype", msgType);
param.put(msgType, msg);
//是否@所有人
if (msg instanceof DingRobotMsgText) {
if (Objects.isNull(at)) {
param.put("at", new DingRobotMsgAt());
} else {
param.put("at", at);
}
} else if (msg instanceof DingRobotMsgMarkdown) {
if (Objects.isNull(at)) {
param.put("at", new DingRobotMsgAt());
} else {
param.put("at", at);
}
}
return JSON.toJSONString(param);
}
/**
* 检查消息参数
*
* @param msg
* @param at
*/
private void checkMsg(DingRobotMsg msg, DingRobotMsgAt at) {
if (Objects.isNull(msg)) {
throw new RuntimeException("DingRobotMsg参数不为空");
}
if (msg instanceof DingRobotMsgText) {
DingRobotMsgText msgText = (DingRobotMsgText) msg;
if (StringUtils.isEmpty(msgText.getContent())) {
throw new RuntimeException("发送" + msgText.getMsgType().getMsgType() + "类型消息的content不为空");
}
this.doContent(msg, at);
} else if (msg instanceof DingRobotMsgMarkdown) {
DingRobotMsgMarkdown msgMarkdown = (DingRobotMsgMarkdown) msg;
if (StringUtils.isEmpty(msgMarkdown.getTitle())) {
throw new RuntimeException("发送" + msgMarkdown.getMsgType().getMsgType() + "类型消息的title不为空");
}
if (StringUtils.isEmpty(msgMarkdown.getText())) {
throw new RuntimeException("发送" + msgMarkdown.getMsgType().getMsgType() + "类型消息的text不为空");
}
this.doContent(msg, at);
} else if (msg instanceof DingRobotMsgLink) {
DingRobotMsgLink msgLink = (DingRobotMsgLink) msg;
if (StringUtils.isEmpty(msgLink.getTitle())) {
throw new RuntimeException("发送" + msgLink.getMsgType().getMsgType() + "类型消息的title不为空");
}
if (StringUtils.isEmpty(msgLink.getText())) {
throw new RuntimeException("发送" + msgLink.getMsgType().getMsgType() + "类型消息的text不为空");
}
} else if (msg instanceof DingRobotMsgSingleActionCard) {
DingRobotMsgSingleActionCard singleActionCard = (DingRobotMsgSingleActionCard) msg;
if (StringUtils.isEmpty(singleActionCard.getTitle())) {
throw new RuntimeException("发送" + singleActionCard.getMsgType().getMsgType() + "类型消息的title不为空");
}
if (StringUtils.isEmpty(singleActionCard.getText())) {
throw new RuntimeException("发送" + singleActionCard.getMsgType().getMsgType() + "类型消息的text不为空");
}
if (StringUtils.isEmpty(singleActionCard.getSingleTitle())) {
throw new RuntimeException("发送" + singleActionCard.getMsgType().getMsgType() + "类型消息的singleTitle不为空");
}
if (StringUtils.isEmpty(singleActionCard.getSingleURL())) {
throw new RuntimeException("发送" + singleActionCard.getMsgType().getMsgType() + "类型消息的singleURL不为空");
}
} else if (msg instanceof DingRobotMsgMoreActionCard) {
DingRobotMsgMoreActionCard moreActionCard = (DingRobotMsgMoreActionCard) msg;
if (StringUtils.isEmpty(moreActionCard.getTitle())) {
throw new RuntimeException("发送" + moreActionCard.getMsgType().getMsgType() + "类型消息的title不为空");
}
if (StringUtils.isEmpty(moreActionCard.getText())) {
throw new RuntimeException("发送" + moreActionCard.getMsgType().getMsgType() + "类型消息的text不为空");
}
if (CollectionUtil.isEmpty(moreActionCard.getBtns())) {
throw new RuntimeException("发送" + moreActionCard.getMsgType().getMsgType() + "类型消息的btns不为空");
}
//校验btns
List<DingRobotMsgActionCardButton> btns = moreActionCard.getBtns();
for (DingRobotMsgActionCardButton btn : btns) {
if (StringUtils.isEmpty(btn.getTitle())) {
throw new RuntimeException("发送" + moreActionCard.getMsgType().getMsgType() + "类型消息的btns中title不为空");
}
if (StringUtils.isEmpty(btn.getActionURL())) {
throw new RuntimeException("发送" + moreActionCard.getMsgType().getMsgType() + "类型消息的btns中actionURL不为空");
}
}
} else if (msg instanceof DingRobotMsgFeedCard) {
DingRobotMsgFeedCard feedCard = (DingRobotMsgFeedCard) msg;
if (CollectionUtil.isEmpty(feedCard.getLinks())) {
throw new RuntimeException("发送" + feedCard.getMsgType().getMsgType() + "类型消息的links不为空");
}
//校验links
List<DingRobotMsgFeedCardLink> links = feedCard.getLinks();
for (DingRobotMsgFeedCardLink link : links) {
if (StringUtils.isEmpty(link.getTitle())) {
throw new RuntimeException("发送" + feedCard.getMsgType().getMsgType() + "类型消息的links中title不为空");
}
}
}
}
private void doContent(DingRobotMsg msg, DingRobotMsgAt at) {
if (Objects.nonNull(at) && CollectionUtil.isNotEmpty(at.getAtUserIds())) {
//userIds去重
List<String> atUserIds = at.getAtUserIds();
log.info("doContent.atUserIds:{}", JSON.toJSONString(atUserIds));
Set<String> atUserIdsSet = new HashSet<>(atUserIds);
List<String> atUserIdsNew = new ArrayList<>(atUserIdsSet);
log.info("doContent.atUserIdsNew:{}", JSON.toJSONString(atUserIdsNew));
at.setAtUserIds(atUserIdsNew);
StringBuffer sb = new StringBuffer();
atUserIdsNew.forEach(e -> {
sb.append("@" + e);
}
);
String userIdsNewStr = sb.toString();
log.info("DingRobotService.doContent.userIdsNewStr:{}", userIdsNewStr);
if (msg instanceof DingRobotMsgText) {
DingRobotMsgText msgText = (DingRobotMsgText) msg;
msgText.setContent(msgText.getContent() + userIdsNewStr);
log.info("DingRobotService.doContent.atUserIds.text-content:{}", msgText.getContent());
} else if (msg instanceof DingRobotMsgMarkdown) {
DingRobotMsgMarkdown msgMarkdown = (DingRobotMsgMarkdown) msg;
msgMarkdown.setText(msgMarkdown.getText() + userIdsNewStr);
log.info("DingRobotService.doContent.atUserIds.markdown-text:{}", msgMarkdown.getText());
}
}
if (Objects.nonNull(at) && CollectionUtil.isNotEmpty(at.getAtMobiles())) {
List<String> atMobiles = at.getAtMobiles();
log.info("DingRobotService.doContent.atMobiles:{}", JSON.toJSONString(atMobiles));
//手机号去重
Set<String> atMobilesSet = new HashSet<>(atMobiles);
StringBuffer sb = new StringBuffer();
atMobilesSet.forEach(e -> {
sb.append("@" + e);
});
String atMobileStr = sb.toString();
log.info("DingRobotService.doContent.atMobileStr:{}", atMobileStr);
if (msg instanceof DingRobotMsgText) {
DingRobotMsgText msgText = (DingRobotMsgText) msg;
msgText.setContent(msgText.getContent() + atMobileStr);
log.info("DingRobotService.doContent.atMobiles.text-content:{}", msgText.getContent());
} else if (msg instanceof DingRobotMsgMarkdown) {
DingRobotMsgMarkdown msgMarkdown = (DingRobotMsgMarkdown) msg;
msgMarkdown.setText(msgMarkdown.getText() + atMobileStr);
log.info("DingRobotService.doContent.atMobiles.markdown-text:{}", msgMarkdown.getText());
}
}
if (Objects.nonNull(at) && (CollectionUtil.isNotEmpty(at.getAtMobiles()) || CollectionUtil.isNotEmpty(at.getAtUserIds()))) {
at.setIsAtAll(Boolean.FALSE);
}
}
private RobotProperties getRobotProperties(int index) {
List<RobotProperties> rbs = dingRobotConfig.getRbs();
if (CollectionUtil.isEmpty(rbs)) {
throw new RuntimeException("根据index获取RobotProperties为空");
}
return rbs.get(index);
}
private void send(int index, String msg) {
try {
RobotProperties p = this.getRobotProperties(index);
Long timestamp = System.currentTimeMillis();
String sign = getSign(p.getSecret(), timestamp);
if (StringUtils.isEmpty(sign)) {
log.error("【发送钉钉群消息】sign不为空,签名异常");
}
String url = ZlfDingRobotConstant.DING_URL + p.getAccessToken() + "×tamp=" + timestamp + "&sign=" + sign;
ThreadPoolService.getInstance().execute(
() -> {
log.info("【发送钉钉群消息】请求参数:url = {}, msg = {}", url, msg);
String res = HttpUtil.post(url, msg);
log.info("【发送钉钉群消息】消息响应结果:" + res);
});
} catch (Exception e) {
log.error("【发送钉钉群消息】请求钉钉接口异常,msg = {}", e);
}
}
private String getSign(String secret, Long timestamp) {
try {
String stringToSign = timestamp + "\n" + secret;
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
String sign = URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8");
log.info("【发送钉钉群消息】获取到签名sign = {}", sign);
return sign;
} catch (Exception e) {
log.error("【发送钉钉群消息】计算签名异常,errMsg = {}", e);
return null;
}
}
}
ThreadPoolService类
package com.zlf.service;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @author zlf
* @time: 2024/3/14
*/
@Slf4j
public class ThreadPoolService {
private static final int DEFAULT_CORE_SIZE = Runtime.getRuntime().availableProcessors();
private static final int MAX_QUEUE_SIZE = Runtime.getRuntime().availableProcessors();
private static final int QUEUE_INIT_MAX_SIZE = 500;
private volatile static ThreadPoolExecutor executor;
private ThreadPoolService() {
}
// 获取单例的线程池对象
public static ThreadPoolExecutor getInstance() {
if (executor == null) {
synchronized (ThreadPoolService.class) {
if (executor == null) {
//拒绝策略
executor = new ThreadPoolExecutor(
DEFAULT_CORE_SIZE,// 核心线程数
MAX_QUEUE_SIZE, // 最大线程数
10L, // 闲置线程存活时间
TimeUnit.SECONDS,// 时间单位
new LinkedBlockingDeque<>(QUEUE_INIT_MAX_SIZE),// 线程队列
Executors.defaultThreadFactory(),// 线程工厂
(r, executor) -> {
try {
executor.getQueue().put(r);
} catch (InterruptedException e) {
log.error("线程处理拒绝策略失败:{}", e.getMessage());
}
}
);
}
}
}
return executor;
}
public void execute(Runnable runnable) {
if (runnable == null) {
return;
}
executor.execute(runnable);
}
// 从线程队列中移除对象
public void cancel(Runnable runnable) {
if (executor != null) {
executor.getQueue().remove(runnable);
}
}
}
消息类型相关类的封装参看钉钉官网:
https://open.dingtalk.com/document/orgapp/robot-message-types-and-data-format#title-z74-8to-i7e
atUserIds这个参数我没有找到,因为我没有钉钉的管理员权限,需要登录钉钉后台查看,不是用户头像里面的钉钉号,可以参看钉钉官网的如下接口:
https://open.dingtalk.com/document/isvapp/query-the-list-of-department-userids
at手机号下面是测试是可以的,这个只是一个发消息的简单的api集成,可以拓展集成钉钉官方文档的其它接口,比如如下可以集成开发一个机器人服务端,发送消息到指定的钉钉群,然后服务端可以收到用户发的消息,然后机器人回复相应的消息:
https://open.dingtalk.com/document/orgapp/robot-receive-message
这只是一个例子,可以根据自己的需求来集成,官方提供的sdk,依赖的东西比较多,也不怎么好用,所以可以自己去造个符合自己需求和使用习惯的轮子。
3.配置使用
3.1 引入项目resources下libs中的jar包依赖如下
右键点击ding-robot-spring-boot-start-1.0-SNAPSHOT.jar将该jar包手动导入(add as Library),复制该jar包到resources下libs,若果maven自动导入就不用右键手动导入
<dependency>
<groupId>org.zlf</groupId>
<artifactId>ding-robot-spring-boot-start</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>system</scope>
<systemPath>${pom.basedir}/src/main/resources/libs/ding-robot-spring-boot-start-1.0-SNAPSHOT.jar
</systemPath>
</dependency>
3.2引入maven私服依赖如下
<dependency>
<groupId>org.zlf</groupId>
<artifactId>ding-robot-spring-boot-start</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
3.3yaml配置
zlf:
robot:
rbs:
- accessToken: xxxxxxx
secret: xxxxxxx
4.测试验证
在项目中引入3.2的依赖和配置好3.3的配置
然后写如下的controller
DingDingController类
package xxxx.controller;
import com.zlf.service.DingRobotService;
import com.zlf.type.DingRobotMsgActionCardButton;
import com.zlf.type.DingRobotMsgAt;
import com.zlf.type.DingRobotMsgLink;
import com.zlf.type.DingRobotMsgMarkdown;
import com.zlf.type.DingRobotMsgMoreActionCard;
import com.zlf.type.DingRobotMsgSingleActionCard;
import com.zlf.type.DingRobotMsgText;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@Slf4j
@RestController
@RequestMapping("ding")
public class DingDingController {
@Autowired
private DingRobotService dingRobotService;
@GetMapping("/sendMsg1")
public String sendMsg1(@RequestParam(value = "msg") String msg) {
DingRobotMsgText dingRobotMsgText = new DingRobotMsgText();
dingRobotMsgText.setContent(msg);
DingRobotMsgAt at = new DingRobotMsgAt();
/* List<String> mobiles = new ArrayList<>();
mobiles.add("xxxx");
mobiles.add("xxxxxx");
at.setAtMobiles(mobiles);*/
//xxxxxx
List<String> userIds = new ArrayList<>();
userIds.add("xxxxx");
userIds.add("xxxxx");
at.setAtUserIds(userIds);
dingRobotService.sendMsgByIndex0(dingRobotMsgText, at);
return "ok";
}
@GetMapping("/sendMsg2")
public String sendMsg2(@RequestParam(value = "msg") String msg) {
DingRobotMsgMarkdown msgMarkdown = new DingRobotMsgMarkdown();
msgMarkdown.setTitle("测试");
msgMarkdown.setText(msg);
dingRobotService.sendMsgByIndex0(msgMarkdown);
return "ok";
}
@GetMapping("/sendMsg3")
public String sendMsg() {
DingRobotMsgMarkdown msgMarkdown = new DingRobotMsgMarkdown();
msgMarkdown.setTitle("测试");
Map<String, Object> map = new LinkedHashMap<>();
map.put("title", "=====我是标题=====");
/*map.put("年龄", "28");
map.put("兴趣", "打球");*/
Map<String, String> map1 = new HashMap<>();
map1.put("姓名", "张三");
map1.put("年龄", "28");
Map<String, String> map2 = new HashMap<>();
map2.put("兴趣", "打球");
map.put("item1", map1);
map.put("item2", map2);
map.put("我是张三", "我是张三");
map.put("我是李四", "我是李四");
String msg = dingRobotService.buildMarkDownContent(map);
msgMarkdown.setText(msg);
DingRobotMsgAt at = new DingRobotMsgAt();
dingRobotService.sendMsgByIndex0(msgMarkdown,at);
return "ok";
}
@GetMapping("/sendMsg4")
public String sendMsg4() {
DingRobotMsgLink link = new DingRobotMsgLink();
link.setTitle("这是Link消息");
link.setText("这是一个Link消息");
link.setPicUrl("https://img.alicdn.com/tfs/TB1NwmBEL9TBuNjy1zbXXXpepXa-2400-1218.png");
link.setMessageUrl("https://open.dingtalk.com/document/");
dingRobotService.sendMsgByIndex0(link);
return "ok";
}
@GetMapping("/sendMsg5")
public String sendMsg5() {
DingRobotMsgSingleActionCard singleActionCard = new DingRobotMsgSingleActionCard();
singleActionCard.setTitle("打造一间咖啡厅");
singleActionCard.setText("![screenshot](https://img.alicdn.com/tfs/TB1NwmBEL9TBuNjy1zbXXXpepXa-2400-1218.png) \\n #### 乔布斯 20 年前想打造的苹果咖啡厅 \\n\\n Apple Store 的设计正从原来满满的科技感走向生活化,而其生活化的走向其实可以追溯到 20 年前苹果一个建立咖啡馆的计划");
singleActionCard.setSingleTitle("阅读全文");
singleActionCard.setSingleURL("https://www.dingtalk.com/");
dingRobotService.sendMsgByIndex0(singleActionCard);
return "ok";
}
@GetMapping("/sendMsg6")
public String sendMsg6() {
DingRobotMsgMoreActionCard moreActionCard = new DingRobotMsgMoreActionCard();
moreActionCard.setTitle("打造一间咖啡厅");
moreActionCard.setText("![screenshot](https://img.alicdn.com/tfs/TB1NwmBEL9TBuNjy1zbXXXpepXa-2400-1218.png) \\n #### 乔布斯 20 年前想打造的苹果咖啡厅 \\n\\n Apple Store 的设计正从原来满满的科技感走向生活化,而其生活化的走向其实可以追溯到 20 年前苹果一个建立咖啡馆的计划");
List<DingRobotMsgActionCardButton> btns = new ArrayList<>();
DingRobotMsgActionCardButton bt1 = new DingRobotMsgActionCardButton();
bt1.setTitle("内容不错");
bt1.setActionURL("https://www.dingtalk.com/");
DingRobotMsgActionCardButton bt2 = new DingRobotMsgActionCardButton();
bt2.setTitle("不感兴趣");
bt2.setActionURL("https://www.dingtalk.com/");
btns.add(bt1);
btns.add(bt2);
moreActionCard.setBtns(btns);
dingRobotService.sendMsgByIndex0(moreActionCard);
return "ok";
}
@GetMapping("/sendMsg7")
public String sendMsg7() {
DingRobotMsgFeedCard feedCard = new DingRobotMsgFeedCard();
List<DingRobotMsgFeedCardLink> links = new ArrayList<>();
DingRobotMsgFeedCardLink link = new DingRobotMsgFeedCardLink();
link.setTitle("时代的火车向前开1");
link.setMessageURL("https://www.dingtalk.com/");
link.setPicURL("https://img.alicdn.com/tfs/TB1NwmBEL9TBuNjy1zbXXXpepXa-2400-1218.png");
DingRobotMsgFeedCardLink link2 = new DingRobotMsgFeedCardLink();
link2.setTitle("时代的火车向前开2");
link2.setMessageURL("https://www.dingtalk.com/");
link2.setPicURL("https://img.alicdn.com/tfs/TB1NwmBEL9TBuNjy1zbXXXpepXa-2400-1218.png");
links.add(link);
links.add(link2);
feedCard.setLinks(links);
dingRobotService.sendMsgByIndex0(feedCard);
}
}
4.1测试实现效果如下
只有text和markdown消息支持at参数,at参数可选
4.1.1.发送text消息
4.1.2.发送markdown消息
4.1.3.发送link消息
4.1.4.发送单actionCard消息
4.1.5.发送多actionCard消息
4.1.6.发送feedCard消息
4.1.7.发送自定义markdown消息
这个就是我们业务上最常用的发消息的样子,使用一个Map<String,Object>来实现,Object可以放String和一个Map<String,String>,可以使用有序Map和无序Map,所以我就实现了一个默认的,还可以自定义一个markdown消息的text,只不过需要自己去拼接text,也比较麻烦。
5.总结
通过以上的分享就实现了一个使用钉钉机器人发消息的starter,希望我的分享对你有所帮助和启发,请一键三连,么么哒,下期分享见!