iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 11
1
Software Development

30天從零開始 使用 Spring Boot 跟 Spring Cloud 建構完整微服務架構系列 第 11

Day 11 - 如何客製 Admin 的通知(使用 Line )

上一篇設定好監控後, 透過 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 啦
那我們來改一下符合台灣人的習慣吧

首先你需要有個開發者帳號
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 , 也就是上線或下線這種變化作通知

推送出去的效果
in line

是不是比沒人在用的 Slack 或 Email 更即時呢?


上一篇
Day 10 - 上線前增加 SpringBoot Admin 來做監控
下一篇
Day 12 - 使用 Spring Security 建置 OAuth2 授權服務
系列文
30天從零開始 使用 Spring Boot 跟 Spring Cloud 建構完整微服務架構35
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
Audioshock
iT邦新手 5 級 ‧ 2018-04-24 17:14:09

你好!請問是直接執行spring boot 就會送訊息了嗎???
https://ithelp.ithome.com.tw/upload/images/20180424/20109661cILv8ST5e5.png
因為我執行完是這樣子不過都沒任何動作...

Sam iT邦新手 4 級 ‧ 2018-04-24 18:00:37 檢舉

準確一點的說
當接收到別的服務 event 才會觸發喔
自己本身啟動不會的樣子

我要留言

立即登入留言