前段时间做项目时遇到调用钉钉推送群消息的需求,研究钉钉开发文档和各种搜集相关内容的帖子,整理并实现推送功能,感兴趣的朋友们一起探讨一下吧。
一、准备工作
1、在钉钉群内创建机器人,群设置->智能群助手->添加机器人->自定义;
*填写机器人的名字,检查添加到的群组对不对,安全设置选择加签并复制密钥,程序中会用到。
*获取到Webhook地址,复制下来,程序中会用到
准备工作到此完成。
二、编写功能逻辑
1.获取请求的url
/**
* errcode处理
*
* @param resultStr
*/
private static void handleErrorCode(String resultStr) {
if (StringUtils.isEmpty(resultStr)) {
throw new RuntimeException("返回结果为空");
}
JSONObject jsonObject = JSONObject.parseObject(resultStr);
if (310000 == jsonObject.getLong("errcode")) {
throw new RuntimeException("keywords not in content");
}
}
2.报错处理
/**
* 获取请求url
*
* @return 钉钉机器人地址
*/
private static String getDingUrl() throws Exception {
// 获取系统时间戳
Long timestamp = System.currentTimeMillis();
// 拼接
String stringToSign = timestamp + "\n" + SECRET;
// 使用HmacSHA256算法计算签名
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(SECRET.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
// 进行Base64 encode 得到最后的sign,可以拼接进url里
String sign = URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8");
// 钉钉机器人地址(配置机器人的webhook),为了让每次请求不同,避免钉钉拦截,加上时间戳
String dingUrl = WEBHOOK + "×tamp=" + timestamp + "&sign=" + sign;
return dingUrl;
}
3. 发送消息
1).发送文本类型消息
/**
* 群里面发送消息
*
* @param content 消息内容
* @param isAtAll 是否@所有人
* @param mobileList 被@人的手机号
* @param userIdList 被@人的用户userid
* @throws Exception
*/
public static void sendTextMsg(String content, List<String> mobileList, List<String> userIdList, boolean isAtAll) throws Exception {
String dingUrl = getDingUrl();
// 组装请求内容
String reqStr = buildReqTextStr(content, isAtAll, mobileList, userIdList);
// 推送消息(http请求)
//由于用到的是公司网络需要配置代理才能连接外网,不需要代理的可以删除HttpProxy设置
String result = HttpRequest.post(dingUrl).setHttpProxy(HOST, PORT).body(reqStr).execute().body();
handleErrorCode(result);
logger.info("钉钉请求发送成功,返回结果:" + result);
}
/**
* 组装请求报文-text类型
*
* @param content 消息内容
* @param isAtAll 是否@所有人
* @param mobileList 被@人的手机号
* @param atUserIds 被@人的用户userid
* @return
*/
public static String buildReqTextStr(String content, boolean isAtAll, List<String> mobileList, List<String> atUserIds) {
Map<String, String> contentMap = Maps.newHashMap();
contentMap.put("content", content);
Map<String, Object> atMap = Maps.newHashMap();
atMap.put("isAtAll", isAtAll);
atMap.put("atMobiles", mobileList);
atMap.put("atUserIds", atUserIds);
Map<String, Object> reqMap = Maps.newHashMap();
reqMap.put("msgtype", "text");
reqMap.put("text", contentMap);
reqMap.put("at", atMap);
return JSONObject.toJSONString(reqMap);
}
2).发送带有网页跳转的消息
/**
* 群里面发送消息
*
* @param title 消息标题
* @param messageUrl 点击消息跳转的URL
* @param picUrl 图片URL
* @param text 消息内容
* @throws Exception
*/
public static void sendLinkMsg(String title, String text, String messageUrl, String picUrl) throws Exception {
String dingUrl = getDingUrl();
// 组装请求内容
String reqStr = buildReqLinkStr(title, text, messageUrl, picUrl);
// 推送消息(http请求)
//由于用到的是公司网络需要配置代理才能连接外网,不需要代理的可以删除HttpProxy设置
String result = HttpRequest.post(dingUrl).setHttpProxy(HOST, PORT).body(reqStr).execute().body();
handleErrorCode(result);
logger.info("钉钉请求发送成功,返回结果:" + result);
}
/**
* 组装请求报文-link类型
*
* @param title 消息标题
* @param text 消息内容
* @param messageUrl 点击消息跳转的URL
* @param picUrl 图片URL
* @return
*/
private static String buildReqLinkStr(String title, String text, String messageUrl, String picUrl) {
Map<String, String> linkMap = Maps.newHashMap();
linkMap.put("text", text);
linkMap.put("title", title);
linkMap.put("picUrl", picUrl);
linkMap.put("messageUrl", messageUrl);
Map<String, Object> reqMap = Maps.newHashMap();
reqMap.put("msgtype", "link");
reqMap.put("link", linkMap);
return JSONObject.toJSONString(reqMap);
}
3).发送markdown类型消息
/**
* 群里面发送消息
*
* @param title 首屏会话透出的展示内容
* @param text markdown格式的消息
* @param isAtAll 是否@所有人
* @param mobileList 被@人的手机号
* @param atUserIds 被@人的用户userid
* @throws Exception
*/
public static void sendMarkdownMsg(String title, String text, boolean isAtAll, List<String> mobileList, List<String> atUserIds) throws Exception {
String dingUrl = getDingUrl();
// 组装请求内容
String reqStr = buildReqMarkdownStr(title, text, isAtAll, mobileList, atUserIds);
// 推送消息(http请求)
//由于用到的是公司网络需要配置代理才能连接外网,不需要代理的可以删除HttpProxy设置
String result = HttpRequest.post(dingUrl).setHttpProxy(HOST, PORT).body(reqStr).execute().body();
handleErrorCode(result);
logger.info("钉钉请求发送成功,返回结果:" + result);
}
/**
* 组装请求报文-markdown类型
*
* @param title 首屏会话透出的展示内容
* @param text markdown格式的消息
* @param isAtAll 是否@所有人
* @param mobileList 被@人的手机号
* @param atUserIds 被@人的用户userid
* @return
*/
private static String buildReqMarkdownStr(String title, String text, boolean isAtAll, List<String> mobileList, List<String> atUserIds) {
Map<String, String> contentMap = Maps.newHashMap();
contentMap.put("title", title);
contentMap.put("text", text);
Map<String, Object> atMap = Maps.newHashMap();
atMap.put("isAtAll", isAtAll);
atMap.put("atMobiles", mobileList);
atMap.put("atUserIds", atUserIds);
Map<String, Object> reqMap = Maps.newHashMap();
reqMap.put("msgtype", "markdown");
reqMap.put("markdown", contentMap);
reqMap.put("at", atMap);
return JSONObject.toJSONString(reqMap);
}
4).整体跳转和独立跳转ActionCard类型
/**
* 群里面发送消息
*
* @param title 首屏会话透出的展示内容
* @param text markdown格式的消息
* @param btnOrientation 0:按钮竖直排列 1:按钮横向排列
* @param singleTitle 单个按钮的标题
* @param singleURL 点击消息跳转的URL
* @throws Exception
*/
public static void sendActionCardMsg(String title, String text, String btnOrientation, String singleTitle, String singleURL) throws Exception {
String dingUrl = getDingUrl();
// 组装请求内容
String reqStr = buildReqActionCard(title, text, btnOrientation, singleTitle, singleURL);
// 推送消息(http请求)
//由于用到的是公司网络需要配置代理才能连接外网,不需要代理的可以删除HttpProxy设置
String result = HttpRequest.post(dingUrl).setHttpProxy(HOST, PORT).body(reqStr).execute().body();
handleErrorCode(result);
logger.info("钉钉请求发送成功,返回结果:" + result);
}
/**
* 组装请求报文-整体跳转ActionCard类型
*
* @param title 首屏会话透出的展示内容
* @param text markdown格式的消息
* @param btnOrientation 0:按钮竖直排列 1:按钮横向排列
* @param singleTitle 单个按钮的标题
* @param singleURL 点击消息跳转的URL
* @return
*/
private static String buildReqActionCard(String title, String text, String btnOrientation, String singleTitle, String singleURL) {
Map<String, String> actionCardMap = Maps.newHashMap();
actionCardMap.put("title", title);
actionCardMap.put("text", text);
actionCardMap.put("btnOrientation", btnOrientation);
actionCardMap.put("singleTitle", singleTitle);
actionCardMap.put("singleURL", singleURL);
Map<String, Object> reqMap = Maps.newHashMap();
reqMap.put("msgtype", "actionCard");
reqMap.put("actionCard", actionCardMap);
return JSONObject.toJSONString(reqMap);
}
/**
* 群里面发送消息
*
* @param title 首屏会话透出的展示内容
* @param text markdown格式的消息
* @param btnOrientation 0:按钮竖直排列 1:按钮横向排列
* @param btnsList 按钮
* @throws Exception
*/
public static void sendActionCardMsg(String title, String text, String btnOrientation, List<Map<String, String>> btnsList) throws Exception {
String dingUrl = getDingUrl();
// 组装请求内容
String reqStr = buildReqActionCard(title, text, btnOrientation, btnsList);
// 推送消息(http请求)
//由于用到的是公司网络需要配置代理才能连接外网,不需要代理的可以删除HttpProxy设置
String result = HttpRequest.post(dingUrl).setHttpProxy(HOST, PORT).body(reqStr).execute().body();
handleErrorCode(result);
logger.info("钉钉请求发送成功,返回结果:" + result);
}
/**
* 组装请求报文-独立跳转ActionCard类型
*
* @param title 首屏会话透出的展示内容
* @param text markdown格式的消息
* @param btnOrientation 0:按钮竖直排列 1:按钮横向排列
* @param btnsList 按钮
* @return
*/
private static String buildReqActionCard(String title, String text, String btnOrientation, List<Map<String, String>> btnsList) {
Map<String, Object> actionCardMap = Maps.newHashMap();
actionCardMap.put("title", title);
actionCardMap.put("text", text);
actionCardMap.put("btnOrientation", btnOrientation);
actionCardMap.put("btns", btnsList);
Map<String, Object> reqMap = Maps.newHashMap();
reqMap.put("msgtype", "actionCard");
reqMap.put("actionCard", actionCardMap);
return JSONObject.toJSONString(reqMap);
}
5). 发送freedCard类型消息
/**
* 群里面发送消息
*
* @param linksList 列表集合
* @throws Exception
*/
public static void sendFeedCardMsg(List<Map<String, String>> linksList) throws Exception {
String dingUrl = getDingUrl();
// 组装请求内容
String reqStr = buildReqFeedCard(linksList);
// 推送消息(http请求)
//由于用到的是公司网络需要配置代理才能连接外网,不需要代理的可以删除HttpProxy设置
String result = HttpRequest.post(dingUrl).setHttpProxy(HOST, PORT).body(reqStr).execute().body();
handleErrorCode(result);
logger.info("钉钉请求发送成功,返回结果:" + result);
}
/**
* 组装请求报文-FeedCard类型
*
* @param linksList 列表集合
* @return
*/
private static String buildReqFeedCard(List<Map<String, String>> linksList) {
Map<String, Object> feedCardMap = Maps.newHashMap();
feedCardMap.put("links", linksList);
Map<String, Object> reqMap = Maps.newHashMap();
reqMap.put("msgtype", "feedCard");
reqMap.put("feedCard", feedCardMap);
return JSONObject.toJSONString(reqMap);
}
以上就是整个工具类,没有太大难度,仔细看看每一块相互调用的逻辑就能掌握,此外这些消息的样式还需要自己探索,全部展示出来,就没有了探索精神