mirror of
https://gitee.com/dromara/RuoYi-Vue-Plus.git
synced 2026-09-19 09:55:16 +08:00
add 新增服务监控邮件通知以及钉钉机器人通知
This commit is contained in:
parent
e9bd0858e2
commit
5d6f706a95
@ -39,6 +39,11 @@
|
|||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.dromara</groupId>
|
||||||
|
<artifactId>ruoyi-common-mail</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
|
||||||
|
}
|
||||||
@ -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.domain.events.InstanceStatusChangedEvent;
|
||||||
import de.codecentric.boot.admin.server.notify.AbstractEventNotifier;
|
import de.codecentric.boot.admin.server.notify.AbstractEventNotifier;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
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 org.springframework.stereotype.Component;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
@ -49,6 +51,13 @@ public class CustomNotifier extends AbstractEventNotifier {
|
|||||||
};
|
};
|
||||||
log.info("Instance Status Change: 状态名称【{}】, 注册名称【{}】, 实例ID【{}】, 状态【{}】, 服务URL【{}】",
|
log.info("Instance Status Change: 状态名称【{}】, 注册名称【{}】, 实例ID【{}】, 状态【{}】, 服务URL【{}】",
|
||||||
statusName, registName, instanceId, status, serviceUrl);
|
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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -46,3 +46,47 @@ spring.boot.admin.client:
|
|||||||
userpassword: ${spring.boot.admin.client.password}
|
userpassword: ${spring.boot.admin.client.password}
|
||||||
username: ruoyi
|
username: ruoyi
|
||||||
password: 123456
|
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**: {}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user