上一篇設定好監控後, 透過 Chrome 通知其實不太夠, 因為我們不可能一直開著電腦, 所以還是需要一些其它手段來通知我們
SpringBoot Admin 原本就整合好了一些常見的通知機制
Reminder notifications
Mail notifications
Hipchat notifications
Slack notifications
Let’s Chat notifications
都是在 Server 端設定一下就完成了, 非常方便.
舉例來說 email 這樣就可以
spring:
application:
name: 'ServiceAdmin'
mail:
host: "mail.xxx.com"
username: "ecs@xxx.com"
password: "xxxxxxxxxxx"
boot:
admin:
notify:
mail:
enabled: true
from: 'ec@xxxxxx.com'
to: 'sam@xxxxxx.com,chu@xxxxxx.com'
或是團隊比較愛用 slack 也可以
spring:
application:
name: 'ServiceAdmin'
boot:
admin:
notify:
slack:
enabled: true
webhook-url: 'https://hooks.slack.com/services'
But 這兩個 在台灣不一定大家都會裝 & 即時看到, but 台灣幾乎每個人都會裝 Line 啦
那我們來改一下符合台灣人的習慣吧
首先你需要有個開發者帳號
記得要申請開發者喔
不然你沒有 PUSH_MESSAGE 的權限就無法主動推訊息出去
再來組態檔部分 application.yml
spring:
application:
name: ServiceAdmin
boot:
admin:
notify:
line:
enabled: true
channelSecret: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
channelToken: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
to: 'xxxxxxxxxxxxxxxxxxxxxxxxx'
channelSecret 是 Line 官方提供
channelToken 是 Line 官方提供
to 這個就是你要推送的個人或群組的代碼, 要怎麼查到呢? 官網上登入後會在同一頁最下面提供給你 Your user ID
如果是群組呢? 加入群組的時候你會收到 line 的官方訊息, 你要去收下來讀出裡面的 Group ID.
再來是我們程式
首先要讀取配置檔
LineProperties.java
package com.example.admin;
import lombok.Data;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "spring.boot.admin.notify.line")
@ConditionalOnProperty(prefix = "spring.boot.admin.notify.line", name = "enabled", matchIfMissing = true)
public class LineProperties {
private boolean enabled = false;
private String channelSecret;
private String channelToken;
private String to;
}
再來是我們的推播程式 LineNotifier.java
package com.example.admin;
import de.codecentric.boot.admin.event.ClientApplicationEvent;
import de.codecentric.boot.admin.event.ClientApplicationRegisteredEvent;
import de.codecentric.boot.admin.event.ClientApplicationStatusChangedEvent;
import de.codecentric.boot.admin.notify.AbstractEventNotifier;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.Expression;
import org.springframework.expression.ParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@Slf4j
@Component
public class LineNotifier extends AbstractEventNotifier {
@Autowired
private LineProperties lineProperties;
private static final String DEFAULT_MESSAGE = "#{application.name} (#{application.id}) is #{to.status}";
private final SpelExpressionParser parser = new SpelExpressionParser();
private Expression message;
private List<String> notifyStatuses = Arrays.asList("UP", "DOWN", "OFFLINE");
@Override
protected void doNotify(ClientApplicationEvent event) throws Exception {
if (lineProperties.isEnabled() == false) {
return;
}
this.message = parser.parseExpression(DEFAULT_MESSAGE, ParserContext.TEMPLATE_EXPRESSION);
if (event instanceof ClientApplicationRegisteredEvent) {
ClientApplicationRegisteredEvent registeredEvent = (ClientApplicationRegisteredEvent) event;
// System.out.println(registeredEvent.getApplication());// Application [id=2a87974b, name=boot-test, managementUrl=http://SAMPC:5566, healthUrl=http://SAMPC:5566/health, serviceUrl=http://SAMPC:5566]
// System.out.println(registeredEvent.getType());// REGISTRATION
// System.out.println(registeredEvent.getApplication().getServiceUrl());// http://SAMPC:5566
// System.out.println(registeredEvent.getApplication().getStatusInfo().getStatus());// UNKNOWN
}
if (event instanceof ClientApplicationStatusChangedEvent) {
ClientApplicationStatusChangedEvent statusChangedEvent = (ClientApplicationStatusChangedEvent) event;
String msg = message.getValue(event, String.class); // boot-test (2a87974b) is UP
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
//headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON_UTF8));
headers.add("Authorization", String.format("%s %s", "Bearer", lineProperties.getChannelToken()));
HashMap object = new HashMap<>();
object.put("to", lineProperties.getTo());
List messages = new ArrayList();
HashMap message = new HashMap<>();
message.put("type", "text");
message.put("text", msg);
messages.add(message);
object.put("messages", messages);
HttpEntity<HashMap> entity = new HttpEntity<HashMap>(object, headers);
ResponseEntity<String> response = restTemplate.exchange(
"https://api.line.me/v2/bot/message/push",
HttpMethod.POST, entity, String.class);
if (response.getStatusCode().is2xxSuccessful()) {
System.out.println(response.getBody());
}
}
}
}
繼承 admin 的 AbstractEventNotifier 就可以接收到事件通知了
再來我只針對 ClientApplicationStatusChangedEvent , 也就是上線或下線這種變化作通知
推送出去的效果
是不是比沒人在用的 Slack 或 Email 更即時呢?
你好!請問是直接執行spring boot 就會送訊息了嗎???
因為我執行完是這樣子不過都沒任何動作...
準確一點的說
當接收到別的服務 event 才會觸發喔
自己本身啟動不會的樣子