【JAVA】利用钉钉自定义机器人监控NACOS服务,实现实时下线通知

利用钉钉自定义机器人监控NACOS服务,实现实时下线通知

自定义机器人步骤

  1. 创建一个钉钉群,拉人创建
  2. 在群设置中,选择自定义机器人
  3. 记住webhook 和 accessKey,用于代码中配置

钉钉实体类

java 复制代码
@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;
}

监控代码

java 复制代码
@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());
                }
            });
        }
    }
}

封装工具类

java 复制代码
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() + "&timestamp=" + 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配置

yaml 复制代码
#钉钉消息推送
dingtalk:
  webhook: https://oapi.dingtalk.com/robot/send?access_token=a4dab6098cf65xxxxxxxxxxxxxxxxxxxb1267dd4f39
  secret: SECe4f7ef42ea7d10df102xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx07287769f16c91d
  userMobil: 1xxxxxx156
  namespace: dev

钉钉依赖

java 复制代码
    <!--钉钉消息推送依赖-->
        <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>
相关推荐
小羊没烦恼!5 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
俊昭喜喜里5 天前
java中的继承和多态的区别
java
小羊没烦恼!5 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
譕痕5 天前
JSONObject与JSONArray封装数据格式区别
java·json
胡写代码5 天前
别再前后端各写一套表单校验了
java·后端
小鱼能吃糖5 天前
缺陷修复总览 · mall电商项目:5类缺陷,1个病根,4个业务域
java·电商
此时不提桶,更待何时5 天前
01-06-A-JVM排查实战详解
java·jvm
风合星语5 天前
2026 具身智能技术实战(一):VLA 到底怎么控制机器人?——用 LeRobot 跑通 SmolVLA 推理
pytorch·机器人·具身智能·vla·lerobot·smolvla
鲁邦通物联网5 天前
图书馆机器人跨楼层运行,机器人梯控低噪设计与架构分析
机器人·巡检机器人·机器人梯控·agv梯控·非侵入式采集·机器人乘梯·机器人自主乘梯
vipxieliang5 天前
ValidX 在 DDD 领域驱动设计中的实践
java·spring boot