Как стать автором
Обновить

Telegram bot на Java? Быстро и легко

Публикаций по данной теме не мало, на самом хабре есть дюжина страниц с полезной информацией. Зачем я решил написать очередную статью о создании бота? Для начинающих в изучении java это хороший вариант познакомиться с Maven и Telegram API, для людей далеких от IT - возможность создать бота с нуля. Ниже я попытаюсь описать создание простейшего бота. Программа будет иметь несложный функционал, по моей задумке бот будет хранить в себе различные цитаты великих людей и по запросу пользователя, отправлять случайные из них. Что нам понадобится? Аккаунт в telegram и среда разработки, я использую Intellij IDEA. Описывать процесс установки не буду, в интернете есть достаточно подробные инструкции.

Шаг перый - регистрация бота в системе

Создание любого бота начинается с обращения к самому главному из них.

  1. Заходим в телеграмм и ищем @BotFather.

  2. Пишем ему команду /newbot

  3. Далее он спросит название будущего бота (грубо говоря, это заголовок в чате, который будут видеть пользователи) и его имя. Главное условие для имени - оно должно оканчиваться на 'bot'.

Инициализация закончена, BotFather отправит нам ссылку на нашего будущего бота и, самое главное, выдаст нам уникальный токен, необходимый для авторизации в системе. По сути бот готов, уже можно его найти в общем поиске по имени и начать ему писать, но логика у нас еще не готова

Шаг второй - создание проекта в среде разработки и добавление зависимостей

File>New>Project

Создаем новый проект и в процессе настройки обязательно выбираем maven, он необходим для автоматизации сборки проектов. С помощью этого инструмента мы на порядок облегчим себе жизнь, добавление сторонних библиотек не составит труда.

Для использования Telegram API, cкачивать и подключать извне ничего не нужно, достаточно зайти в pom.xml в корневом каталоге и написать несколько строк. С помощью конструкции <dependencies><dependency>***</dependency></dependencies> мы указываем среде разработки, какие библиотеки нужно загрузить и добавить в проект, в нашем случае это org.telegram. Остальную часть файла maven сгенерировал сам. Получаем такой файл:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>TgBotQuote</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>16</maven.compiler.source>
        <maven.compiler.target>16</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.telegram</groupId>
            <artifactId>telegrambots</artifactId>
            <version>5.3.0</version>
        </dependency>
    </dependencies>

</project>

Шаг третий - логика

Наш бот будет уметь хранить и отправлять случайные фразы великих людей. Я создал три класса: Main, Bot, Storage, начнем с последнего, с хранилища. Создаем коллекцию quoteList, инициализируем в конструкторе и добавляем несколько фраз. Также создаем функцию, котораю выдает случайную фразу из нашего хранилища getRandQuote().

public class Storage {
    private ArrayList<String> quoteList;
    Storage()
    {
        quoteList = new ArrayList<>();
        quoteList.add("Начинать всегда стоит с того, что сеет сомнения. \n\nБорис Стругацкий.");
        quoteList.add("80% успеха - это появиться в нужном месте в нужное время.\n\nВуди Аллен");
        quoteList.add("Мы должны признать очевидное: понимают лишь те,кто хочет понять.\n\nБернар Вербер");
    }

    String getRandQuote()
    {
    		//получаем случайное значение в интервале от 0 до самого большого индекса
        int randValue = (int)(Math.random() * quoteList.size());
        //Из коллекции получаем цитату со случайным индексом и возвращаем ее  
        return quoteList.get(randValue);
    }
}

Далее, создаем класс Bot и наследум его от TelegramLongPollingBot, предварительно создав две константы BOT_TOKEN(токен выдал BotFather), BOT_NAME и экземпляр класса Storage. Среда попросит реализовать три метода от материнского класса getBotUserName(), getBotToken() и onUpdateReceived(). Первые два возращают имя бота и его токен соответственно, а последний вызывается при каждой отправке сообщения пользователем, он нас и интересует. Метод onUpdateReceived(Update update) получает на вход объект update, из которого мы можем получить сообщение, текст и id чата, необходмые для отправки ответного сообщения. Также я написал метод parseMessage(), который принимает текст сообщения пользователя, обрабатывает (сравнивает текст с возможными командами) и выдает ответ

Дабы не усложнять учебный процесс, ограничимся только двумя командами. При первом запуске любого бота автоматически отправляется команда /start . Советую всегда реализовывать ответ на это сообщение, в нашем случае это простое приветствие и краткое объяснение функционала. Вторая команда, которую умеет определять наш бот - /get. В ответ на сообщение мы обращаемся к нашему хранилищу storage и методом getRandQuote() получаем случайную цитату и отправляем ее дальше. На самом деле необязательно использовать косую черту и латиницу, количеством и функционалом команд вы ограничены только своим воображением

public class Bot extends TelegramLongPollingBot {
		//создаем две константы, присваиваем им значения токена и имя бота соответсвтенно
    //вместо звездочек подставляйте свои данные
    final private String BOT_TOKEN = "***";
    final private String BOT_NAME = "***";
    Storage storage;

    Bot()
    {
        storage = new Storage();
    }

    @Override
    public String getBotUsername() {
        return BOT_NAME;
    }

    @Override
    public String getBotToken() {
        return BOT_TOKEN;
    }

    @Override
    public void onUpdateReceived(Update update) {
        try{
            if(update.hasMessage() && update.getMessage().hasText())
            { 
                //Извлекаем из объекта сообщение пользователя
                Message inMess = update.getMessage();
                //Достаем из inMess id чата пользователя
                String chatId = inMess.getChatId().toString();
                //Получаем текст сообщения пользователя, отправляем в написанный нами обработчик 
                String response = parseMessage(inMess.getText());
                //Создаем объект класса SendMessage - наш будущий ответ пользователю
                SendMessage outMess = new SendMessage();

                //Добавляем в наше сообщение id чата а также наш ответ
                outMess.setChatId(chatId);
                outMess.setText(response);
                
                //Отправка в чат
                execute(outMess);
            }
        } catch (TelegramApiException e) {
            e.printStackTrace();
        }
    }
    public String parseMessage(String textMsg) {
        String response;
				
        //Сравниваем текст пользователя с нашими командами, на основе этого формируем ответ  
        if(textMsg.equals("/start"))
            response = "Приветствую, бот знает много цитат. Жми /get, чтобы получить случайную из них";
        else if(textMsg.equals("/get"))
            response = storage.getRandQuote();
        else
            response = "Сообщение не распознано";

        return response;
    }
}

В главном классе создаем сессию и регистрируем бота

public class Main {
    public static void main(String args[])
    {
        try {
            TelegramBotsApi telegramBotsApi = new TelegramBotsApi(DefaultBotSession.class);
            telegramBotsApi.registerBot(new Bot());
        } catch (TelegramApiException e) {
            e.printStackTrace();
        }
    }
}

Жмем run. После запуска заходим в мессенджер, находим нашего бота, начинаем чат и вуаля, бот готов к общению. Прямо из среды разработки наша программа доступна к использованию в telegram. Основная цель на статью выполнена - мы познакомились со структурой программы, с основными методами, быстро и легко получили рабочий шаблон бота, на основе которого теперь вы можете поробовать написать своего элементарного робота. Теперь хотелось бы сделать его чуточку удобнее. Ну и разнообразить наш контент не помешало бы

Шаг четвертый - добавляем клавиатуру

Для этого в классе Bot создадим экземпляр класса ReplyKeyboardMarkup, грубо говоря это шаблон ответов, который мы прикрепляем к нашему сообщению. Он состоит из объектов KeyboardRow, которые в свою очередь представяют ряды кнопок. Все это я реализовал в отдельном методе и вызвал его в конструкторе класса Bot

void initKeyboard()
    {
        //Создаем объект будущей клавиатуры и выставляем нужные настройки
        replyKeyboardMarkup = new ReplyKeyboardMarkup();
        replyKeyboardMarkup.setResizeKeyboard(true); //подгоняем размер
        replyKeyboardMarkup.setOneTimeKeyboard(false); //скрываем после использования

        //Создаем список с рядами кнопок
        ArrayList<KeyboardRow> keyboardRows = new ArrayList<>();
        //Создаем один ряд кнопок и добавляем его в список
        KeyboardRow keyboardRow = new KeyboardRow();
        keyboardRows.add(keyboardRow);
        //Добавляем одну кнопку с текстом "Просвяти" наш ряд
        keyboardRow.add(new KeyboardButton("Просвяти"));
        //добавляем лист с одним рядом кнопок в главный объект
        replyKeyboardMarkup.setKeyboard(keyboardRows);
    }

Нам хватит всего одной кнопки для реализации задумки. Нет ни каких проблем методом add() добавить необходимое количество рядов и клавиши на них. Вы можете создавать различные клавиатуры, скрывать и показывать их пользователю в разных ситуациях. Также существует второй класс для создания клавиатур - InlineKeyboard, позволяющий делать более сложные действия, но мы оставим первый вариант

Теперь, в методе onUpdateReceived() к исходящему от нас сообщению добавляем клавиатуру.

outMess.setReplyMarkup(replyKeyboardMarkup);

Так как нажатие на кнопку отправляет в чат то, что на ней написано, немного изменим наш обработчик. Теперь бот понимает сообщение "Просвяти" и реагирует на него, как на команду /get

else if(textMsg.equals("/get") || textMsg.equals("Просвяти"))
            response = storage.getRandQuote();

После запуска мы видим, что все прекрасно работает. Изучение telegram API в этой публикации на этом заканчивается. Я только поверхностно рассказал об основных возможностях этой библиотеки, для более подробных знаний есть достаточно подробная документацию. Стоило бы закончить статью, но чего-то нашему боту не хватает - разнообразия в контенте. Три цитаты это слишком несерьезно - значит пишем парсер

Шаг пятый - пишим простой парсер

Что такое парсер? Парсер - программа, которая извлекает и анализирует данные с веб страниц. Данный шаг не относится к непосредсвенному написанию ботов, поэтому вдаваться в подробности не буду, этой теме можно посвятить отдельную статью.

Для начала в файле pom.xml прописываем еще одну зависимость. Библиотека jsoup позволяет нам работать с веб страницами, располагает очень удобными методами для обращения к определенным элементам на сайтах.

		<dependency>
			<groupId>org.jsoup</groupId>
			<artifactId>jsoup</artifactId>
			<version>1.14.3</version>
		</dependency>

Взяв первый попавшийся сайт с цитатами, я приступил к написанию парсера. Для этого в классе Storage я написал метод parser(String strURL), который принимает на вход ссылку искомой страницы. Изучив страницу сайта через исходный код в браузере, я нашел блок, в котором находятся цитаты - "su-note-inner su-u-clearfix su-u-trim".

void parser(String strURL)
    {
        String classNmae = "su-note-inner su-u-clearfix su-u-trim";
        Document doc = null;
        try {
            //Получаем документ нужной нам страницы
            doc = Jsoup.connect(strURL).maxBodySize(0).get();
        } catch (IOException e) {
            e.printStackTrace();
        }

        //Получаем группу объектов, обращаясь методом из Jsoup к определенному блоку
        Elements elQuote = doc.getElementsByClass(classNmae);

        //Достаем текст из каждого объекта поочереди и добавляем в наше хранилище
        elQuote.forEach(el -> {
            quoteList.add(el.text());
        });
    }

Осталось только где-то вызвать наш метод. Сделал это я в конструкторе класса Storage, чтобы наполнить нашу коллекцию на этапе запуска программы и инициализации объектов. Код, в котором мы вручную добавляли цитаты в хранилище, я удалил. Вместо них - метод вызова парсера, которому мы передаем ссылку на сайт.

parser("https://citatnica.ru/citaty/mudrye-tsitaty-velikih-lyudej");

Запускаем! Теперь вместо скудного запаса из трех высказываний, бот знает 200 цитат и это только с одной страницы.

Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.