【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>
相关推荐
renhongxia17 小时前
世界模型的四个商业场景:自动驾驶、机器人、内容产业与工业仿真
人工智能·机器人·自动驾驶
都叫我大帅哥7 小时前
从Python到Java:为什么企业级Agent最终会选择Java?
java·ai编程
wanderist.8 小时前
Lambda表达式在算法竞赛中的应用
java·开发语言·算法
腻害兔9 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:IM 即时通讯模块,一个被低估的「全功能聊天系统」
java·前端·vue.js·产品经理·ai编程
心念枕惊9 小时前
.NET CORE 授权进阶-角色、策略与动态权限实现
java·前端·.netcore
景同学11 小时前
把 AI 用到线上运维:可行、有效,前提是喂足信息——一次 Full GC 排障实录
java·人工智能·后端
C++、Java和Python的菜鸟11 小时前
第7章 后端Web实战(Tlias系统)
java
憧憬成为java架构高手的小白12 小时前
黑马八股--spring框架学习
java·学习·spring
唐青枫12 小时前
Java Picocli 实战详解:用注解写出好用的命令行工具
java
X-⃢_⃢-X13 小时前
四、OpenFeign远程调用
java·微服务·springboot·springcloud