0%

Spring boot와 Telegram 연동 (텔레그램 메세지 보내기)

Spring Boot에서 Telegram 메세지를 보내기

개발하는 서비스의 업,다운 및 기타 특정 에러 발생 시 알림을 받는 것에 대해 고민하게 되었다.
메일의 경우 사실 바로 대응하기 힘들었고, 메세지형의 알림이 와야 바로 대응할 수 있을 것 같았다.
그래서 이번 포스팅에서는 텔레그램과 Spring boot와 연동하는 법에 대해서 포스팅 해보려 한다.

포스팅에 앞서 아래의 실행환경과 선행 조건이 충족되어 있다는 것을 가정하고 진행한다.

  • Spring boot 2.1
  • Lombok 사용
  • Gradle 사용
  • Telegram bot 생성 완료 참고
  • 참고한 TelegramBot의 경우 Github-TelegramBots을 참고
  • 예제코드는 Github 참고

1. Gradle 추가

먼저 프로젝트의 build.gradle 파일에 아래의 의존성을 추가한다.

1
implementation 'org.telegram:telegrambots:4.4.0.1'

2. Main Method 코드 추가

프로젝트의 Main Method에 아래의 코드를 추가한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void main(String[] args) {
//1
ApiContextInitializer.init();

//2
TelegramBotsApi botsApi = new TelegramBotsApi();
try {
botsApi.registerBot(new MyAmazingBot());
} catch (TelegramApiException e) {
e.printStackTrace();
}


SpringApplication.run(MovillContractApplication.class, args);
}

여기서 주의할 것은 1번, 2번의 작업이 run() 메서드 호출 전에 이뤄져야 한다.
주석의 1번 작업의 경우 Api context를 초기화 해주는 부분이다.
2번의 경우 봇 인스턴스를 등록하는 부분이다.
주의점으로는 각 봇의 경우 한번만 등록하여 호출할 수 있다.
registerBot 으로 하나의 봇을 등록할 수 있다는 의미이다.
필자의 경우 이 부분을 제대로 파악하지 못하여 개발용과 테스트, 그리고 운영 서버에 함께 등록을 하였더니 무수한 에러가 발생하였다.

이와 관련된 에러 발생 및 처리는 이곳을 참고하자.


3. 텔레그램 봇 클래스 생성

텔래그램의 봇 클래스를 하나 만들어준다.
생성 클래스는 아래 코드를 참고하자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.meta.TelegramBotsApi;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;

import javax.annotation.PostConstruct;


@Slf4j
@Component
public class TelegramMessageBot extends TelegramLongPollingBot { //
private final String BOT_NAME = "Input_Bot_Name"; //Bot Name
private final String AUTH_KEY = "Input_Bot_Auth-Key"; //Bot Auth-Key
private final String CHAT_ID = "Chat_ID"; //Chat ID

@Override
public String getBotUsername() {
return BOT_NAME;
}

@Override
public String getBotToken() {
return AUTH_KEY;
}

/**
* 메세지를 받으면 처리하는 로직
* @param update
*/
@Override
public void onUpdateReceived(Update update) {
//따로 처리하지는 않음
}

/**
* 메세지 전달
* @param sendMessage
*/
public void sendMessage(String sendMessage) {
SendMessage message = new SendMessage()
.setChatId(CHAT_ID)
.setText(sendMessage);
try {
execute(message);
} catch (TelegramApiException e) {
e.printStackTrace();
}
}
}

코드에 있는 주석을 참고하면 파악하는데 큰 어려움은 없겠지만, 몇 가지 보완 및 첨언을 통해 설명을 보강하겠다.

먼저 TelegramLongPollingBot 추상 클래스를 상속 받고, LongPollingBot 인터페이스에 선언된 메서드를 구현한다.
그리고 해당 클래스를 컴포넌트로 등록하여 빈으로 등록하여 사용한다.

getBotUsername 메서드에는 봇의 이름을 반환하게끔 처리하고, getBotToken 메서드에는 AuthKey를 반환하게끔 처리한다.
예제에서는 위와 같이 상수 값을 선언하고 처리하였는데, 그냥 메서드에서 반환해도 무방하다.

onUpdateReceived 메서드의 경우 해당 봇이 메세지를 받은 경우에 대해 처리하는 부분인데 이번 포스팅에서는 단순하게 메세지를 보내는 역할을 하는 부분까지 이므로 해당 메서드는 따로 처리하지 않았다.

sendMessage 메서드는 필자가 만든 커스텀 메서드인데 단순하게 메세지를 Chat ID에 해당하는 방으로 메세지를 전송하는 메서드이다.


4. 봇으로 메세지 보내기

봇으로 메세지를 보낼 때는 위에서 만든 빈을 이용하여 보낸다.
아래는 Boot가 시작 그리고 종료될 때 텔레그램으로 메세지를 보내는 샘플 코드이다.
실제 사용하는 코드에서 회사쪽 로직은 제거한 부분이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@RefreshScope
@Slf4j
@Component
@RequiredArgsConstructor
public class StartUpApplicationListener {
//.... 변수 선언 부
private final TelegramMessageBot telegramMessageBot;


@EventListener
public void onApplicationEvent(ContextRefreshedEvent event) {
LocalDateTime dateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(event.getTimestamp()), TimeZone.getDefault().toZoneId());
String startMsg = "\n===== Application =====\n"
+ "=== SERVER START === \n\n"
+ "[Active Profile] : " + profile
+ "\n[Up-Time] : " + dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss"));

//특정 프로필일 때만 전송 처리
if (Arrays.asList("dev", "real", "real-slave", "stage", "stage-slave").contains(profile)) {
telegramMessageBot.sendMessage(startMsg);
}
}

@EventListener
public void shutdownApplicationEvent(ContextClosedEvent event) {
LocalDateTime dateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(event.getTimestamp()), TimeZone.getDefault().toZoneId());
String startMsg = "\n===== Application =====\n"
+ "=== SERVER DOWN === \n\n"
+ "[Active Profile] : " + profile
+ "\n[Down-Time] : " + dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss"));

//특정 프로필일 때만 전송 처리
if (Arrays.asList("dev", "real", "real-slave", "stage", "stage-slave").contains(profile)) {
telegramMessageBot.sendMessage(startMsg);
telegramMessageBot.onClosing();
}
}
}

위와 같이 처리할 경우 아래의 사진과 같이 서버가 올라가거나 내려갈 때 텔레그램 봇으로 메세지가 오게 된다.


정리

이번 포스팅을 통해 간단하게 텔레그램 봇에게 메세지를 전송하는 부분을 알아보았다.
사실 자료를 찾아보다가 Java쪽 보다는 Node.js나 Python이 더 이런 쪽에 특화되어 있다는 것을 알게 되었다.
하지만 java로도 구현이 가능하며, 간단한 기능 등은 위와 같이 쉽게 연동할 수 있다.

다음 포스팅에서는 몇 가지 상태 등을 조회할 수 있는 기능에 대해 포스팅을 해보도록 하겠다.

PS : Github에 예제를 등록하여야 하는데… 주말에 시간이 될 때 등록해서 수정해야 겠다.
8월 26일 Github 등록완료