Телеграм-бот «Java ассистент»
Работа с кнопками (inline keyboards)
Добавим простую логику в наш бот: выдача подходящего курса Java, соответствующего уровню участника.
Для этого подключим работу с командами Telegram и с кнопками (Lesson 6 в Telegram Bot Tutorial)
Для этого подключим работу с командами Telegram и с кнопками (Lesson 6 в Telegram Bot Tutorial)
В ветке master примените патч 2_1_keyboard из архива патчей
-
Команды Telegram — это специальные сообщения, начинающиеся со знака "/" (косая черта), которые используются для запуска определённых действий в ботах.
Например, пользователь может отправить /start, чтобы начать общение с ботом, или /help, чтобы получить справку. Для работ с командами добавим
класс
CommandHandler - Добавляем утильный класс
KeyboardHandlerдля создания кнопок. Кнопки можно помещать в один ряд и создавать из них несколько рядов,callbackData- это данные, которые возвратит бот при нажатии на кнопку. -
Добавляем метод
ClientHandler#sendMdAndKeyboard, который отсылает в бота markdown-сообoщение вместе с созданными кнопками. - В
UpdateHandlerдобавляем-
InlineKeyboardMarkup YES_NO_KEYBOARD- простой ряд с кнопками Yes/No -
Метод
getDataFromCallbackQueryдля полученияcallbackDataнажатой кнопки
-
-
Мы сразу готовим код для большого проекта, поэтому создали отдельный класс
Util, пока там только метод проверки наnull -
Наконец в классе-реализации бота реализуем простую логику:
- Ответ на команду /help
- Начало диалога при команде /start
- Обработка ответа на
YES_NO_KEYBOARD - Обработка ответа оценки уровня знания Java участника ("How high out of 10 would you rate your Java knowledge?")
Хранение состояния
Telegram API не хранит состояния (stateless протокол). Если нам нужен диалог с пользователей с сохранением состояния, необходимо сделать его на стороне приложения.
При этом, если нам важно, чтобы он не прерывался при рестарте приложения, его нужно хранить в базе данных приложения, или, например, в MapDB.
Однако рестарт приложение - событие редкое и, если диалог недолгий, мы можем хранить состояние просто в памяти.
В ветке master примените патч 2_2_state из архива патчей
- Т.к. мы создаем основу реального приложения, которое работает с множеством пользователей, в
pom.xmlподключим
in-memory cache Caffeine, чтобы удалять состояние после заданного промежутка времени. - Добавляем класс хранения состояний
Statesс ивалидацией.expireAfterWrite(120, TimeUnit.MINUTES). В одном приложении мы можем запускать несколько ботов, поэтому делаем этот класс Generic. - В
UpdateHandlerдобавлем универсальный обработчик каллбэков отYES_NO_KEYBOARD - Наконец, в
AIBotмы делаем новую логику, которую не смогли бы реализовать без сохранения состояния. На каждом шаге мы или завершаем диалог, или сохраняем состояние, которое будет обрабатываться на следующем шаге:states.update(tgId, nextStage)
Подключаем Spring Boot
Подключим Spring Boot 4 и используем его для конфигурирования токена:
В ветке master примените патч 2_3_spring_boot из архива патчей
- Делаем класс
AIBotбином Spring (можем сюда инжектить, например, репозитории для хранения пользователей и результатов), инжектим в него значение@Value("${BOT_HTTP_API_TOKEN}")и через@PostConstructинициализируемClientHandler AIBotMainаннотируем@SpringBootApplicationи через lombok@RequiredArgsConstructorинжектим сюдаAIBot- Запустить проект можно с переменной окружения
BOT_HTTP_API_TOKENили с профилемdev, сделав для него конфигурацию:
в корне проекта создайте\config\application-dev.yaml(скопируйте в\configиз application-dev.yaml и замените свой BOT_HTTP_API_TOKEN). В запуске нужно указать профиль: