钉钉发送群消息是常用的业务场景,现在详细来说下
建好钉钉群,建好机器人
这些参数在建立机器人后会自动给你的,这两参数比较重要,然代码识别知道哪个钉钉群和哪个机器人需要发送消息。
首先测试钉钉方法
/**
* @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);
("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;
}