기본 콘텐츠로 건너뛰기

Java로 텔레그램 인라인 버튼 봇 만들기: TelegramBots API CallbackQuery 실전 예제

Java로 텔레그램 인라인 버튼 봇 만들기: TelegramBots API 실전 예제

텔레그램 봇으로 메뉴 버튼을 띄우고, 버튼 클릭 이벤트(CallbackQuery)를 처리하는 예제입니다. 사용자가 1을 입력하면 인라인 키보드 버튼이 표시되고, 버튼을 클릭하면 콜백 데이터와 메시지 ID를 다시 보내주는 구조입니다.


1. 예제 기능 개요

이 텔레그램 봇 예제는 TelegramBots Java 라이브러리를 사용합니다. 주요 기능은 다음과 같습니다.

  • 사용자가 채팅 창에 1을 입력하면 “메뉴를 선택하세요”라는 메시지와 함께 인라인 버튼 출력
  • 버튼 텍스트: “버튼”, callbackData: “CheckBtn”
  • 버튼 클릭 시 콜백 데이터(callData) + 메시지 ID를 채팅으로 다시 전송

즉, 인라인 키보드(InlineKeyboardMarkup)CallbackQuery 처리를 한 번에 이해할 수 있는 기본 구조입니다.

텔레그램 인라인 버튼 예시 화면


2. 텔레그램 인라인 버튼 봇 전체 코드

아래는 질문에 포함된 코드를 보기 좋게 정리한 버전입니다.


import org.telegram.telegrambots.ApiContextInitializer;
import org.telegram.telegrambots.TelegramBotsApi;
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.meta.TelegramBotsApiException;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.api.objects.CallbackQuery;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.InlineKeyboardMarkup;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.InlineKeyboardButton;

import java.util.ArrayList;
import java.util.List;

public class TelegramV2 {

    public static void main(String[] args) {
        // (구버전 라이브러리 기준) 텔레그램 컨텍스트 초기화
        ApiContextInitializer.init();

        TelegramBotsApi api = new TelegramBotsApi();

        // 익명 클래스 형태의 LongPollingBot 구현
        TelegramLongPollingBot bot = new TelegramLongPollingBot() {

            @Override
            public void onUpdatesReceived(List<Update> updates) {
                // 필요시 여러 Update를 한 번에 처리할 때 사용
                super.onUpdatesReceived(updates);
            }

            @Override
            public void onUpdateReceived(Update update) {

                // 1) 일반 메시지 처리
                if (update.hasMessage() && update.getMessage().hasText()) {

                    Message message = update.getMessage();
                    String text = message.getText();

                    // 사용자가 1을 입력한 경우 인라인 버튼 표시
                    if ("1".equals(text)) {

                        long chatId = message.getChatId();

                        // 인라인 키보드 생성
                        List<List<InlineKeyboardButton>> keyboard = new ArrayList<>();
                        List<InlineKeyboardButton> row = new ArrayList<>();

                        // "버튼" 텍스트, callbackData는 "CheckBtn"
                        row.add(new InlineKeyboardButton()
                                .setText("버튼")
                                .setCallbackData("CheckBtn"));

                        keyboard.add(row);

                        InlineKeyboardMarkup keyboardMarkup = new InlineKeyboardMarkup();
                        keyboardMarkup.setKeyboard(keyboard);

                        // 전송할 메시지 구성
                        SendMessage msg = new SendMessage()
                                .setChatId(chatId)
                                .setText("메뉴를 선택하세요")
                                .setReplyMarkup(keyboardMarkup);

                        try {
                            execute(msg);
                        } catch (TelegramApiException e) {
                            e.printStackTrace();
                        }
                    }

                // 2) 버튼 클릭(CallbackQuery) 처리
                } else if (update.hasCallbackQuery()) {

                    CallbackQuery callbackQuery = update.getCallbackQuery();

                    long chatId = callbackQuery.getMessage().getChatId();
                    String callData = callbackQuery.getData();            // "CheckBtn"
                    int messageId = callbackQuery.getMessage().getMessageId();

                    try {
                        // 콜백 데이터와 메시지 ID를 그대로 사용자에게 회신
                        execute(new SendMessage()
                                .setChatId(chatId)
                                .setText(callData + " // " + messageId));
                    } catch (TelegramApiException e) {
                        e.printStackTrace();
                    }

                    System.out.println("callData = " + callData);
                }
            }

            @Override
            public String getBotUsername() {
                // 텔레그램 BotFather에서 설정한 봇 이름
                return "YOUR_BOT_USERNAME";
            }

            @Override
            public String getBotToken() {
                // BotFather에서 발급받은 토큰
                return "YOUR_BOT_TOKEN";
            }
        };

        try {
            // 봇 등록
            api.registerBot(bot);

            // 시작 시 초기 메시지 보내고 싶을 때 사용 가능 (채팅 ID 직접 지정)
            // bot.execute(new SendMessage("CHAT_ID", "봇이 시작되었습니다."));

        } catch (TelegramApiException e) {
            e.printStackTrace();
        }
    }
}
    

위 코드에서 YOUR_BOT_USERNAME, YOUR_BOT_TOKEN 부분은 BotFather에게서 발급받은 값으로 직접 교체해야 합니다.


3. onUpdateReceived() 로직 상세 설명

텔레그램의 LongPolling 방식에서는 새로운 메시지나 버튼 클릭이 발생할 때마다 onUpdateReceived(Update update)가 호출됩니다. 이 예제에서는 크게 두 가지 경우를 처리합니다.

3-1. 사용자가 “1”이라고 입력했을 때

  • update.hasMessage() && update.getMessage().hasText() 조건으로 텍스트 메시지인지 확인
  • message.getText().equals("1")인 경우에만 인라인 키보드 생성
  • InlineKeyboardButtonsetCallbackData("CheckBtn")에 콜백용 키값 할당
  • InlineKeyboardMarkup에 키보드 리스트를 세팅 후 SendMessage에 연결
  • execute(msg) 호출로 사용자에게 버튼이 포함된 메시지 전송

즉, 이 부분은 “조건에 맞으면 메뉴 버튼을 띄우는 역할”입니다.


4. CallbackQuery 처리와 버튼 동작 방식

인라인 키보드 버튼이 눌리면, 텔레그램 서버는 메시지가 아니라 CallbackQuery를 보내줍니다. 이때 update.hasCallbackQuery()true로 들어오게 됩니다.

4-1. 콜백 데이터·메시지 ID 추출


} else if (update.hasCallbackQuery()) {

    CallbackQuery callbackQuery = update.getCallbackQuery();

    long chatId = callbackQuery.getMessage().getChatId();
    String callData = callbackQuery.getData();          // "CheckBtn"
    int messageId = callbackQuery.getMessage().getMessageId();

    try {
        execute(new SendMessage()
                .setChatId(chatId)
                .setText(callData + " // " + messageId));
    } catch (TelegramApiException e) {
        e.printStackTrace();
    }

    System.out.println("callData = " + callData);
}
    
  • getData() : 버튼 만들 때 setCallbackData()에 넣은 값 (여기서는 "CheckBtn")
  • getMessage().getChatId() : 콜백이 발생한 메시지가 속한 채팅 ID
  • getMessage().getMessageId() : 어떤 메시지에 붙어 있던 버튼인지 구분할 때 사용 가능

이 구조를 확장하면 다음과 같이 구현할 수 있습니다.

  • callData 값에 따라 메뉴 분기 – 예: "MENU_1", "MENU_2", "BACK"
  • 특정 메시지에 대한 상태 관리 – messageId를 이용해 어느 화면에서 온 콜백인지 판별
  • 추가로 메시지 편집(EditMessageText)를 사용하면, 화면을 깔끔하게 유지하면서 메뉴 교체 가능

5. 실무에서 쓸 때 고려할 점

5-1. Bot Token/Username 보안

  • 코드에 직접 토큰을 하드코딩하지 않고 환경변수, 설정 파일에서 불러오는 것을 추천
  • 깃허브에 올릴 때 토큰이 노출되지 않도록 application.properties, .env 등 사용

5-2. 구조 개선

  • 익명 클래스로 봇을 구현하기보다, 별도의 클래스로 분리해 가독성을 높이는 편이 좋습니다.
  • 콜백 처리 부분도 if-else 대신 callData → 핸들러 매핑 구조로 리팩토링하면 유지보수가 편해집니다.

5-3. 라이브러리 버전

  • 예제는 구버전 스타일(ApiContextInitializer)에 맞춰져 있으므로, 최신 버전에서는 TelegramBotsApi 생성 방법이 조금 달라질 수 있습니다.
  • 실제 프로젝트에서는 사용하는 telegrambots 라이브러리 버전에 맞는 초기화 코드를 확인하세요.

이 예제는 Java와 TelegramBots API를 활용해 인라인 버튼 메뉴 + CallbackQuery 처리까지 구현한 기본 골격입니다. 여기서 버튼을 여러 개로 늘리고, callData에 따라 서로 다른 비즈니스 로직을 태우면 충분히 실전용 텔레그램 봇 메뉴 시스템으로 확장할 수 있습니다.

댓글

이 블로그의 인기 게시물

Java Servlet Request Parameter 완전 정복 — GET/POST 모든 파라미터 확인 & 디버깅 예제 (Request Parameter 전체보기)

Java Servlet Request Parameter 완전 정복 — GET/POST 모든 파라미터 확인 & 디버깅 예제 Java Servlet Request Parameter 완전 정복 웹 애플리케이션에서 클라이언트로부터 전달되는 Request Parameter 를 확인하는 것은 필수입니다. 이 글에서는 Java Servlet 과 JSP 에서 GET/POST 요청 파라미터를 전체 출력하고 디버깅하는 방법을 다양한 예제와 함께 소개합니다. 1. 기본 예제: getParameterNames() 사용 Enumeration<String> params = request.getParameterNames(); System.out.println("----------------------------"); while (params.hasMoreElements()){ String name = params.nextElement(); System.out.println(name + " : " + request.getParameter(name)); } System.out.println("----------------------------"); 위 코드는 요청에 포함된 모든 파라미터 이름과 값을 출력하는 기본 방법입니다. 2. HTML Form과 연동 예제 <form action="CheckParamsServlet" method="post"> 이름: <input type="text" name="username"><br> 이메일: <input type="email" name="email"><b...

PostgreSQL 달력(일별,월별)

SQL 팁: GENERATE_SERIES로 일별, 월별 날짜 목록 만들기 SQL 팁: GENERATE_SERIES 로 일별, 월별 날짜 목록 만들기 데이터베이스에서 통계 리포트를 작성하거나 비어있는 날짜 데이터를 채워야 할 때, 특정 기간의 날짜 목록이 필요할 수 있습니다. PostgreSQL과 같은 데이터베이스에서는 GENERATE_SERIES 함수를 사용하여 이 작업을 매우 간단하게 처리할 수 있습니다. 1. 🗓️ 일별 날짜 목록 생성하기 2020년 1월 1일부터 12월 31일까지의 모든 날짜를 '1 day' 간격으로 생성하는 쿼리입니다. WITH date_series AS ( SELECT DATE(GENERATE_SERIES( TO_DATE('2020-01-01', 'YYYY-MM-DD'), TO_DATE('2020-12-31', 'YYYY-MM-DD'), '1 day' )) AS DATE ) SELECT DATE FROM date_series 이 쿼리는 WITH 절(CTE)을 사용하여 date_series 라는 임시 테이블을 만들고, GENERATE_SERIES 함수로 날짜를 채웁니다. 결과 (일별 출력) 2. 📅 월별 날짜 목록 생성하기 동일한 원리로, 간격을 '1 MONTH' 로 변경하면 월별 목록을 생성할 수 있습니다. TO...

CSS로 레이어 팝업 화면 가운데 정렬하는 방법 (top·left·transform 완전 정리)

레이어 팝업 센터 정렬, 이 코드만 알면 끝 (CSS 예제 포함) 이벤트 배너나 공지사항을 띄울 때 레이어 팝업(center 정렬) 을 깔끔하게 잡는 게 생각보다 어렵습니다. 화면 크기가 변해도 가운데에 고정되고, 모바일에서도 자연스럽게 보이게 하려면 position , top , left , transform 을 정확하게 이해해야 합니다. 이 글에서는 아래 내용을 예제로 정리합니다. 레이어 팝업(center 정렬)의 기본 개념 자주 사용하는 position: absolute / fixed 정렬 방식 질문에서 주신 스타일 top: 3.25%; left: 50%; transform: translateX(-50%) 의 의미 실무에서 바로 쓰는 반응형 레이어 팝업 HTML/CSS 예제 1. 레이어 팝업(center 정렬)이란? 레이어 팝업(레이어 팝업창) 은 새 창을 띄우는 것이 아니라, 현재 페이지 위에 div 레이어를 띄워서 공지사항, 광고, 이벤트 등을 보여주는 방식을 말합니다. 검색엔진(SEO) 입장에서도 같은 페이지 안에 HTML이 존재 하기 때문에 팝업 안의 텍스트도 정상적으로 인덱싱될 수 있습니다. 즉, “레이어 팝업 센터 정렬”, “레이어 팝업 만드는 방법”과 같이 관련 키워드를 적절히 넣어주면 검색 노출에 도움이 됩니다. 2. 질문에서 주신 레이어 팝업 스타일 분석 질문에서 주신 스타일은 다음과 같습니다. <div class="layer-popup" style="width:1210px; z-index:9001; position:absolute; top:3.25%; left:50%; transform:translateX(-50%);"> 레이어 팝업 내용 <...