钉钉发送群消息是常用的业务场景,现在详细来说下
建好钉钉群,建好机器人
这些参数在建立机器人后会自动给你的,这两参数比较重要,然代码识别知道哪个钉钉群和哪个机器人需要发送消息。
首先测试钉钉方法
/** * @author samxie * @version 1.0 * @date 2022/3/22 15:54 **/ @Slf4j public class test { public static void main(String[] args) { DingReportFailMessageListener dingReportFailMessageListener = new DingReportFailMessageListener(); DingReportFailMessage dingReportFailMessage = new DingReportFailMessage(); dingReportFailMessage.setUserName("samxie"); dingReportFailMessage.setUserId(String.valueOf(23)); dingReportFailMessage.setReportInstanceId(12222233344L); dingReportFailMessage.setReportType("铺位评估"); dingReportFailMessage.setReportName("测试报告"); dingReportFailMessage.setFailDesc("org.springframework.beans.factory.BeanDefinitionStoreException:"); Date now = DateUtils.getNow(); String dayTime = DateUtils.formatYYYYMMDDHHMMSS(now); dingReportFailMessage.setCreateTime(dayTime); dingReportFailMessageListener.sendDingDingTest(dingReportFailMessage); } }
测试发送钉钉消息
public void sendDingDingTest(DingReportFailMessage reportMessage) { //钉钉报告地址 String dingWebHookUrl = "****"; //钉钉报告机密钥 String reportSecret = "********"; /**钉钉报告消息体 报告预警提示~\n用户昵称:%s\n用户ID:%s\n报告编号:%s\n报告类型:%s\n报告名称:%s\n * 预警描述:%s\n报告预警时间:%s */ String messageBody = "报告预警提示~%s用户昵称:%s用户ID:%s报告编号:" + "%s报告类型:%s报告名称:%s预警描述:%s报告预警时间:%s"; if (StringUtils.isEmpty(messageBody) || StringUtils.isEmpty(dingWebHookUrl) || StringUtils.isEmpty(reportSecret)) { log.info("发送报告钉钉消息, 消息配置项未配置"); }
//请求消息 String sendMessage = String.format(messageBody, "\n", reportMessage.getUserName() + "\n", reportMessage.getUserId() + "\n", reportMessage.getReportInstanceId() + "\n", reportMessage.getReportType() + "\n", reportMessage.getReportName() + "\n", reportMessage.getFailDesc() + "\n", reportMessage.getCreateTime()); //钉钉消息 String dingMessage = DingMessageUtil.generateMessageBody(sendMessage, false, null); //发送钉钉消息 DingMessageUtil.sendMessage(reportSecret, dingMessage, dingWebHookUrl); } /** * 组装请求报文 * @param content 通知内容 * @param isNotifyAll 是否通知所有人 * @param mobileList 通知手机号 * @return */ public static String generateMessageBody(String content, boolean isNotifyAll, List<String> mobileList) { // 消息内容 Map<String, String> contentMap = new HashMap<>(16); contentMap.put("content", content); // 通知人 Map<String, Object> atMap = new HashMap<>(16); // 是否通知所有人 atMap.put("isAtAll", isNotifyAll); // 通知具体人的手机号码列表 atMap.put("atMobiles", mobileList); Map<String, Object> reqMap = new HashMap<>(16); reqMap.put("msgtype", "text"); reqMap.put("text", contentMap); reqMap.put("at", atMap); return JSONObject.toJSONString(reqMap); } /** * 钉钉发送消息 * @param secret 钉钉机器人密钥 * @param message 消息 * @param dingUrl 钉钉机器人hook地址 */ public static void sendMessage(String secret, String message, String dingUrl) { final String actionLog = "【发送钉钉消息】"; log.info("{}, secret:{}, message:{}, dingUrl:{}, mobileList:{}", actionLog, secret, message, dingUrl); try { // 系统时间戳 Long timestamp = System.currentTimeMillis(); // 拼接 String signStr = timestamp + "\n" + secret; // 使用HmacSHA256算法计算签名 Mac mac = Mac.getInstance("HmacSHA256"); mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256")); byte[] signData = mac.doFinal(signStr.getBytes("UTF-8")); String sign = URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8"); String requestUrl = dingUrl + "×tamp=" + timestamp + "&sign=" + sign; // 推送消息(http请求) HttpPost httpPost = new HttpPost(requestUrl.trim()); RequestConfig requestConfig = RequestConfig.custom() .setConnectTimeout(30000) .setConnectionRequestTimeout(30000) .setSocketTimeout(30000).build(); httpPost.setConfig(requestConfig); // 设置参数 httpPost.setEntity(new StringEntity(message, ContentType.DEFAULT_TEXT.withCharset("UTF-8"))); httpPost.setHeader(new BasicHeader("Content-Type", "application/json")); // 发送请求,获取返回数据 String response = execute(httpPost); log.info("{}, 钉钉返回:{}", response); log.info("{}, 消息处理完毕"); } catch (Exception e) { e.printStackTrace(); } } private static String execute(HttpRequestBase requestBase) throws Exception { CloseableHttpClient httpclient = HttpClients.createDefault(); String body = null; try { CloseableHttpResponse response = httpclient.execute(requestBase); try { HttpEntity entity = response.getEntity(); if (entity != null) { body = EntityUtils.toString(entity, "UTF-8"); } EntityUtils.consume(entity); } catch (Exception e) { throw e; } finally { response.close(); } } catch (Exception e) { throw e; } finally { httpclient.close(); } return body; }
基本上就能发送成功消息,工具类组装了请求报文,然后发送过去就可以了。
下面进入写方法
/** * sendDingDing * * @return */ @Override public Boolean sendDingDing() { DingReportFailMessage dingReportFailMessage = new DingReportFailMessage(); dingReportFailMessage.setUserName("samxie"); dingReportFailMessage.setUserId(String.valueOf(23)); dingReportFailMessage.setReportInstanceId(12222233344L); dingReportFailMessage.setReportType("铺位评估"); dingReportFailMessage.setReportName("测试报告"); dingReportFailMessage.setFailDesc("org.springframework.beans.factory.BeanDefinitionStoreException:"); Date now = DateUtils.getNow(); String dayTime = DateUtils.formatYYYYMMDDHHMMSS(now); dingReportFailMessage.setCreateTime(dayTime); mqSend.sendDingReportFailMessage(dingReportFailMessage); return true; }
这里用的是mq异步提供给别的服务去调用的,上面测试类可以直接调用到它的
public interface IMqSend { /** * 发送钉钉预警消息 * @param dingReportFailMessage */ void sendDingReportFailMessage(DingReportFailMessage dingReportFailMessage); } 这里是发送预警消息的方法 /** * 发送钉钉预警消息 * * @param dingReportFailMessage */ @Override public void sendDingReportFailMessage(DingReportFailMessage dingReportFailMessage) { String message = JSON.toJSONString(dingReportFailMessage); LOGGER.info("sendDingReportFailMessage take success send message to mq message = {}", message); producerUtil.sendAsyncMsg(mqTopicConfig.getMessageTopic(), mqTopicConfig.getMessageTopicReportDingTag(), message, dingReportFailMessage.getReportInstanceId() + ""); }
这里两个参数配置是上面建立机器人的时候生成的,一般把它放到配置中就好了。
@Component @Data public class MqTopicConfig { @Value(value = "${message.config.messageTopic}") private String messageTopic; @Value(value = "${message.config.messageTopicReportDingTag}") private String messageTopicReportDingTag; }
监听器去消费消息,这里是发送预警消息的主要实现方法,包括了组装数据、发送钉钉通知。
@Slf4j @Component @Api(tags = "钉钉预警报告消息监控类") public class DingReportFailMessageListener extends MessageListener { @Autowired private MessageConfig messageConfig;
/** * 消费钉钉消息 * @param message * @param consumeContext * @return */ @Override public Action consume(Message message, ConsumeContext consumeContext) { try { Boolean notifyOpen = messageConfig.getNotifyOpen(); if (!notifyOpen) { log.info("报告通知开关已关闭或未配置 notifyOpen:{}", notifyOpen); return Action.CommitMessage; } //钉钉报告地址 String dingWebHookUrl = messageConfig.getDingReportUrl(); //钉钉报告机密钥 String reportSecret = messageConfig.getDingReportSecret(); /**钉钉报告消息体 报告预警提示~\n用户昵称:%s\n用户ID:%s\n报告编号:%s\n报告类型:%s\n报告名称:%s\n * 预警描述:%s\n报告预警时间:%s */ String messageBody = messageConfig.getDingReportMessageBody(); if (StringUtils.isEmpty(messageBody) || StringUtils.isEmpty(dingWebHookUrl) || StringUtils.isEmpty(reportSecret)) { log.info("发送报告钉钉消息, 消息配置项未配置"); return Action.CommitMessage; } //请求体 String requestBody = new String(message.getBody(), StandardCharsets.UTF_8); //报告消息体 DingReportFailMessage reportMessage = JSONObject.parseObject(requestBody, DingReportFailMessage.class); //请求消息 String sendMessage = String.format(messageBody, "\n", reportMessage.getUserName() + "\n", reportMessage.getUserId() + "\n", reportMessage.getReportInstanceId() + "\n", reportMessage.getReportType() + "\n", reportMessage.getReportName() + "\n", reportMessage.getFailDesc() + "\n", reportMessage.getCreateTime()); //钉钉消息 String dingMessage = DingMessageUtil.generateMessageBody(sendMessage, false, null); //发送钉钉消息 DingMessageUtil.sendMessage(reportSecret, dingMessage, dingWebHookUrl); return Action.CommitMessage; } catch (Exception e) { log.error("发送钉钉失败报告消息异常 e:{}", e); return Action.ReconsumeLater; } }
}
一些用到的配置文件定义
@ConfigurationProperties(prefix = "message.config") @Component @Data public class MessageConfig { @ApiModelProperty("钉钉报告机密钥") private String dingReportSecret; @ApiModelProperty("钉钉报告地址") private String dingReportUrl; @ApiModelProperty("钉钉报告密钥") private String dingOrderSecret; @ApiModelProperty("钉钉订单消息图片地址") private String dingOrderPicUrl; @ApiModelProperty("钉钉订单消息头部") private String dingOrderTitle; @ApiModelProperty("订单钉钉报告地址") private String dingOrderUrl; @ApiModelProperty("订单路由地址") private String orderRouteUrl; @ApiModelProperty("钉钉订单消息体") private String dingOrderMessageBody; @ApiModelProperty("钉钉报告消息体") private String dingReportMessageBody; @ApiModelProperty("消息开关") private Boolean notifyOpen; @ApiModelProperty("钉钉日报") private String dingDailyReportMessageBody; @ApiModelProperty("订单分配通知开关") private Boolean notifyDistributeOpen; @ApiModelProperty("分配订单通知密钥") private String dingDistributeSecret; @ApiModelProperty("分配通知地址") private String dingDistributeUrl; @ApiModelProperty("订单分配消息主体") private String dingDistributeMessageBody; @ApiModelProperty("topic") private String messageTopic; @ApiModelProperty("messageTopicReportDingTag") private String messageTopicReportDingTag; }
实体类
@Data public class DingReportFailMessage implements Serializable { private static final long serialVersionUID = -3901024808802199329L; /** * 有报告预警需要处理哟~\n 用户昵称:%s\n 用户ID:%s\n 报告编号:%s\n 报告类型:%s\n 报告名称:%s\n 预警描述:%s\n 报告预警时间:%s */ @ApiModelProperty("用户名称") private String userName; @ApiModelProperty("用户id") private String userId; @ApiModelProperty("报告实例id") private Long reportInstanceId; @ApiModelProperty("报告类型") private String reportType; @ApiModelProperty("报告名称") private String reportName; @ApiModelProperty("预警描述") private String failDesc; @ApiModelProperty("报告预警时间") private String createTime; }