add 新增服务监控邮件通知以及钉钉机器人通知

This commit is contained in:
AprilWind 2024-07-25 15:09:58 +08:00
parent e9bd0858e2
commit 5d6f706a95
6 changed files with 310 additions and 0 deletions

View File

@ -39,6 +39,11 @@
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-mail</artifactId>
</dependency>
</dependencies>
<build>

View File

@ -0,0 +1,80 @@
package org.dromara.monitor.admin.config.properties;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* 通知配置
*
* @author AprilWind
*/
@Data
@ConfigurationProperties(prefix = "notify")
@Configuration
public class NotifyProperties {
/**
* 邮件设置
*/
private Mail mail;
/**
* WebHooks 设置
*/
private WebHook webHook;
@Data
@NoArgsConstructor
public static class Mail {
/**
* 发送开关
*/
private Boolean enabled = false;
/**
* 收件人
*/
private String to;
/**
* 主题
*/
private String subject;
/**
* 邮件模版
*/
private String template;
}
@Data
@NoArgsConstructor
public static class WebHook {
/**
* 发送开关
*/
private Boolean enabled = false;
/**
* 0默认 1密码 2签名密钥
*/
private String type;
/**
* Post地址
*/
private String url;
/**
* WebHook发送模版
*/
private String template;
}
}

View File

@ -0,0 +1,44 @@
package org.dromara.monitor.admin.event;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 通知事件
*
* @author AprilWind
*/
@Data
public class NotifierEvent implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 实例注册名称
*/
private String registName;
/**
* 实例状态名称
*/
private String statusName;
/**
* 实例ID
*/
private String instanceId;
/**
* 实例状态
*/
private String status;
/**
* 服务URL
*/
private String serviceUrl;
}

View File

@ -6,6 +6,8 @@ import de.codecentric.boot.admin.server.domain.events.InstanceEvent;
import de.codecentric.boot.admin.server.domain.events.InstanceStatusChangedEvent;
import de.codecentric.boot.admin.server.notify.AbstractEventNotifier;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.monitor.admin.event.NotifierEvent;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
@ -49,6 +51,13 @@ public class CustomNotifier extends AbstractEventNotifier {
};
log.info("Instance Status Change: 状态名称【{}】, 注册名称【{}】, 实例ID【{}】, 状态【{}】, 服务URL【{}】",
statusName, registName, instanceId, status, serviceUrl);
NotifierEvent notifier = new NotifierEvent();
notifier.setRegistName(registName);
notifier.setStatusName(statusName);
notifier.setInstanceId(instanceId);
notifier.setStatus(status);
notifier.setServiceUrl(serviceUrl);
SpringUtils.context().publishEvent(notifier);
}
});
}

View File

@ -0,0 +1,128 @@
package org.dromara.monitor.admin.notifier;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mail.utils.MailUtils;
import org.dromara.monitor.admin.config.properties.NotifyProperties;
import org.dromara.monitor.admin.event.NotifierEvent;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.HashMap;
import java.util.Map;
/**
* 信息通知
*
* @author AprilWind
*/
@RequiredArgsConstructor
@Slf4j
@Service
public class InfoNotifier {
private final NotifyProperties notifyProperties;
/**
* 服务上线或者离线
*
* @param notifier 通知事件
*/
@Async
@EventListener(condition = "#notifier.status == 'UP' || #notifier.status == 'OFFLINE'")
public void infoNotification(NotifierEvent notifier) {
sendWebHook(notifier);
}
/**
* 服务下线或者发送异常
*
* @param notifier 通知事件
*/
@Async
@EventListener(condition = "#notifier.status == 'DOWN' || #notifier.status == 'UNKNOWN'")
public void errNotification(NotifierEvent notifier) {
sendMail(notifier);
sendWebHook(notifier);
}
/**
* 发送邮件通知
*
* @param notifier 包含通知信息的对象
*/
public void sendMail(NotifierEvent notifier) {
NotifyProperties.Mail mail = notifyProperties.getMail();
if (mail.getEnabled()) {
String message = StringUtils.format(mail.getTemplate(), notifier.getRegistName(), notifier.getInstanceId(),
notifier.getStatusName(), notifier.getStatus(), notifier.getServiceUrl());
try {
MailUtils.sendHtml(mail.getTo(), notifier.getRegistName() + notifier.getStatusName(), message);
log.info("邮件已发送至: {}", mail.getTo());
} catch (Exception e) {
log.error("邮件发送失败: ", e);
}
}
}
/**
* 发送WebHook通知
*
* @param notifier 包含通知信息的对象
*/
public void sendWebHook(NotifierEvent notifier) {
NotifyProperties.WebHook webHook = notifyProperties.getWebHook();
if (webHook.getEnabled()) {
String title = notifier.getRegistName() + notifier.getStatusName();
String message = StringUtils.format(webHook.getTemplate(), title,
notifier.getRegistName(), notifier.getInstanceId(), notifier.getStatus(), notifier.getServiceUrl());
try {
sendWebHookMessage(webHook.getUrl(), title, message);
log.info("WebHook消息已发送至: {}", webHook.getUrl());
} catch (Exception e) {
log.error("WebHook消息发送失败: ", e);
}
}
}
private void sendWebHookMessage(String url, String title, String markdownMessage) throws Exception {
// 构造消息体
Map<String, Object> messageBody = new HashMap<>();
messageBody.put("msgtype", "markdown");
Map<String, String> markdownContent = new HashMap<>();
markdownContent.put("title", title + "通知");
markdownContent.put("text", markdownMessage);
messageBody.put("markdown", markdownContent);
// 将消息体转换为JSON字符串
ObjectMapper objectMapper = new ObjectMapper();
String jsonMessage = objectMapper.writeValueAsString(messageBody);
// 创建HTTP客户端
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI(url))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(jsonMessage))
.build();
// 发送请求
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
// 处理响应
if (response.statusCode() == 200) {
log.info("WebHook消息发送成功");
} else {
log.error("WebHook消息发送失败: {}", response.body());
}
}
}

View File

@ -46,3 +46,47 @@ spring.boot.admin.client:
userpassword: ${spring.boot.admin.client.password}
username: ruoyi
password: 123456
--- # mail 邮件发送
mail:
enabled: false
host: smtp.163.com
port: 465
# 是否需要用户名密码验证
auth: true
# 发送方遵循RFC-822标准
from: xxx@163.com
# 用户名注意如果使用foxmail邮箱此处user为qq号
user: xxx@163.com
# 密码注意某些邮箱需要为SMTP服务单独设置密码详情查看相关帮助
pass: xxxxxxxxxx
# 使用 STARTTLS安全连接STARTTLS是对纯文本通信协议的扩展。
starttlsEnable: true
# 使用SSL安全连接
sslEnable: true
# SMTP超时时长单位毫秒缺省值不超时
timeout: 0
# Socket连接超时值单位毫秒缺省值不超时
connectionTimeout: 0
# 服务通知
notify:
mail:
enabled: false
to:
subject: 系统通知
template: "<html><body>
<p>服务名: <b>{}</b> ({})</p>
<p>状态: <b>{}</b> ({})</p>
<p>服务IP: <b>{}</b></p>
</body></html>"
web-hook:
enabled: false
type: 0
url:
template: |
### {}通知
- **服务名**: {}
- **实例ID**: {}
- **状态**: {}
- **服务IP**: {}