利用钉钉自定义机器人监控NACOS服务,实现实时下线通知
自定义机器人步骤
- 创建一个钉钉群,拉人创建
- 在群设置中,选择自定义机器人
- 记住webhook 和 accessKey,用于代码中配置
钉钉实体类
@Data
public class MessageSender {
// 消息类型
private String messageType;
// 钉钉的 webhook URL
private String webhookUrl;
// 安全密钥
private String accessKey;
// 消息内容
private String messageContent;
// 指定的接收者手机号列表
private List<String> recipientMobiles;
// 是否发送给所有人
private boolean notifyAll;
}
监控代码
@Component
public class ServiceStatusMonitor {
private static final Logger logger = LoggerFactory.getLogger(ServiceStatusMonitor.class);
@Value("${dingtalk.webhook}")
private String webhook;
@Value("${dingtalk.secret}")
private String secret;
@Value("${dingtalk.userMobil}")
private String[] userMobil;
@Value("${dingtalk.namespace}")
private String namespace;
@Value("${spring.cloud.nacos.config.server-addr}")
private String nacosUrl;
private static Map<String, Integer> instanceCache = new ConcurrentHashMap<>();
// 初始化服务监控
@PostConstruct
public void initialize() throws Exception {
List<String> mobileList = Arrays.asList(userMobil);
Properties properties = System.getProperties();
properties.setProperty("serverAddr", nacosUrl);
properties.setProperty("namespace", namespace);
NamingService namingService = NamingFactory.createNamingService(properties);
List<String> monitoredServices = Arrays.asList("order", "serviceA", "serviceB"); // 监控的服务列表
for (String serviceName : monitoredServices) {
namingService.subscribe(serviceName, event -> {
List<Instance> instances = ((NamingEvent) event).getInstances();
instanceCache.computeIfAbsent(serviceName, k -> instances.size());
if (instances.size() < instanceCache.get(serviceName)) {
MessageSender alertMessage = new MessageSender();
alertMessage.setNotifyAll(false);
alertMessage.setMessageType("text");
alertMessage.setAccessKey(secret);
alertMessage.setWebhookUrl(webhook);
alertMessage.setRecipientMobiles(mobileList);
alertMessage.setMessageContent(serviceName + " 服务下线,当前在线节点数:" + instances.size());
DingTalkUtil.sendMessage(alertMessage);
logger.info("服务下线: " + serviceName);
instanceCache.put(serviceName, instances.size());
} else {
logger.info("服务上线: " + serviceName + ", 当前在线节点数:" + instances.size());
}
});
}
}
}
封装工具类
public class DingTalkUtils {
private static final Logger logger = LoggerFactory.getLogger(DingTalkUtils.class);
// 消息类型常量
private static final String MESSAGE_TYPE_TEXT = "text";
/**
* 发送钉钉消息
**/
public static void sendMessage(MessageSender message) {
try {
logger.info("准备发送钉钉消息:" + message);
Long timestamp = System.currentTimeMillis();
String secret = message.getAccessKey();
String signatureString = timestamp + "\n" + secret;
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
byte[] signedData = mac.doFinal(signatureString.getBytes("UTF-8"));
String signature = URLEncoder.encode(new String(Base64.encodeBase64(signedData)), "UTF-8");
DingTalkClient client = new DefaultDingTalkClient(message.getWebhookUrl() + "×tamp=" + timestamp + "&sign=" + signature);
OapiRobotSendRequest request = new OapiRobotSendRequest();
OapiRobotSendRequest.At at = new OapiRobotSendRequest.At();
if (message.isNotifyAll() || message.getRecipientMobiles() == null || message.getRecipientMobiles().isEmpty()) {
// 发送给所有人
at.setIsAtAll(true);
} else {
// 发送给指定用户
at.setAtMobiles(message.getRecipientMobiles());
at.setIsAtAll(false);
}
request.setAt(at);
// 处理文本消息
if (MESSAGE_TYPE_TEXT.equals(message.getMessageType())) {
request.setMsgtype(MESSAGE_TYPE_TEXT);
OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text();
text.setContent(message.getMessageContent());
request.setText(text);
}
OapiRobotSendResponse response = client.execute(request);
logger.info("钉钉消息发送结果:" + response);
} catch (Exception e) {
logger.error("钉钉消息发送异常", e);
}
}
public static void main(String[] args) {
List<String> mobileList = new ArrayList<>();
mobileList.add("13026578156");
MessageSender message = new MessageSender();
message.setMessageType(MESSAGE_TYPE_TEXT);
message.setNotifyAll(false);
message.setRecipientMobiles(mobileList);
message.setWebhookUrl("https://oapi.dingtalk.com/robot/send?access_token=a4dxxxxxxxxxxxx347e4b1267dd4f39");
message.setAccessKey("SECe4f7ef42exxxxxxxxxxxxxxxxxxxxxxx07d07287769f16c91d");
message.setMessageContent("监控消息通知");
sendMessage(message);
}
}
yml配置
#钉钉消息推送
dingtalk:
webhook: https://oapi.dingtalk.com/robot/send?access_token=a4dab6098cf65xxxxxxxxxxxxxxxxxxxb1267dd4f39
secret: SECe4f7ef42ea7d10df102xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx07287769f16c91d
userMobil: 1xxxxxx156
namespace: dev
钉钉依赖
<!--钉钉消息推送依赖-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>alibaba-dingtalk-service-sdk</artifactId>
<version>2.0.0</version>
<exclusions>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>