Search
Write a publication
Pull to refresh

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 цитат и это только с одной страницы.

Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.