Долгое время изучаю Java (но работаю с Oracle) и всё время хочется написать что-то полезное и интересное. Так наткнулся на статьи о Телегам ботах, которые меня и надоумили соорудить своего бота Avandy News.
За идеей для функционала далеко ходить не пришлось, т.к. у меня имеется одна более менее успешная программа, которая попала в Реестр российского ПО (о ней и о том как попасть в Реестр я писал в этой статье).
Видеообзор можно посмотреть на Youtube, а если вкратце о функционале, то:
автоматический поиск новостей по ключевым словам (вы задаёте частоту поиска новостей и добавляете слова, заголовки с которыми хотите получать)
поиск всех новостей с фильтрацией за выбранный период (просто почитать что сейчас пишут СМИ, но с возможностью отсеивать новости типа "Как правильно красить ресницы". Добавляете слово "ресниц" в слова-исключения и таких заголовков больше не получите. У меня таких исключений уже почти 3 тысячи и сейчас из 2 тысяч новостей в среднем за день, я читаю около 150-200 действительно важных новостей).
Топ 20 часто употребляемых слов в заголовках за период (здесь нет фильтрации и, посмотрев "Топ 20", вы сразу поймёте о чём сейчас пишут СМИ, а благодаря быстрому поиску сразу же прочитаете все новости с выбранным словом).
Топ 20 слов в новостях за 4 часа (включено удаление окончаний)
Почему я пишу эту статью?
Да потому, что много постов где бот написан на языке Python и от этого у меня был стереотип, что боты пишутся только на этом языке. Однако я понимал, что на Java можно сделать очень многое, поэтому поджипитил (погуглил уже неактуально) и нашёл неплохой курс на YouTube. Посмотрел - сделал первую версию бота (исходный код, пользуйтесь, конструктивно критикуйте на здоровье).
Бот написан на Spring Boot версии 3.1.5, сборка проекта производится с помощью Maven. База данных - PostgreSQL (на сервере версия 14.10, на локальном ПК версия 16.1).
Дальше уже был миллиард доработок:
изучение логов поведения пользователей, которые творили нереальную дичь, для упрощения и понятности интерфейса.
перевод интерфейса на английский язык (UI может быть либо на русском, либо на английском языке. Язык определяется исходя из настроек пользователя в Телеграме. У меня установлен английский язык. Это подтверждается тем, что после команды start, бот просит выбрать язык на английском языке).
добавление источников новостей из других стран, т.к. на бота подписался человек из Колумбии и добавил ключевые слова на Испанском языке. Не хотелось его разочаровывать. Теперь он получает 10-20 новостей в неделю по своим ключевым словам.
добавление французских, немецких и американских источников новостей (пользователь на старте выбирает на каком языке он хочет получать новости)
В общем, перечислять можно долго, поэтому посмотрим что там "под капотом".
А под капотом...
Бот и база данных расположены на VDS от Спринбокс[ссылка удалена модератором] (процессор - 1 шт., RAM - 1 Gb, Память - 16 Gb (SSD), платёж - 349 рублей в месяц).
Операционная система: Ubuntu 22.04 "Jammy Jellyfish" [x64].
На сервере вручную установлены Java 17 и Postgres 14.10, а бот представляет собой jar файл, который лежит в домашней директории и запускается сервисом на Linux.
Пример сервиса
Cоздадим файл сервиса с именем bot.service, который содержит переменные окружения, указанные в application.properties
Файл создавать здесь /lib/systemd/system/
Содержимое файла
[Unit]
Description=Avandy News Bot
[Service]
ExecStart=java -jar /home/bot.jar
Type=idle
KillMode=process
SyslogIdentifier=bot
SyslogFacility=daemon
Restart=on-failure
Environment="TOKEN=здесь указываем токен бота"
Environment="PWD=здесь пароль подключения к БД"
[Install]
WantedBy=multiuser.target
После создания сервиса выполним команды
sudo systemctl enable bot.service
-- перезапускаем сервер
shutdown -r now
-- запускаем сервис
sudo systemctl start bot.service
-- проверяем, что сервис в статусе "active"
sudo systemctl status bot.service
Далее: собираем кальсоны ... потом прибыль :)
Схема базы данных выглядит так:

В общем - пользователи и другие дополнительные таблицы. Расскажу об интересных:
showed_news: сохраняются все найденные пользователем новости, чтобы не показывать одно и то же дважды. Заголовки хранятся в виде хэша и в будущем отсеиваются также по хэшу. Таким образом экономится место на диске, поскольку хэш это 10 символов, а длина заголовков от 20 до бесконечности (таблица очищается раз в 72 часа).
rss_list: список новостных источников (слово rss идёт издревле). В основном приложении у каждого пользователя свой набор источников новостей. Здесь у каждой страны - свой набор. Поле chat_id заложено на светлое будущее, где пользователь будет формировать свой список источников.
Таблица в транспонированном виде
keywords: список ключевых слов
excluding_terms: (слова-исключения для полного поиска)
top_excluded: (слова, которые вы ранее удалили, т.к. не хотели их видеть в Топ 20)
news_list: архив всех новостей (таблица очищается раз в 72 часа)
settings: настройки пользователя (можно настроить частоту запуска поисков и отключить автопоиск или фильтрацию новостей)
Для быстроты доступа к данным и исключения дубликатов используются уникальные индексы, а для целостности данных в таблицах созданы внешние ключи (как никак 5 лет работы с SQL дают о себе знать).
Полезная информация
В BotFather я сделал второго бота для тестирования нового функционала, чтобы не затрагивать работ основного бота, поскольку два экземпляра одного и того же бота не могут быть запущены одновременно.
По умолчанию в application.properties у меня активирован токен второго тестового бота, а когда надо собрать проект, то четвёртую строку я комментирую, третью наоборот.

Очень удобно использовать переменные среды (окружения).
В Windows 10 они задаются так: нажмите правой кнопкой на "Мой компьютер" (не на ярлыке) и выберите "Свойства", потом "Дополнительные параметры системы", далее нажмите кнопку "Переменные среды". Создайте эти переменные с любым именем. Обязательно перезагрузите компьютер. Свойства компьютера можно также вызвать, нажав Win + Pause/Break.

Благодарности
Спасибо больше Павлу Дурову за сам Телеграм и за BotFather. Благодаря этому мне не нужно тратить уйму времени на изучение мобильной разработки, а моё детище доступно по всему Миру. Жму руку (удалённо), желаю процветания!