Приветствую вас, мои дорогие друзья. Да-да, именно друзья. Я уже так сросся с этой серией статей, что те люди, которые регулярно пишут в комментариях свою благодарность и/или показывают, что прочли и поняли материал, стали уже близки.
Мы с вами идем с двух сторон к одной цели. Вы хотите понять, а я хочу объяснить. И конечная цель у нас одна — написанное приложение, которое понятно вам от начала до конца.
О многом из того, что опишу в этой статье вы, возможно, уже наслышаны. Не думаю, что я расскажу что-то новое и неординарное (но в рамках проекта знать/повторить это необходимо).
Весной я писал бота для себя, так что будем опираться на его “лекала”.
Далее нас просят дать имя этому боту. Так как это бот для тестовых задач, то и имя у него будет соответствующее:
[TEST] JavarushBot
Теперь пришло время дать уникальное имя, по которому его всегда можно будет найти — его username:
test_javarush_community
Как я и говорил выше, нужно добавлять суффикс _bot для username, поэтому пишем еще раз:
test_javarush_community_bot
И все! Бот создан. Теперь по username и token его можно подключить к нашему проекту. Разумеется для бесперебойной работы тестового сервера я не буду выставлять token (по сути это пароль к доступу к боту) этого бота на общее обозрение.
Исходя из описания, нам нужно просто создать новый класс, унаследоваться от TelegramLongPollingBot и добавить этот класс в Application Context нашего SpringBoot.
Application Context — это место, где хранятся созданные объекты для работы проекта. Чтобы добавить какой-то класс, нужно использовать одну из аннотаций: @Component, @Service, @Repository, @Controller. Или аннотацию @Bean, если создается через метод в конфигурационном классе (то есть в классе, который помечен аннотацией Configuration).
Я понимаю, что все это пока может казаться непонятным. Но когда вы начнете разбираться, увидите, что ничего сложного там нет. Чтобы быстро разобраться со Spring Boot, советую крутую книжку — Spring In Action 5th edition. Если будет желание, я могу написать серию статей по этой книге.
Возвращаемся обратно. В пакете, в котором лежит JavarushTelegramBotApplication, создаем пакет bot, в котором будет лежать наш телеграм-бот. Имя у него будет JavaRushTelegramBot:
У SpringBoot есть отличная аннотация — @Value. Если ее правильно использовать, то она подтянет нам значения из application.properties файла. Обновляем проект под это:
Из логов видим, что бот запустился. Значит, пришло время идти в Телеграм и написать боту:
Нажимаем начать и нам сразу же приходит ответ:
Напишем еще какую-то лабуду, чтобы проверить:
И все, на этом моменте можно сказать, что задача наша JRTB-2 завершена. Здесь пока что особенно тесты не напишешь, поэтому оставим все как есть.
Далее нужно создать новый коммит:
Обратите внимание на имя коммита: опять заостряю ваше внимание на этом. Коммит вначале содержит имя задачи, а потом уже более детальное описание, что сделано.
Нажимаем Commit and Push… и подтверждаем, еще раз нажав Push:
Переходим в наш проект. Как и раньше, GitHub уже увидел новую ветку и предлагает создать пул-реквест на main. Не противимся и создаем его:
Уже как обычно выбрали лейбу, проект и назначили ее на меня. В конце нажимаем Create Pull Request.
Немного подождем, пока пройдет билд — и все, пул-реквест готов к слиянию:!["Java-проект от А до Я": добавляем телеграм-бота на проект - 17]()
Стоит версия 0.0.1-SNAPSHOT. Это дежурная версия. А мы начнем с того, что будем обновлять версию проекта с каждой новой решенной задачей.
Пока мы не вышли в MVP, версия будет идти с суффиксом -SNAPSHOT.
Какая будет схема версионирования?
X.Y.Z-SNAPSHOT
Где:
Идем в файл RELEASE_NOTES, где будем описывать изменения проекта с каждой новой версией:
Наша первая запись. Теперь при каждом последующем обновлении версии будем здесь описывать что именно произошло.
Делаем коммит этого дела, пишем описание:
JRTB-2: updated project version and added to RELEASE_NOTES
Все точно так же, как и до этого. Ждем, пока билд пройдет, и мы сможем смержить наши изменения.
Только здесь будет несколько иначе. Я хочу сделать так, чтобы каждая задача в main ветке была отдельным коммитом, поэтому просто нажать в пул-реквест Merge pull request нам не подойдет.
В гите есть опция git squash, которая собирает все коммиты в один и мержит.
Выбираем эту опцию:
Нажимаем Squash and Merge, и нам предлагают еще отредактировать сообщение, которое будет в итоге:
Очень удобно и главное, что востребовано. К слову, на битбакете такой фичи я не видел =/
Подтверждаем мерж.
Осталась самая малость — перевести задачу в статус Done у нас в доске, написать комментарий со ссылкой на пул-реквест и закрыть его:
Наша доска теперь выглядит так:!["Java-проект от А до Я": добавляем телеграм-бота на проект - 24]()
Спасибо им за это! Что же теперь делать? Удалить из гита уже не получится, так как даже если я накачу новый коммит уже без этого токена, то он все равно останется в старом. А удалять и откатывать назад коммит я не хочу. Поэтому я пошел и деактивировал токен у уже упомянутого BotFather. Теперь токен есть, но он уже недействителен.
Подписывайтесь на мой гитхаб аккаунт, чтобы раньше публикации статьи увидеть весь код по ней.
Всем спасибо за чтение, до встречи.
!["Java-проект от А до Я": добавляем телеграм-бота на проект - 1](https://cdn.javarush.com/images/article/05bf61f9-8d16-4258-8c1e-c6195f1fff2d/800.jpeg)
Пишем 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!["Java-проект от А до Я": добавляем телеграм-бота на проект - 4](https://cdn.javarush.com/images/article/da251e55-7d65-405d-8269-eae59ddec3fd/1080.jpeg)
!["Java-проект от А до Я": добавляем телеграм-бота на проект - 5](https://cdn.javarush.com/images/article/cf774e29-d1bd-45ac-be63-4eec1ace7c8b/1080.jpeg)
!["Java-проект от А до Я": добавляем телеграм-бота на проект - 6](https://cdn.javarush.com/images/article/bc2012c9-a5fd-409c-9afb-d731c2498ba9/1080.jpeg)
!["Java-проект от А до Я": добавляем телеграм-бота на проект - 7](https://cdn.javarush.com/images/article/fb211e24-7ad5-4826-93ac-131f48bec30b/1080.jpeg)
Подключаем бота в проект
Мы не будем подключать библиотеку как обычно, а сразу воспользуемся преимуществами нашего скелета — 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>
Добавляем ее в наш помник. Выносим версию как положено и обновляем мавен проект.!["Java-проект от А до Я": добавляем телеграм-бота на проект - 8](https://cdn.javarush.com/images/article/f4f45c30-c562-4961-b5c7-c08d60352a05/800.jpeg)
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.
!["Java-проект от А до Я": добавляем телеграм-бота на проект - 9](https://cdn.javarush.com/images/article/f49789c6-3378-42d7-9da2-c7e7ec38b72c/512.jpeg)
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 и ищем нашего бота в Телеграме:!["Java-проект от А до Я": добавляем телеграм-бота на проект - 10](https://cdn.javarush.com/images/article/0e5175c2-2cea-4294-b6d8-2d7b42e5d0ec/1080.jpeg)
!["Java-проект от А до Я": добавляем телеграм-бота на проект - 11](https://cdn.javarush.com/images/article/1bed4559-f9bf-43e5-b4b8-dcdd4eb4a2ed/512.jpeg)
!["Java-проект от А до Я": добавляем телеграм-бота на проект - 12](https://cdn.javarush.com/images/article/392c2361-b04e-411e-8750-44ff8ac05b56/512.jpeg)
!["Java-проект от А до Я": добавляем телеграм-бота на проект - 13](https://cdn.javarush.com/images/article/42578b38-d572-40a1-8c58-b56c9848dba3/512.jpeg)
!["Java-проект от А до Я": добавляем телеграм-бота на проект - 14](https://cdn.javarush.com/images/article/fab24536-9f78-4d76-87aa-94662b19ad7b/512.jpeg)
!["Java-проект от А до Я": добавляем телеграм-бота на проект - 15](https://cdn.javarush.com/images/article/bb41a8e6-2dee-4b14-be36-460e23b60ace/512.jpeg)
!["Java-проект от А до Я": добавляем телеграм-бота на проект - 16](https://cdn.javarush.com/images/article/75880a98-5812-49e7-bc02-09d2d4fb5ff5/800.jpeg)
!["Java-проект от А до Я": добавляем телеграм-бота на проект - 17](https://cdn.javarush.com/images/article/f63be8c4-31ec-47fb-af9b-dc621e0f3489/800.jpeg)
Версионирование
Я как-то упустил момент, что нам нужно вести версионирование. Для этого сделаем еще несколько изменений в нашей ветке. Заходим обратно в IDEA и смотрим на версию проекта в помнике:!["Java-проект от А до Я": добавляем телеграм-бота на проект - 18](https://cdn.javarush.com/images/article/5637da0d-2fe8-4d59-8674-f1790d03a305/512.jpeg)
- X — мажорное обновление версии, зачастую содержит проблемы с обратной совместимостью с предыдущей версией;
- Y — не сильно большие изменения, полностью совместимые с предыдущей версией;
- Z — счетчик дефектов, которые мы нашли и починили.
!["Java-проект от А до Я": добавляем телеграм-бота на проект - 19](https://cdn.javarush.com/images/article/44e2a45c-6291-4fdf-bda5-042e6a7ba595/800.jpeg)
!["Java-проект от А до Я": добавляем телеграм-бота на проект - 20](https://cdn.javarush.com/images/article/138e13d9-499b-45d4-a2e7-e20d81cdf3a5/800.jpeg)
!["Java-проект от А до Я": добавляем телеграм-бота на проект - 21](https://cdn.javarush.com/images/article/24112b77-07f4-4eb6-b649-5faf70bcf2d6/800.jpeg)
!["Java-проект от А до Я": добавляем телеграм-бота на проект - 22](https://cdn.javarush.com/images/article/a583cdfc-9d42-4f03-b956-feeda0294423/800.jpeg)
!["Java-проект от А до Я": добавляем телеграм-бота на проект - 23](https://cdn.javarush.com/images/article/d04861f7-8bc2-45c1-b589-6c9b328c2afb/800.jpeg)
!["Java-проект от А до Я": добавляем телеграм-бота на проект - 24](https://cdn.javarush.com/images/article/9a32e01a-6370-4fae-b8a5-ba7203aa5c89/800.jpeg)
Вывод
Сегодня мы шаг за шагом создали телеграм-бота и внедрили его в наш SpringBoot проект. Бот работает, отдает ответы. Сделали сразу же доступ к данным бота через проперти. Дальше больше: будем делать большой кусок — выполнять JRTB-3 — добавление Command Pattern для нашего проекта. Ох, еще один нюанс…. Я же говорил, что не буду публиковать token, чтобы им не воспользовались. Но так как я писал статью уже ближе к полуночи и после рабочего дня, то вышло, что я выложил-таки в репозиторий действующий токен, а сказала мне об этом GitGuardian в письме:!["Java-проект от А до Я": добавляем телеграм-бота на проект - 25](https://cdn.javarush.com/images/article/573a85c7-ed5f-4f7a-84b4-daf515eedb33/512.jpeg)
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ