Pull to refresh

Простыми словами про обработку текстовых запросов пользователя в Телеграмм ботах на java

Level of difficultyMedium
Reading time5 min
Views2.9K
найдено на просторах Интернета
найдено на просторах Интернета

Мотивация

У разработчика, предпочитающего индивидуальные проекты, есть множество способов самореализации. Для меня, например, приоритетным является создание небольших Telegram-ботов на java. Ведь помимо того, что в процессе разработки всегда можно наглядно проверить работу программы на любом этапе ее реализации, Telegram-боты, на мой взгляд, имеют потребительский потенциал в основном за счет того, что, являясь программой, они не нуждаются в отдельной установке на устройство. Достаточно пользоваться мессенджером Telegram и запустить в нем бот с подходящим функционалом, что, как минимум, экономит ресурсы самого устройства.

Ранее на Хабре я уже делилась с читателями своим опытом самостоятельного создания несложных Telegram-ботов на java, а также небольшими пошаговыми инструкциями по решению отдельных вопросов, возникающих при написании кода. После новогодней разработки очередного чат-бота хочу продолжить сложившуюся традицию и рассказать немного о некоторых нюансах одного из распространенных способов взаимодействия с ботом – принятие и обработка от пользователя запроса с сообщением.

Детализация

Тем, кто так или иначе уже сталкивался с разработкой Telegram-ботов на java, известно, что бот должен уметь отправлять запросы Telegram-серверу и получать от него обновления (updates). В настоящее время существует два способа получения обновлений:

- использование LongPolling (регулярную отправку запрос к серверу Telegram для получения обновлений. Все обновления обрабатываются последовательно, что делает бота очень простым для отладки, а все поведение - предсказуемым),

- использование Webhooks (Telegram сам отправляет запросы по нужному URL).

Поскольку LongPolling используется по умолчанию, я буду рассматривать взаимодействие с ботом на его примере.

Итак, для того, чтобы класс, содержащий логику бота, реализовывал взаимодействие с сервисами Telegram, его необходимо унаследовать от класса TelegramLongPollingBot и реализовать следующие его базовые методы:

- public void onUpdateReceived(Update update);

- public String getBotUsername();

- public String getBotToken().

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

Основной функционал моего последнего бота прост: он принимает от пользователя текстовое сообщение с двумя параметрами (вес и рост, указанными целыми цифрами и разделенными одним пробелом), рассчитывает по формуле индекс массы тела (ИМТ) и высылает пользователю результат с характеристикой и краткими рекомендациями. То есть, помимо команд, которые предусмотрены в моем боте, обрабатывается только одно текстовое сообщение от пользователя.

Казалось бы, все предельно просто – достаточно лишь проверить при реализации метода onUpdateReceived, есть ли во входящем обновлении (update) сообщение (метод getMessage()) и есть ли в таком сообщении текст (метод hasText()). Но текст должен быть с определенными параметрами – это должно быть 2 целые цифры, разделенные пробелом. Все остальные запросы должны блокироваться, а пользователю высылаться сообщение об ошибке и повторная просьба корректно направить запрос.

Реализация

Для себя я нашла следующий вариант обработки и запроса:

1. Проверить входящее сообщение на наличие в нем пробелов и, при наличии таковых, разделить строку на части и создать из них массив.

 2. В созданном массиве проверить длину такого массива и принадлежность элементов к целым положительным числам и, при соблюдении условий, вызвать метод, в котором производится расчет ИМТ, присвоив его параметрам соответствующие значения элементов массива.

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

Синтаксис регулярных выражений основан на использовании символов <([{\^-=$!|]})?*+.>, которые можно комбинировать с буквенными символами.

Поскольку меня интересовали только целые числа, я использовала следующие символы регулярного выражения:

‘\d’ - соответствует любой одной цифре и заменяет собой выражение [0-9];

‘+’ – частота появления элемента (1 или более цифра в выражении),

и matches() – метод, который возвращает true только тогда, когда вся строка соответствует заданному регулярному выражению.

 3. Во всех остальных случаях, не подпадающих под заданные проверки, пользователь должен получать сообщение об ошибке и необходимости корректно ввести запрос.  

В итоге, если опустить реализацию методов, участвующих в обработке команд, расчете ИМТ и формировании рекомендаций, передаче данных в базу данных, у меня получилась вот такая реализация метода onUpdateReceived:

@SneakyThrows
@Override

    public void onUpdateReceived(Update update) {

// проверка, содержит ли обновление сообщение и содержит ли сообщение текст
        if (update.hasMessage() && update.getMessage().hasText()) {

            String messageText = update.getMessage().getText();
            Long chatId = update.getMessage().getChatId();

            Message message = update.getMessage();
            User from = message.getFrom();

            SendMessage sendMessage = new SendMessage();
            sendMessage.setChatId(update.getMessage().getChatId().toString());


            if (commandType.types().contains(messageText)) {
                commandHandler.onUpdateReceived(update);


// если сообщение с текстом содержит пробел
            } else if (messageText.contains(" ")) {


// создаем строковый массив, в котором элементы образуются через разделитель - пробел
                String[] weightAntHeight = update.getMessage().getText().split(" ");


// если длина массива 2 элемента, которые соответствуют целым числам 
//(те самые нужные нам значения веса и роста),
                if (weightAntHeight.length == 2
                        && weightAntHeight[0].matches("\\d+")
                        && weightAntHeight[1].matches("\\d+")) {


// производим расчет ИМТ, высылаем пользователю результаты и рекомендации, заносим результаты в базу данных
                    String resultImt = String.format("%.1f", ImtCount.imt(weightAntHeight[0], weightAntHeight[1]));
                    String resultWithDescription = ImtCount.description(weightAntHeight[0], weightAntHeight[1]);

                    WriteUser.writeUserIntoDb(LocalDateTime.now().withNano(0),
                            from.getId(), from.getFirstName()
                            , resultImt
                    );
                    sendMessage.setText(resultWithDescription);
                    execute(sendMessage);


// во всех остальных случаях выдается сообщение об ошибке и инструкция с правилами направления запроса.
                } else {
                    execute(Sender.sendMessage(chat_id, UNKNOWN + INSTRUCTION));
                }
            }

            else {
                execute(Sender.sendMessage(chat_id, UNKNOWN + INSTRUCTION));
            }

        }

}

Описанный способ может применяться, например, и при регистрации пользователя для формирования параметров обработки логина и пароля.

Резюмирование

Да, статей, посвященный разработке Telegram-ботов, великое множество, но, как показывает мой личный опыт поиска нужной информации, они в большинстве своем однотипны и зачастую не содержат ответов (разъяснений) на практические вопросы. В своих публикациях я делюсь самостоятельно пройденным путем больше с новичками и с теми, кому в принципе как и мне интересна разработка Telegram-ботов.

Надеюсь, этот разбор и реализация обработки текстовых запросов пользователя в проекте, код которого выложен на GitHub, кому-нибудь поможет при разработке своих телеграмм ботов.

Если интересно, как работает мой последний телеграмм бот, то милости прошу: Индекс массы тела.

Tags:
Hubs:
If this publication inspired you and you want to support the author, do not hesitate to click on the button
Total votes 4: ↑3 and ↓1+5
Comments4

Articles