Приветствую вас, мои дорогие друзья. Да-да, именно друзья. Я уже так сросся с этой серией статей, что те люди, которые регулярно пишут в комментариях свою благодарность и/или показывают, что прочли и поняли материал, стали уже близки.
Мы с вами идем с двух сторон к одной цели. Вы хотите понять, а я хочу объяснить. И конечная цель у нас одна — написанное приложение, которое понятно вам от начала до конца.
О многом из того, что опишу в этой статье вы, возможно, уже наслышаны. Не думаю, что я расскажу что-то новое и неординарное (но в рамках проекта знать/повторить это необходимо).
Весной я писал бота для себя, так что будем опираться на его “лекала”.
Пишем JRTB-2
Будем делать так же, как делали в статье с задачей JRTB-0:- Обновляем main ветку в локальном проекте через комбинацию ctrl + t.
- На основе main ветки создаем:
- Добавляем бота.
- Создаем новый коммит с описанием сделанного и пушим на гитхаб.
- Создаем пул-реквест на main ветку и еще раз проверяем. Ждем, чтобы прошел билд (github actions), мержим в мейн ветку.
- Закрываем соответствующую задачу.
Что такое телеграм-бот
Мы, разработчики, можем представить работу с телеграм-ботом так: мы используем их клиент для работы с ними. У нас есть готовая библиотека для работы. Есть набор действий, после которых телеграм-бот будет знать, что он связан нашей программой. А уже внутри программы мы научимся получать письма, команды и как-то их обрабатывать. Есть такая вещь как команда в телеграм-ботах: она начинается со слеша “/”. После нее сразу слитно пишем слово, и это будет считаться командой. Например, есть две команды, которые все должны знать:- /start — начало работы с ботом;
- /stop — конец работы с ботом.
Создаем бота у BotFather
Чтобы подключить бота, его вначале нужно создать. У Телеграма есть подход — создание бота со своим уникальным именем. К нему будет прилагаться еще токен (большая строка, которая работает как пароль). Я уже создал бота для JavaRush — @javarush_community_bot. Этот бот еще пустой и ничего не умеет. Главное, чтобы в конце имени было _bot. Чтобы показать, как это сделать, я создам бота, на котором мы будем тестировать наш функционал. В терминах реальных проектов это будет test environment (тестовое окружение). А наш основной будет будет prod environment (prod — production, то есть реальное окружение, на котором будет выполняться проект). Конечно, можно было бы добавить еще одно окружение — sandbox environment: общую песочницу, более изменяемую и доступную всем участникам разработки. Но это лишь усложнит ситуацию на этапе создания проекта. Пока что создадим еще два бота для test и для sandbox окружения. Первый шаг — создать (зарегистрировать) бота в самом Телеграме. Нужно найти бота: @BotFather и написать ему команду: /newbotДалее нас просят дать имя этому боту. Так как это бот для тестовых задач, то и имя у него будет соответствующее: [TEST] JavarushBotТеперь пришло время дать уникальное имя, по которому его всегда можно будет найти — его username: test_javarush_communityКак я и говорил выше, нужно добавлять суффикс _bot для username, поэтому пишем еще раз: test_javarush_community_botИ все! Бот создан. Теперь по username и token его можно подключить к нашему проекту. Разумеется для бесперебойной работы тестового сервера я не буду выставлять token (по сути это пароль к доступу к боту) этого бота на общее обозрение.Подключаем бота в проект
Мы не будем подключать библиотеку как обычно, а сразу воспользуемся преимуществами нашего скелета — SpringBoot. У него есть такая вещь, как Starter. Подключив библиотеку, с его помощью можно дать знать SpringBoot’у, что мы хотим настроить проект правильно. Если бы мы пошли по обычному пути, который описан во множестве мест, нам бы нужно было где-то создать конфигурацию, в которой было бы что-то такое:
ApiContextInitializer.init();
TelegramBotsApi telegramBotsApi = new TelegramBotsApi();
try {
telegramBotsApi.registerBot(Bot.getBot());
} catch (TelegramApiRequestException e) {
e.printStackTrace();
}
Здесь создается объект, при помощи которого можно установить связь с ботом.
В нашем случае стартер, который мы захотим подключить, сделает все за нас где-то “под капотом” (это тоже перевод часто используемой фразы в IT — under the hood).
Вот ссылка на этот стартер.
Сразу же по README.md файлу видно, что это, зачем и как его использовать.
Чтобы его подключить, нужно просто добавить эту зависимость в помник. И все :)
Вот нужная зависимость:
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-spring-boot-starter</artifactId>
<version>5.0.1</version>
</dependency>
Добавляем ее в наш помник. Выносим версию как положено и обновляем мавен проект.Исходя из описания, нам нужно просто создать новый класс, унаследоваться от TelegramLongPollingBot и добавить этот класс в Application Context нашего SpringBoot.
Application Context — это место, где хранятся созданные объекты для работы проекта. Чтобы добавить какой-то класс, нужно использовать одну из аннотаций: @Component, @Service, @Repository, @Controller. Или аннотацию @Bean, если создается через метод в конфигурационном классе (то есть в классе, который помечен аннотацией Configuration).
Я понимаю, что все это пока может казаться непонятным. Но когда вы начнете разбираться, увидите, что ничего сложного там нет. Чтобы быстро разобраться со Spring Boot, советую крутую книжку — Spring In Action 5th edition. Если будет желание, я могу написать серию статей по этой книге.
Возвращаемся обратно. В пакете, в котором лежит JavarushTelegramBotApplication, создаем пакет bot, в котором будет лежать наш телеграм-бот. Имя у него будет JavaRushTelegramBot:
package com.github.javarushcommunity.jrtb.bot;
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.meta.api.objects.Update;
/**
* Telegrambot for Javarush Community from Javarush community.
*/
@Component
public class JavarushTelegramBot extends TelegramLongPollingBot {
@Override
public void onUpdateReceived(Update update) {
}
@Override
public String getBotUsername() {
return null;
}
@Override
public String getBotToken() {
return null;
}
}
Этот класс был абстрактный и нужно было реализовать три метода. Поговорим о них подробнее:- onUpdateReceived(Update update) — это и есть точка входа, куда будут поступать сообщения от пользователей. Отсюда будет идти вся новая логика;
- getBotUsername() — здесь нужно добавить username нашего бота, к которому будем соединяться;
- getBotToken() — а это, соответственно, токен бота.
- bot.username;
- bot.token.
package com.github.javarushcommunity.jrtb.bot;
import org.springframework.beans.factory.annotation.Value;
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.meta.api.objects.Update;
/**
* Telegram bot for Javarush Community from Javarush community.
*/
@Component
public class JavarushTelegramBot extends TelegramLongPollingBot {
@Value("${bot.username}")
private String username;
@Value("${bot.token}")
private String token;
@Override
public void onUpdateReceived(Update update) {
}
@Override
public String getBotUsername() {
return username;
}
@Override
public String getBotToken() {
return token;
}
}
Видно, что мы передали в аннотацию значение переменной. И вот когда SpringBoot будет создавать объект нашего бота, то и значения будут взяты с пропертей (опять калька с английского — properties).
Мы уже почти у цели. Нужно сделать так, чтобы бот что-то отвечал. Поэтому обновим метод onUpdateReceived. Нужно, чтобы мы извлекли сообщение, которое пришло к боту, и передали его обратно. Так мы будем знать, что бот работает.
Для этого мы грубо и быстро напишем то, что нужно:
@Override
public void onUpdateReceived(Update update) {
if(update.hasMessage() && update.getMessage().hasText()) {
String message = update.getMessage().getText().trim();
String chatId = update.getMessage().getChatId().toString();
SendMessage sm = new SendMessage();
sm.setChatId(chatId);
sm.setText(message);
try {
execute(sm);
} catch (TelegramApiException e) {
//todo add logging to the project.
e.printStackTrace();
}
}
}
Здесь все предельно просто: мы проверяем, что сообщение реально существует, потому извлекаем само сообщение (message) и айдишник чата (chatId), в котором идет переписка.
Далее мы создаем объект для отправки сообщения SendMessage, передаем в него само сообщение и айдишник чата — то есть то, что отправить боту и куда.
Этого нам уже хватает. Далее запускаем main метод в класс JavarushTelegramBotApplication и ищем нашего бота в Телеграме:Из логов видим, что бот запустился. Значит, пришло время идти в Телеграм и написать боту:Нажимаем начать и нам сразу же приходит ответ:Напишем еще какую-то лабуду, чтобы проверить:И все, на этом моменте можно сказать, что задача наша JRTB-2 завершена. Здесь пока что особенно тесты не напишешь, поэтому оставим все как есть.
Далее нужно создать новый коммит:Обратите внимание на имя коммита: опять заостряю ваше внимание на этом. Коммит вначале содержит имя задачи, а потом уже более детальное описание, что сделано.
Нажимаем Commit and Push… и подтверждаем, еще раз нажав Push:Переходим в наш проект. Как и раньше, GitHub уже увидел новую ветку и предлагает создать пул-реквест на main. Не противимся и создаем его:Уже как обычно выбрали лейбу, проект и назначили ее на меня. В конце нажимаем Create Pull Request.
Немного подождем, пока пройдет билд — и все, пул-реквест готов к слиянию:Версионирование
Я как-то упустил момент, что нам нужно вести версионирование. Для этого сделаем еще несколько изменений в нашей ветке. Заходим обратно в IDEA и смотрим на версию проекта в помнике:Стоит версия 0.0.1-SNAPSHOT. Это дежурная версия. А мы начнем с того, что будем обновлять версию проекта с каждой новой решенной задачей. Пока мы не вышли в MVP, версия будет идти с суффиксом -SNAPSHOT. Какая будет схема версионирования? X.Y.Z-SNAPSHOT Где:- X — мажорное обновление версии, зачастую содержит проблемы с обратной совместимостью с предыдущей версией;
- Y — не сильно большие изменения, полностью совместимые с предыдущей версией;
- Z — счетчик дефектов, которые мы нашли и починили.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ