当前位置: 首页 > ds >正文

Java实现钉钉自定义机器人接入

Java实现钉钉自定义机器人接入

  • 1. 钉钉自定义机器人接入概述
    • 1.1 钉钉机器人简介
    • 1.2 自定义机器人接入
  • 2. 钉钉自定义机器人接入实现
    • 2.1 场景介绍
    • 2.2 调用频率限制
    • 2.3 创建钉钉群
    • 2.4 自定义机器人
    • 2.4 代码实现
    • 2.5 测试验证

1. 钉钉自定义机器人接入概述

1.1 钉钉机器人简介

在钉钉,机器人是独立存在的一个应用类型,可以开箱即用,也可以进行二次开发,无需和微应用或者群等场景进行强制绑定。

对于开发者而言,钉钉机器人是全局唯一的应用,即无论是在单聊中还是群聊中,都可以用来推送微应用的通知和用来对用户进行对话式服务,其对应的机器人ID都可以是唯一的。这意味着开发者既可以选择仅创建一个机器人,而后将其放在各个应用场景下使用,也可以创建多个机器人,然后分别部署再不同场景下。

上边是官方介绍,其实钉钉机器人就是在钉钉群里实现消息推送或者人机交互,从而可以实现企业业务核心业务流程的处理功能。
钉钉开放平台文档:https://open.dingtalk.com/document/robots/robot-overview

1.2 自定义机器人接入

钉钉开放平台文档中 机器人-自定义机器人接入下
自定义机器人接入是接入方式,自定义机器人安全设置是获取签名方式。

接入方式以及实现写的比较详细,具体可以参考官方文档,这里就不在重复,下边开始自己的实践验证。

2. 钉钉自定义机器人接入实现

2.1 场景介绍

企业内部有较多系统支撑着公司的核心业务流程,譬如CRM系统、交易系统、监控报警系统等等。通过钉钉的自定义机器人,可以将这些系统事件同步到钉钉的聊天群。

说明:当前机器人尚不支持应答机制,该机制指的是群里成员在聊天@机器人的时候,钉钉回调指定的服务地址,即Outgoing机器人

2.2 调用频率限制

由于消息发送太频繁会严重影响群的使用体验,因此自定义机器人发送消息的频率限制如下:
每个机器人每分钟最多发送20条消息到群里,如果超过20条,会限流10分钟。

注意:如果你有大量发消息的场景(譬如系统监控报警)可以将这些信息进行整合,通过markdown消息以摘要的形式发送到群里。

2.3 创建钉钉群

创建钉钉群:DingTalkRobot
钉钉窗口左上角用户加号-建场景群-私聊群-输入群名称-点击立即创建。
在这里插入图片描述

2.4 自定义机器人

群设置-智能群助手-添加机器人-自定义(通过Webhook接入自定义服务)

1.选择需要添加机器人的群聊,然后依次单击群设置 > 智能群助手。

2.在机器人管理页面选择自定义机器人,输入机器人名字并选择要发送消息的群,同时可以为机器人设置机器人头像。

3.完成必要的安全设置,勾选我已阅读并同意《自定义机器人服务及免责条款》,然后单击完成。

4.完成安全设置后,复制出机器人的Webhook地址,可用于向这个群发送消息。

5.具体配置信息

机器人名字:雪容融
接收群组:DingTalkRobot
消息推送:开启
Webhook:https://oapi.dingtalk.com/robot/send?access_token=7xxx478b
安全设置- 勾选 自定义关键词(关键词一定要包含在要发送的消息文本中,否则会推送失败)加签:SEC240d7bb4c0bafc62
IP地址 (段):192.168.10.11
以上这两个是选填,可选可不选,根据实际需要选择。

在这里插入图片描述

2.4 代码实现

1.mvn依赖
有两种依赖钉钉新版服务端SDK与旧版本依赖,目前两个版本各有不同的服务,未来计划新版会覆盖旧版本。
https://open.dingtalk.com/document/orgapp-server/differences-between-server-apis-and-new-server-apis
在这里插入图片描述

<!--钉钉新版服务端SDK-->
<dependency><groupId>com.aliyun</groupId><artifactId>dingtalk</artifactId><version>1.3.23</version>
</dependency>
<!--钉钉旧版服务端SDK-->
<dependency><groupId>com.aliyun</groupId><artifactId>alibaba-dingtalk-service-sdk</artifactId><version>2.0.0</version>
</dependency>

2.钉钉机器人工具类DingTalkUtils

package com.jerry.ding.utils;import cn.hutool.core.collection.ListUtil;
import com.alibaba.fastjson.JSON;
import com.aliyun.credentials.utils.StringUtils;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiRobotSendRequest;
import com.dingtalk.api.response.OapiRobotSendResponse;
import com.taobao.api.ApiException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.util.CollectionUtils;import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.List;/*** 钉钉机器人工具类** @author zrj* @since 2022/5/17**/
@Slf4j
public class DingTalkUtils {/*** 钉钉群设置 webhook, 支持重置*/private static final String ACCESS_TOKEN = "https://oapi.dingtalk.com/robot/send?access_token=7ebb82478b";private static final String SECRET = "SEC240d620adf";/*** 消息类型*/private static final String MSG_TYPE_TEXT = "text";private static final String MSG_TYPE_LINK = "link";private static final String MSG_TYPE_MARKDOWN = "markdown";private static final String MSG_TYPE_ACTION_CARD = "actionCard";private static final String MSG_TYPE_FEED_CARD = "feedCard";/*** 客户端实例*/private static DingTalkClient client;static {try {client = new DefaultDingTalkClient(ACCESS_TOKEN + sign());} catch (NoSuchAlgorithmException | UnsupportedEncodingException | InvalidKeyException e) {e.printStackTrace();}}/*** 官方演示示例* title 是消息列表下透出的标题* text 是进入群后看到的消息内容* 注意事项:* 1.文本,链接,Markdown会存在覆盖,推送最后一个定义的消息* 2.自定义机器人关键字要包含在content或title中,text.setContent("");link.setTitle("");markdown.setTitle("");** @return OapiRobotSendResponse*/public static void sdkDemoJava() {//请求对象OapiRobotSendRequest request = new OapiRobotSendRequest();//链接request.setMsgtype("link");OapiRobotSendRequest.Link link = new OapiRobotSendRequest.Link();link.setMessageUrl("https://www.dingtalk.com/");link.setPicUrl("");link.setTitle("时代的火车向前开");link.setText("这个即将发布的新版本,创始人阿Q称它为红树林。而在此之前,每当面临重大升级,产品经理们都会取一个应景的代号,这一次,为什么是红树林");request.setLink(link);//Markdownrequest.setMsgtype("markdown");OapiRobotSendRequest.Markdown markdown = new OapiRobotSendRequest.Markdown();markdown.setTitle("南京的天气真好呀");markdown.setText("#### 南京的天气真好呀 @130****1239\n" +"> 9度,西北风1级,空气良89,相对温度73%\n\n" +"> ![screenshot](https://gw.alicdn.com/tfs/TB1ut3xxbsrBKNjSZFpXXcXhFXa-846-786.png)\n" +"> ###### 10点20分发布 [天气](http://www.thinkpage.cn/) \n");request.setMarkdown(markdown);//文本request.setMsgtype("text");OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text();text.setContent("大家好!我是 DingTalkRobot 机器人,很高兴为你们服务!");request.setText(text);OapiRobotSendRequest.At at = new OapiRobotSendRequest.At();at.setAtMobiles(Arrays.asList("130****1239"));// isAtAll类型如果不为Boolean,请升级至最新SDKat.setIsAtAll(true);at.setAtUserIds(Arrays.asList("109929", "32099"));request.setAt(at);try {OapiRobotSendResponse response = DingTalkUtils.client.execute(request);System.out.println("【DingTalkUtils】消息发送演示示例 响应参数:" + JSON.toJSONString(response));} catch (ApiException e) {log.error("[ApiException]: 消息发送演示示例, 异常捕获{}", e.getMessage());}}/*** 发送普通文本消息** @param content    文本消息* @param mobileList 指定@ 联系人* @param isAtAll    是否@ 全部联系人* @return OapiRobotSendResponse*/public static OapiRobotSendResponse sendMessageByText(String content, List<String> mobileList, boolean isAtAll) {if (StringUtils.isEmpty(content)) {return null;}//参数	参数类型	必须	说明//msgtype	String	是	消息类型,此时固定为:text//content	String	是	消息内容//atMobiles	Array	否	被@人的手机号(在content里添加@人的手机号)//isAtAll	bool	否	@所有人时:true,否则为:falseOapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text();text.setContent(content);OapiRobotSendRequest request = new OapiRobotSendRequest();if (!CollectionUtils.isEmpty(mobileList)) {// 发送消息并@ 以下手机号联系人OapiRobotSendRequest.At at = new OapiRobotSendRequest.At();at.setAtMobiles(mobileList);at.setIsAtAll(isAtAll);request.setAt(at);}request.setMsgtype(DingTalkUtils.MSG_TYPE_TEXT);request.setText(text);OapiRobotSendResponse response = new OapiRobotSendResponse();try {response = DingTalkUtils.client.execute(request);System.out.println("【DingTalkUtils】发送普通文本消息 响应参数:" + JSON.toJSONString(response));} catch (ApiException e) {log.error("[发送普通文本消息]: 发送消息失败, 异常捕获{}", e.getMessage());}return response;}/*** 发送link 类型消息** @param title      消息标题* @param text       消息内容* @param messageUrl 点击消息后跳转的url* @param picUrl     插入图片的url* @return OapiRobotSendResponse*/public static OapiRobotSendResponse sendMessageByLink(String title, String text, String messageUrl, String picUrl) {if (StringUtils.isEmpty(title) || StringUtils.isEmpty(text) || StringUtils.isEmpty(messageUrl)) {return null;}//参数	参数类型	必须	说明//msgtype	String	是	消息类型,此时固定为:link//title	String	是	消息标题//text	String	是	消息内容。如果太长只会部分展示//messageUrl	String	是	点击消息跳转的URL//picUrl	String	否	图片URLOapiRobotSendRequest.Link link = new OapiRobotSendRequest.Link();link.setTitle(title);link.setText(text);link.setMessageUrl(messageUrl);link.setPicUrl(picUrl);OapiRobotSendRequest request = new OapiRobotSendRequest();request.setMsgtype(DingTalkUtils.MSG_TYPE_LINK);request.setLink(link);OapiRobotSendResponse response = new OapiRobotSendResponse();try {response = DingTalkUtils.client.execute(request);System.out.println("【DingTalkUtils】发送link 响应参数:" + JSON.toJSONString(response));} catch (ApiException e) {log.error("[发送link 类型消息]: 发送消息失败, 异常捕获{}", e.getMessage());}return response;}/*** 发送Markdown 编辑格式的消息** @param title        标题* @param markdownText 支持markdown 编辑格式的文本信息* @param mobileList   消息@ 联系人* @param isAtAll      是否@ 全部* @return OapiRobotSendResponse*/public static OapiRobotSendResponse sendMessageByMarkdown(String title, String markdownText, List<String> mobileList, boolean isAtAll) {if (StringUtils.isEmpty(title) || StringUtils.isEmpty(markdownText)) {return null;}//参数	类型	必选	说明//msgtype	String	是	此消息类型为固定markdown//title	String	是	首屏会话透出的展示内容//text	String	是	markdown格式的消息//atMobiles	Array	否	被@人的手机号(在text内容里要有@手机号)//isAtAll	bool	否	@所有人时:true,否则为:falseOapiRobotSendRequest.Markdown markdown = new OapiRobotSendRequest.Markdown();markdown.setTitle(title);markdown.setText(markdownText);OapiRobotSendRequest request = new OapiRobotSendRequest();request.setMsgtype(DingTalkUtils.MSG_TYPE_MARKDOWN);request.setMarkdown(markdown);if (!CollectionUtils.isEmpty(mobileList)) {OapiRobotSendRequest.At at = new OapiRobotSendRequest.At();at.setIsAtAll(isAtAll);at.setAtMobiles(mobileList);request.setAt(at);}OapiRobotSendResponse response = new OapiRobotSendResponse();try {response = DingTalkUtils.client.execute(request);System.out.println("【DingTalkUtils】发送link 响应参数:" + JSON.toJSONString(response));} catch (ApiException e) {log.error("[发送link 类型消息]: 发送消息失败, 异常捕获{}", e.getMessage());}return response;}/*** 整体跳转ActionCard类型的消息发送** @param title          消息标题, 会话消息会展示标题* @param markdownText   markdown格式的消息* @param singleTitle    单个按钮的标题* @param singleURL      单个按钮的跳转链接* @param btnOrientation 是否横向排列(true 横向排列, false 纵向排列)* @param hideAvatar     是否隐藏发消息者头像(true 隐藏头像, false 不隐藏)* @return OapiRobotSendResponse*/public static OapiRobotSendResponse sendMessageByActionCardSingle(String title, String markdownText, String singleTitle, String singleURL, boolean btnOrientation, boolean hideAvatar) {if (StringUtils.isEmpty(title) || StringUtils.isEmpty(markdownText)) {return null;}//参数	类型	必选	说明//    msgtype	string	true	此消息类型为固定actionCard//    title	string	true	首屏会话透出的展示内容//    text	string	true	markdown格式的消息//    singleTitle	string	true	单个按钮的方案。(设置此项和singleURL后btns无效)//    singleURL	string	true	点击singleTitle按钮触发的URL//    btnOrientation	string	false	0-按钮竖直排列,1-按钮横向排列//    hideAvatar	string	false	0-正常发消息者头像,1-隐藏发消息者头像OapiRobotSendRequest.Actioncard actionCard = new OapiRobotSendRequest.Actioncard();actionCard.setTitle(title);actionCard.setText(markdownText);actionCard.setSingleTitle(singleTitle);actionCard.setSingleURL(singleURL);// 此处默认为0actionCard.setBtnOrientation(btnOrientation ? "1" : "0");// 此处默认为0actionCard.setHideAvatar(hideAvatar ? "1" : "0");OapiRobotSendRequest request = new OapiRobotSendRequest();request.setMsgtype(DingTalkUtils.MSG_TYPE_ACTION_CARD);request.setActionCard(actionCard);OapiRobotSendResponse response = new OapiRobotSendResponse();try {response = DingTalkUtils.client.execute(request);System.out.println("【DingTalkUtils】整体跳转ActionCard类型的发送消息 响应参数:" + JSON.toJSONString(response));} catch (ApiException e) {log.error("[发送ActionCard 类型消息]: 整体跳转ActionCard类型的发送消息失败, 异常捕获{}", e.getMessage());}return response;}/*** 独立跳转ActionCard类型 消息发送** @param title          标题* @param markdownText   文本* @param btns           按钮列表* @param btnOrientation 是否横向排列(true 横向排列, false 纵向排列)* @param hideAvatar     是否隐藏发消息者头像(true 隐藏头像, false 不隐藏)* @return OapiRobotSendResponse*/public static OapiRobotSendResponse sendMessageByActionCardMulti(String title, String markdownText, List<OapiRobotSendRequest.Btns> btns, boolean btnOrientation, boolean hideAvatar) {if (StringUtils.isEmpty(title) || StringUtils.isEmpty(markdownText) || CollectionUtils.isEmpty(btns)) {return null;}//参数	类型	必选	说明//msgtype	string	true	此消息类型为固定actionCard//title	string	true	首屏会话透出的展示内容//text	string	true	markdown格式的消息//btns	array	true	按钮的信息:title-按钮方案,actionURL-点击按钮触发的URL//btnOrientation	string	false	0-按钮竖直排列,1-按钮横向排列//hideAvatar	string	false	0-正常发消息者头像,1-隐藏发消息者头像OapiRobotSendRequest.Actioncard actionCard = new OapiRobotSendRequest.Actioncard();actionCard.setTitle(title);actionCard.setText(markdownText);// 此处默认为0actionCard.setBtnOrientation(btnOrientation ? "1" : "0");// 此处默认为0actionCard.setHideAvatar(hideAvatar ? "1" : "0");actionCard.setBtns(btns);OapiRobotSendRequest request = new OapiRobotSendRequest();request.setMsgtype(DingTalkUtils.MSG_TYPE_ACTION_CARD);request.setActionCard(actionCard);OapiRobotSendResponse response = new OapiRobotSendResponse();try {response = DingTalkUtils.client.execute(request);System.out.println("【DingTalkUtils】独立跳转ActionCard类型发送消息 响应参数:" + JSON.toJSONString(response));} catch (ApiException e) {log.error("[发送ActionCard 类型消息]: 独立跳转ActionCard类型发送消息失败, 异常捕获{}", e.getMessage());}return response;}/*** 发送FeedCard类型消息** @param links* @return OapiRobotSendResponse*/public static OapiRobotSendResponse sendMessageByFeedCard(List<OapiRobotSendRequest.Links> links) {if (CollectionUtils.isEmpty(links)) {return null;}//msgtype	string	true	  此消息类型为固定feedCard//title	string	true	      单条信息文本//messageURL	string	true  点击单条信息到跳转链接//picURL	string	true	  单条信息后面图片的URLOapiRobotSendRequest.Feedcard feedcard = new OapiRobotSendRequest.Feedcard();feedcard.setLinks(links);OapiRobotSendRequest request = new OapiRobotSendRequest();request.setMsgtype(DingTalkUtils.MSG_TYPE_FEED_CARD);request.setFeedCard(feedcard);OapiRobotSendResponse response = new OapiRobotSendResponse();try {response = DingTalkUtils.client.execute(request);System.out.println("【DingTalkUtils】独立跳转ActionCard类型发送消息 响应参数:" + JSON.toJSONString(response));} catch (ApiException e) {log.error("[发送ActionCard 类型消息]: 独立跳转ActionCard类型发送消息失败, 异常捕获{}", e.getMessage());}return response;}/*** 获取签名* 把timestamp+"\n"+密钥当做签名字符串,使用HmacSHA256算法计算签名,然后进行Base64 encode,最后再把签名参数再进行urlEncode,得到最终的签名(需要使用UTF-8字符集)。* timestamp 当前时间戳,单位是毫秒,与请求调用时间误差不能超过1小时。* secret 密钥,机器人安全设置页面,加签一栏下面显示的SEC开头的字符串。** @param* @return java.lang.String*/private static String sign() throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException {Long timestamp = System.currentTimeMillis();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");return "&timestamp=" + timestamp + "&sign=" + sign;}/*** 测试** @param args* @return void*/public static void main(String args[]) {//官方演示示例//sdkDemoJava();//发送普通文本消息//ArrayList<String> userList = ListUtil.toList("130****1239");//sendMessageByText("大家好!我是 DingTalkRobot 机器人,很高兴为你们服务!", userList, true);//发送link 类型消息//String title = "时代的火车向前开";//String text = "这个即将发布的新版本,创始人阿Q称它为红树林。而在此之前,每当面临重大升级,产品经理们都会取一个应景的代号,这一次,为什么是红树林";//String messageUrl = "https://www.dingtalk.com/";//String picUrl = "https://gw.alicdn.com/tfs/TB1ut3xxbsrBKNjSZFpXXcXhFXa-846-786.png";//sendMessageByLink(title, text, messageUrl, picUrl);//发送Markdown 编辑格式的消息//String title = "南京的天气真好呀";//String markdownText = "#### 南京的天气真好呀 @130****1239\n" +//        "> 9度,西北风1级,空气良89,相对温度73%\n\n" +//        "> ![screenshot](https://gw.alicdn.com/tfs/TB1ut3xxbsrBKNjSZFpXXcXhFXa-846-786.png)\n" +//        "> ###### 10点20分发布 [天气](http://www.thinkpage.cn/) \n";//List<String> mobileList = ListUtil.toList("130****1239");//boolean isAtAll = true;//sendMessageByMarkdown(title, markdownText, mobileList, isAtAll);//整体跳转ActionCard类型的消息发送//String title = "南京的天气真好呀";//String markdownText = "#### 南京的天气真好呀 @130****1239\n" +//        "> 9度,西北风1级,空气良89,相对温度73%\n\n" +//        "> ![screenshot](https://gw.alicdn.com/tfs/TB1ut3xxbsrBKNjSZFpXXcXhFXa-846-786.png)\n" +//        "> ###### 10点20分发布 [天气](http://www.thinkpage.cn/) \n";//String singleTitle = "百度一下,啥也不知道";//String singleURL = "https://www.baidu.com/";//boolean btnOrientation = true;//boolean hideAvatar = false;//sendMessageByActionCardSingle(title, markdownText, singleTitle, singleURL, btnOrientation, hideAvatar);//独立跳转ActionCard类型 消息发送//String title = "南京的天气真好呀";//String markdownText = "#### 南京的天气真好呀 @130****1239\n" +//        "> 9度,西北风1级,空气良89,相对温度73%\n\n" +//        "> ![screenshot](https://gw.alicdn.com/tfs/TB1ut3xxbsrBKNjSZFpXXcXhFXa-846-786.png)\n" +//        "> ###### 10点20分发布 [天气](http://www.thinkpage.cn/) \n";////OapiRobotSendRequest.Btns btn = new OapiRobotSendRequest.Btns();//btn.setTitle("按钮-钉钉开放文档");//btn.setActionURL("https://open.dingtalk.com/");//List<OapiRobotSendRequest.Btns> btns = ListUtil.toList(btn);//boolean btnOrientation = true;//boolean hideAvatar = false;//sendMessageByActionCardMulti(title, markdownText, btns, btnOrientation, hideAvatar);//发送FeedCard类型消息OapiRobotSendRequest.Links link = new OapiRobotSendRequest.Links();link.setTitle("时代的火车向前开");link.setMessageURL("https://www.dingtalk.com/");link.setPicURL("https://gw.alicdn.com/tfs/TB1ut3xxbsrBKNjSZFpXXcXhFXa-846-786.png");List<OapiRobotSendRequest.Links> links = ListUtil.toList(link);sendMessageByFeedCard(links);}
}

2.5 测试验证

在这里插入图片描述

http://www.xdnf.cn/news/11302.html

相关文章:

  • Three.js(学习)
  • 云计算基础、Iass、Pass、Sass区别
  • 6-php的web环境安装
  • 【一文带你了解bluetooth】
  • 凶残的挖矿脚本,奴役我数千机器!
  • Google Web Designer for mac(专业网站设计工具)
  • 什么是金叉、死叉
  • java soap api操作和发送soap消息
  • numpy中的nonzero()
  • 什么是ip数据库
  • 安装 Windows 7 VM虚拟机
  • 重装系统基础教程
  • layout布局_关于 layout_weight,你到底知多少
  • 硅基流动完成近亿元融资:加速生成式AI技术普惠进程
  • 想要自己制作一款游戏,需要掌握哪些基本技能
  • android HorizontalScrollView讲解
  • 3D动画软件
  • 电脑操作系统的安装
  • RapidXML的使用
  • Qt 是一个功能强大的跨平台开发框架
  • match_parent和wrap_content的区别
  • C++语法基础--ostream,cout及其格式控制,缓冲区
  • electron一键生成项目图标
  • 抖音短视频常用的scheme跳转协议地址,直播间Intent跳转
  • 华为“天才少年”有多牛?入职不到一年,算法就用于千万台华为手机
  • 黑客入门教程(非常详细)从零基础入门到精通,看完这一篇就够了
  • WIN2016群集存储
  • IIS是什么
  • “大数据中台建设方案详解“
  • crashdump(crashdumps文件夹可以删除吗)