JavaRush /Blog Java /Random-PL /Tworzenie bota telegramowego przy użyciu Spring Boot Pt.2...
Whiskels
Poziom 41
Москва

Tworzenie bota telegramowego przy użyciu Spring Boot Pt.2: Quiz Bot

Opublikowano w grupie Random-PL
CZĘŚĆ 1 Aloha! W poprzednim artykule stworzyliśmy prostego bota, który powita nas na każdym wydarzeniu. Napisaliśmy już tysiące linii kodu, czas dodać do naszego bota bardziej złożoną funkcjonalność. Dzisiaj spróbujemy napisać prostego bota, aby w wolnym czasie móc doskonalić swoją wiedzę z Java Core przed rozmowami kwalifikacyjnymi (o dziwo, nie znalazłem ani jednego działającego bota tego rodzaju). Aby to zrobić, wykonamy następujące czynności:
  • podłącz zewnętrzną bazę danych Postgres do Heroku;
  • Napiszmy nasze pierwsze skrypty inicjujące i zapełniające bazę danych;
  • podłączmy Spring Boot Data JPA do pracy z bazą danych;
  • Realizujemy różne scenariusze zachowania bota.
Jeśli jest to dla Ciebie interesujące, a po przeczytaniu artykułu nie chcesz już rzucać zgniłymi pomidorami, to wstaw gwiazdkę w moim repozytorium , będzie mi miło! Jeśli masz jakieś pytania, omówimy je w komentarzach. Oto co otrzymamy na końcu: Tworzenie bota telegramu przy użyciu Spring Boot Pt.2: Quiz Bot - 1Tworzenie bota telegramu przy użyciu Spring Boot Pt.2: Quiz Bot - 2Tworzenie bota telegramu przy użyciu Spring Boot Pt.2: Quiz Bot - 3<h2>No to zaczynamy!</h2><h3>Tworzenie bazy danych na Heroku</h3>Zacznijmy od stworzenia naszej pierwszej zewnętrznej bazy danych. Do pracy lokalnej polecam sprawdzić pgAdmin . Ale chcę, żebyś kierował się faktem, że w przyszłości wdrożysz bota na Heroku, aby nie był zależny od twojej lokalnej maszyny, i w tym celu zapoznajmy się z tą usługą. Procedura:
  • zarejestruj się na Heroku ;
  • Przejdź do naszego panelu -> Nowy -> Utwórz nową aplikację i utwórz nową aplikację;
  • Wchodzimy do nowo utworzonej aplikacji, przeraża nas ilość przycisków, ale skupiamy się na panelu „Zainstalowane dodatki” – obok niego znajduje się przycisk Konfiguruj dodatki, klikamy w niego;
  • W wyszukiwarce wpisz „Heroku Postgres”, wybierz plan „Hobby Dev - Free” -> Prześlij formularz zamówienia;
  • Otwórz nowo uzyskaną bazę danych -> Ustawienia -> Wyświetl dane uwierzytelniające. W tej zakładce będą znajdować się nasze klucze umożliwiające dostęp do bazy danych. Pamiętamy ich lokalizację - będą nam potrzebne do podłączenia bazy danych, tak jak DataSource w IDEA.
<h3>Dodaj zależności do pom.xml</h3>W ramach pracy nad naszym botem dodamy do naszego pom następujące zależności: Lombok, Spring Boot Data JPA, PostgreSQL. Zatrzymywać się! Co to wszystko jest i dlaczego to dodajemy?
  • Lombok to biblioteka, dzięki której znacząco zmniejszymy ilość różnego kodu. Dzięki niemu możemy automatycznie tworzyć konstruktory, setery, gettery i wiele więcej.
  • Spring Data JPA to framework do pracy z bazami danych (choć brzmi to zbyt prosto). Opis możliwości Spring Data JPA obejmowałby serię artykułów, a podana przez nas zależność obejmuje także Hibernate i wiele więcej, więc pomińmy szczegóły i po prostu spróbujmy dzisiaj napisać coś przy użyciu Spring JPA.
  • PostgreSQL - ściągamy bibliotekę, aby uzyskać sterownik, który będzie współpracował z naszą bazą danych.
Nasz pom.xml zaczyna wyglądać tak: Właściwości: Tworzenie bota telegramu przy użyciu Spring Boot Pt.2: Quiz Bot - 1Zależności: Tworzenie bota telegramu przy użyciu Spring Boot Pt.2: Quiz Bot - 2Jeśli nie czytałeś poprzedniego artykułu, pamiętaj, że dodajemy tutaj nowe zależności, więc nie jest to pełna struktura pom.xml. Nie zapomnij wczytać tych zależności do naszego projektu (np. przechodząc do okna Maven -> Zaimportuj ponownie wszystkie projekty Mavena).<h3>Podłączanie bazy danych w IDEA</h3>Jeśli korzystasz z IDEA Community Edition, możesz włącz kartę DataSource w następujący sposób . Po dodaniu wtyczki musimy skonfigurować DataSource. Aby to zrobić, najpierw włącz wyświetlanie wtyczki: Widok -> Okna narzędziowe -> Przeglądarka DB. W oknie, które zostanie otwarte, kliknij zielony plus (nowe połączenie) -> PostgreSQL. Tutaj będziemy potrzebować poświadczeń, które widzieliśmy już na Heroku. Wypełnij okno: Tworzenie bota telegramu przy użyciu Spring Boot Pt.2: Quiz Bot - 3I kliknij „Testuj połączenie”. Jeśli wszystko zostało wykonane poprawnie, pojawi się wyskakujące okienko z informacją, że połączenie z bazą danych powiodło się. Zapisz nasze źródło danych.<h3>Utwórz tabele w bazie danych</h3>Teraz utwórzmy tabele, z którymi będziemy pracować. Najpierw zainstalujmy PostgreSQL . Po instalacji utwórz plik initDB.sql w folderze src/main/resources:
DROP TABLE IF EXISTS java_quiz;
DROP TABLE IF EXISTS users;
CREATE SEQUENCE global_seq START WITH 100000;

CREATE TABLE users
(
    id         INTEGER PRIMARY KEY DEFAULT nextval('global_seq'),
    chat_id    INTEGER UNIQUE                NOT NULL,
    name       VARCHAR                       NOT NULL,
    score      INTEGER             DEFAULT 0 NOT NULL,
    high_score INTEGER             DEFAULT 0 NOT NULL,
    bot_state  VARCHAR                       NOT NULL
);

CREATE TABLE java_quiz
(
    id             INTEGER PRIMARY KEY DEFAULT nextval('global_seq'),
    question       VARCHAR NOT NULL,
    answer_correct VARCHAR NOT NULL,
    option1        VARCHAR NOT NULL,
    option2        VARCHAR NOT NULL,
    option3        VARCHAR NOT NULL
);
Co robi nasz skrypt? Pierwsze dwie linie usuwają tabele, jeśli są obecne, w celu ich odtworzenia. Trzecia linia tworzy sekwencję, która będzie używana do tworzenia unikalnych wpisów id w naszej bazie danych. Następnie tworzymy dwie tabele: dla użytkowników i dla pytań. Użytkownik będzie miał unikalny identyfikator, identyfikator czatu telegramowego, nazwę, liczbę punktów (bieżącą i maksymalną), a także aktualny status bota. Pytania będą miały również unikalny identyfikator, a także pola odpowiadające za opcje pytań i odpowiedzi. Powstały skrypt możemy wykonać, klikając go prawym przyciskiem myszy i wybierając „Wykonaj skrypt SQL”. Szczególną uwagę należy zwrócić na pozycję „Interfejs Cmd-Line” - tutaj będziemy potrzebować świeżo zainstalowanego PostgreSQL. Konfigurując to pole, wybierz „Nowy interfejs Cmd-Line” i podaj ścieżkę do pliku psql.exe. W rezultacie ustawienia powinny wyglądać mniej więcej tak: Tworzenie bota telegramu przy użyciu Spring Boot Pt.2: Quiz Bot - 4Wykonujemy skrypt i jeśli nigdzie nie popełniliśmy błędu, efekt naszej pracy będzie następujący: Tworzenie bota telegramu przy użyciu Spring Boot Pt.2: Quiz Bot - 8<h3>Utwórz model</h3>Teraz czas aby powrócić do pisania kodu Java. Aby skrócić artykuł, pominę opis adnotacji użytych do napisania zajęć, abyście mogli się z nimi zapoznać. Stwórzmy pakiet modelowy, w którym będziemy mieli trzy klasy:
  • AbstractBaseEntity to klasa opisująca dowolny obiekt, który może mieć identyfikator (ta klasa stanowi duże uproszczenie tego, co możesz zobaczyć na stażu):
    package com.whiskels.telegram.model;
    
    import lombok.Getter;
    import lombok.Setter;
    
    import javax.persistence.*;
    // Аннотация, которая говорит нам, что это суперкласс для всех Entity
    // https://vladmihalcea.com/how-to-inherit-properties-from-a-base-class-entity-using-mappedsuperclass-with-jpa-and-hibernate/
    @MappedSuperclass
    // http://stackoverflow.com/questions/594597/hibernate-annotations-which-is-better-field-or-property-access
    @Access(AccessType.FIELD)
    
    // Аннотации Lombok для автогенерации сеттеров и геттеров на все поля
    @Getter
    @Setter
    public abstract class AbstractBaseEntity {
    
    // Аннотации, описывающие механизм генерации id - разберитесь в dokumentации каждой!
        @Id
        @SequenceGenerator(name = "global_seq", sequenceName = "global_seq", allocationSize = 1, initialValue = START_SEQ)
        @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "global_seq")
    //  See https://hibernate.atlassian.net/browse/HHH-3718 and https://hibernate.atlassian.net/browse/HHH-12034
    //  Proxy initialization when accessing its identifier managed now by JPA_PROXY_COMPLIANCE setting
        protected Integer id;
    
        protected AbstractBaseEntity() {
        }
    }
  • Użytkownik :
    package com.whiskels.telegram.model;
    
    import com.whiskels.telegram.bot.State;
    import lombok.AllArgsConstructor;
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.Setter;
    import org.hibernate.annotations.BatchSize;
    
    import javax.persistence.*;
    import javax.validation.constraints.NotBlank;
    import javax.validation.constraints.NotNull;
    import java.util.Set;
    
    import static javax.persistence.FetchType.EAGER;
    
    @Entity
    @Table(name = "users", uniqueConstraints = {@UniqueConstraint(columnNames = "chat_id", name = "users_unique_chatid_idx")})
    @Getter
    @Setter
    @NoArgsConstructor
    @AllArgsConstructor
    public class User extends AbstractBaseEntity {
        @Column(name = "chat_id", unique = true, nullable = false)
        @NotNull
        private Integer chatId;
    
        @Column(name = "name", unique = true, nullable = false)
        @NotBlank
        private String name;
    
        @Column(name = "score", nullable = false)
        @NotNull
        private Integer score;
    
        @Column(name = "high_score", nullable = false)
        @NotNull
        private Integer highScore;
    
        @Column(name = "bot_state", nullable = false)
        @NotBlank
        private State botState;
    
    // Конструктор нужен для создания нового пользователя (а может и нет? :))
        public User(int chatId) {
            this.chatId = chatId;
            this.name = String.valueOf(chatId);
            this.score = 0;
            this.highScore = 0;
            this.botState = State.START;
        }
    }
  • Klasa pytań :
    package com.whiskels.telegram.model;
    
    import lombok.AllArgsConstructor;
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.Setter;
    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.Table;
    import javax.validation.constraints.NotBlank;
    
    @Entity
    @Table(name = "java_quiz")
    @Getter
    @Setter
    @NoArgsConstructor
    @AllArgsConstructor
    public class Question extends AbstractBaseEntity {
        @Column(name = "question", nullable = false)
        @NotBlank
        private String question;
    
        @Column(name = "answer_correct", nullable = false)
        @NotBlank
        private String correctAnswer;
    
        @Column(name = "option2", nullable = false)
        @NotBlank
        private String optionOne;
    
        @Column(name = "option1", nullable = false)
        @NotBlank
        private String optionTwo;
    
        @Column(name = "option3", nullable = false)
        @NotBlank
        private String optionThree;
    
        @Override
        public String toString() {
            return "Question{" +
                    "question='" + question + '\'' +
                    ", correctAnswer='" + correctAnswer + '\'' +
                    ", optionOne='" + optionOne + '\'' +
                    ", optionTwo='" + optionTwo + '\'' +
                    ", optionThree='" + optionThree + '\'' +
                    '}';
        }
    }
<h3>Tworzenie repozytoriów</h3>Teraz napiszmy repozytoria Spring Data Jpa. Tworzymy pakiet repozytorium, które będzie miało dwa interfejsy : JpaUserRepository, JpaQuestionRepository. Odziedziczą po JpaRepository, interfejsie Spring Data, który pozwala nam praktycznie tworzyć magię. Aby zrozumieć ich pracę, polecam obejrzeć film Jewgienija Borysowa . Klasy będą bardzo małe:
  • Repozytorium użytkowników Jpa:
    package com.whiskels.telegram.repository;
    
    import com.whiskels.telegram.model.User;
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.stereotype.Repository;
    import org.springframework.transaction.annotation.Transactional;
    
    import java.util.Optional;
    
    @Repository
    @Transactional(readOnly = true)
    public interface JpaUserRepository extends JpaRepository<user, integer=""> {
    // По названию метода Spring сам поймет, что мы хотим получить пользователя по переданному chatId
        Optional<user> getByChatId(int chatId);
    }
    </user></user,>
  • Repozytorium JpaQuestion:
    package com.whiskels.telegram.repository;
    
    import com.whiskels.telegram.model.Question;
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.data.jpa.repository.Query;
    
    @Repository
    @Transactional(readOnly = true)
    public interface JpaQuestionRepository extends JpaRepository<question, integer=""> {
    // А здесь мы написали SQL Query, которая будет выбирать 1 случайный вопрос из таблицы вопросов
        @Query(nativeQuery = true, value = "SELECT *  FROM java_quiz ORDER BY random() LIMIT 1")
        Question getRandomQuestion();
    }
    </question,>
<h3>Dodaj funkcjonalność do bota</h3>W klasie User mamy pole jeszcze nie utworzonej klasy State , które poinformuje nas na jakim etapie pracy z botem aktualnie znajduje się użytkownik. Utwórzmy go w pakiecie /bot:
package com.whiskels.telegram.bot;

public enum State {
    NONE,
    START,
    ENTER_NAME,
    PLAYING_QUIZ,
}
Następnie utworzymy pakiet bot/handler, w którym zadeklarujemy interfejs modułu obsługi:
package com.whiskels.telegram.bot.handler;

import com.whiskels.telegram.bot.State;
import com.whiskels.telegram.model.User;
import org.telegram.telegrambots.meta.api.methods.PartialBotApiMethod;

import java.io.Serializable;
import java.util.List;

public interface Handler {

// основной метод, который будет обрабатывать действия пользователя
    List<partialbotapimethod<? extends="" serializable="">> handle(User user, String message);
// метод, который позволяет узнать, можем ли мы обработать текущий State у пользователя
    State operatedBotState();
// метод, который позволяет узнать, Jakие команды CallBackQuery мы можем обработать в этом классе
    List<string> operatedCallBackQuery();
}

</string></partialbotapimethod<?>
Handlery utworzymy nieco później, ale na razie oddelegujmy przetwarzanie zdarzeń do nowej klasy UpdateReceiver , którą utworzymy w katalogu głównym pakietu bota: UWAGA! Tu i dalej będą metody, które będą wyświetlane jako Lista> handle(args); w rzeczywistości wyglądają tak, ale formater kodu je zepsuł:Tworzenie bota telegramu przy użyciu Spring Boot Pt.2: Quiz Bot - 6
package com.whiskels.telegram.bot;

import com.whiskels.telegram.bot.handler.Handler;
import com.whiskels.telegram.model.User;
import com.whiskels.telegram.repository.JpaUserRepository;
import org.springframework.stereotype.Component;
import org.telegram.telegrambots.meta.api.methods.PartialBotApiMethod;
import org.telegram.telegrambots.meta.api.objects.CallbackQuery;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.Update;

import java.io.Serializable;
import java.util.Collections;
import java.util.List;

@Component
public class UpdateReceiver {
    // Храним доступные хендлеры в списке (подсмотрел у Miroha)
    private final List<handler> handlers;
    // Имеем доступ в базу пользователей
    private final JpaUserRepository userRepository;

    public UpdateReceiver(List<handler> handlers, JpaUserRepository userRepository) {
        this.handlers = handlers;
        this.userRepository = userRepository;
    }

    // Обрабатываем полученный Update
    public List<partialbotapimethod<? extends="" serializable="">> handle(Update update) {
        // try-catch, чтобы при несуществующей команде просто возвращать пустой список
        try {
            // Проверяем, если Update - сообщение с текстом
            if (isMessageWithText(update)) {
                // Получаем Message из Update
                final Message message = update.getMessage();
                // Получаем айди чата с пользователем
                final int chatId = message.getFrom().getId();

                // Просим у репозитория пользователя. Если такого пользователя нет - создаем нового и возвращаем его.
                // Как раз на случай нового пользователя мы и сделали конструктор с одним параметром в классе User
                final User user = userRepository.getByChatId(chatId)
                        .orElseGet(() -> userRepository.save(new User(chatId)));
                // Ищем нужный обработчик и возвращаем результат его работы
                return getHandlerByState(user.getBotState()).handle(user, message.getText());

            } else if (update.hasCallbackQuery()) {
                final CallbackQuery callbackQuery = update.getCallbackQuery();
                final int chatId = callbackQuery.getFrom().getId();
                final User user = userRepository.getByChatId(chatId)
                        .orElseGet(() -> userRepository.save(new User(chatId)));

                return getHandlerByCallBackQuery(callbackQuery.getData()).handle(user, callbackQuery.getData());
            }

            throw new UnsupportedOperationException();
        } catch (UnsupportedOperationException e) {
            return Collections.emptyList();
        }
    }

    private Handler getHandlerByState(State state) {
        return handlers.stream()
                .filter(h -> h.operatedBotState() != null)
                .filter(h -> h.operatedBotState().equals(state))
                .findAny()
                .orElseThrow(UnsupportedOperationException::new);
    }

    private Handler getHandlerByCallBackQuery(String query) {
        return handlers.stream()
                .filter(h -> h.operatedCallBackQuery().stream()
                        .anyMatch(query::startsWith))
                .findAny()
                .orElseThrow(UnsupportedOperationException::new);
    }

    private boolean isMessageWithText(Update update) {
        return !update.hasCallbackQuery() && update.hasMessage() && update.getMessage().hasText();
    }
}

</partialbotapimethod<?></handler></handler>
I delegujemy mu przetwarzanie w klasie Bot:
package com.whiskels.telegram.bot;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.meta.api.methods.PartialBotApiMethod;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;

import java.io.Serializable;
import java.util.List;

@Slf4j
@Component
public class Bot extends TelegramLongPollingBot {
    @Value("${bot.name}")
    @Getter
    private String botUsername;

    @Value("${bot.token}")
    @Getter
    private String botToken;

    private final UpdateReceiver updateReceiver;

    public Bot(UpdateReceiver updateReceiver) {
        this.updateReceiver = updateReceiver;
    }

    @Override
    public void onUpdateReceived(Update update) {
        List<partialbotapimethod<? extends="" serializable="">> messagesToSend = updateReceiver.handle(update);

        if (messagesToSend != null && !messagesToSend.isEmpty()) {
            messagesToSend.forEach(response -> {
                if (response instanceof SendMessage) {
                    executeWithExceptionCheck((SendMessage) response);
                }
            });
        }
    }

    public void executeWithExceptionCheck(SendMessage sendMessage) {
        try {
            execute(sendMessage);
        } catch (TelegramApiException e) {
            log.error("oops");
        }
    }
}

</partialbotapimethod<?>
Teraz nasz bot deleguje przetwarzanie zdarzeń do klasy UpdateReceiver , ale nie mamy jeszcze żadnych procedur obsługi. Stwórzmy je! ZASTRZEŻENIE! Bardzo chciałem podzielić się możliwościami napisania takiego bota, więc dalszy kod (jak w zasadzie kod UpdateReceiver) można bardzo dobrze refaktorować przy użyciu różnych wzorców. Ale się uczymy i naszym celem jest minimalnie wykonalny bot, więc w ramach kolejnej pracy domowej możesz refaktoryzować wszystko, co widziałeś :) Utwórz pakiet util, a w nim - klasę TelegramUtil :
package com.whiskels.telegram.util;

import com.whiskels.telegram.model.User;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.InlineKeyboardButton;

public class TelegramUtil {
    public static SendMessage createMessageTemplate(User user) {
        return createMessageTemplate(String.valueOf(user.getChatId()));
    }

    // Создаем шаблон SendMessage с включенным Markdown
    public static SendMessage createMessageTemplate(String chatId) {
        return new SendMessage()
                .setChatId(chatId)
                .enableMarkdown(true);
    }

    // Создаем кнопку
    public static InlineKeyboardButton createInlineKeyboardButton(String text, String command) {
        return new InlineKeyboardButton()
                .setText(text)
                .setCallbackData(command);
    }
}
Napiszemy cztery programy obsługi: HelpHandler, QuizHandler, RegistrationHandler, StartHandler. StartHandler:
package com.whiskels.telegram.bot.handler;

import com.whiskels.telegram.bot.State;
import com.whiskels.telegram.model.User;
import com.whiskels.telegram.repository.JpaUserRepository;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.telegram.telegrambots.meta.api.methods.PartialBotApiMethod;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;

import java.io.Serializable;
import java.util.Collections;
import java.util.List;

import static com.whiskels.telegram.util.TelegramUtil.createMessageTemplate;

@Component
public class StartHandler implements Handler {
    @Value("${bot.name}")
    private String botUsername;

    private final JpaUserRepository userRepository;

    public StartHandler(JpaUserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public List<partialbotapimethod<? extends="" serializable="">> handle(User user, String message) {
        // Приветствуем пользователя
        SendMessage welcomeMessage = createMessageTemplate(user)
                .setText(String.format(
                        "Hola! I'm *%s*%nI am here to help you learn Java", botUsername
                ));
        // Просим назваться
        SendMessage registrationMessage = createMessageTemplate(user)
                .setText("In order to start our journey tell me your name");
        // Меняем пользователю статус на - "ожидание ввода имени"
        user.setBotState(State.ENTER_NAME);
        userRepository.save(user);

        return List.of(welcomeMessage, registrationMessage);
    }

    @Override
    public State operatedBotState() {
        return State.START;
    }

    @Override
    public List<string> operatedCallBackQuery() {
        return Collections.emptyList();
    }
}

</string></partialbotapimethod<?>
Osoba zajmująca się rejestracją:
package com.whiskels.telegram.bot.handler;

import com.whiskels.telegram.bot.State;
import com.whiskels.telegram.model.User;
import com.whiskels.telegram.repository.JpaUserRepository;
import org.springframework.stereotype.Component;
import org.telegram.telegrambots.meta.api.methods.PartialBotApiMethod;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.InlineKeyboardMarkup;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.InlineKeyboardButton;

import java.io.Serializable;
import java.util.List;

import static com.whiskels.telegram.bot.handler.QuizHandler.QUIZ_START;
import static com.whiskels.telegram.util.TelegramUtil.createInlineKeyboardButton;
import static com.whiskels.telegram.util.TelegramUtil.createMessageTemplate;

@Component
public class RegistrationHandler implements Handler {
    //Храним поддерживаемые CallBackQuery в виде констант
    public static final String NAME_ACCEPT = "/enter_name_accept";
    public static final String NAME_CHANGE = "/enter_name";
    public static final String NAME_CHANGE_CANCEL = "/enter_name_cancel";

    private final JpaUserRepository userRepository;

    public RegistrationHandler(JpaUserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public List<partialbotapimethod<? extends="" serializable="">> handle(User user, String message) {
        // Проверяем тип полученного события
        if (message.equalsIgnoreCase(NAME_ACCEPT) || message.equalsIgnoreCase(NAME_CHANGE_CANCEL)) {
            return accept(user);
        } else if (message.equalsIgnoreCase(NAME_CHANGE)) {
            return changeName(user);
        }
        return checkName(user, message);

    }

    private List<partialbotapimethod<? extends="" serializable="">> accept(User user) {
        // Если пользователь принял Nazwa - меняем статус и сохраняем
        user.setBotState(State.NONE);
        userRepository.save(user);

        // Создаем кнопку для начала игры
        InlineKeyboardMarkup inlineKeyboardMarkup = new InlineKeyboardMarkup();

        List<inlinekeyboardbutton> inlineKeyboardButtonsRowOne = List.of(
                createInlineKeyboardButton("Start quiz", QUIZ_START));

        inlineKeyboardMarkup.setKeyboard(List.of(inlineKeyboardButtonsRowOne));

        return List.of(createMessageTemplate(user).setText(String.format(
                "Your name is saved as: %s", user.getName()))
                .setReplyMarkup(inlineKeyboardMarkup));
    }

    private List<partialbotapimethod<? extends="" serializable="">> checkName(User user, String message) {
        // При проверке имени мы превентивно сохраняем пользователю новое Nazwa в базе
        // идея для рефакторинга - добавить временное хранение имени
        user.setName(message);
        userRepository.save(user);

        // Czyn кнопку для применения изменений
        InlineKeyboardMarkup inlineKeyboardMarkup = new InlineKeyboardMarkup();

        List<inlinekeyboardbutton> inlineKeyboardButtonsRowOne = List.of(
                createInlineKeyboardButton("Accept", NAME_ACCEPT));

        inlineKeyboardMarkup.setKeyboard(List.of(inlineKeyboardButtonsRowOne));

        return List.of(createMessageTemplate(user)
                .setText(String.format("You have entered: %s%nIf this is correct - press the button", user.getName()))
                .setReplyMarkup(inlineKeyboardMarkup));
    }

    private List<partialbotapimethod<? extends="" serializable="">> changeName(User user) {
        // При wniosekе изменения имени мы меняем State
        user.setBotState(State.ENTER_NAME);
        userRepository.save(user);

        // Создаем кнопку для отмены операции
        InlineKeyboardMarkup inlineKeyboardMarkup = new InlineKeyboardMarkup();

        List<inlinekeyboardbutton> inlineKeyboardButtonsRowOne = List.of(
                createInlineKeyboardButton("Cancel", NAME_CHANGE_CANCEL));

        inlineKeyboardMarkup.setKeyboard(List.of(inlineKeyboardButtonsRowOne));

        return List.of(createMessageTemplate(user).setText(String.format(
                "Your current name is: %s%nEnter new name or press the button to continue", user.getName()))
                .setReplyMarkup(inlineKeyboardMarkup));
    }

    @Override
    public State operatedBotState() {
        return State.ENTER_NAME;
    }

    @Override
    public List<string> operatedCallBackQuery() {
        return List.of(NAME_ACCEPT, NAME_CHANGE, NAME_CHANGE_CANCEL);
    }
}

</string></inlinekeyboardbutton></partialbotapimethod<?></inlinekeyboardbutton></partialbotapimethod<?></inlinekeyboardbutton></partialbotapimethod<?></partialbotapimethod<?>
Osoba zajmująca się pomocą:
package com.whiskels.telegram.bot.handler;

import com.whiskels.telegram.bot.State;
import com.whiskels.telegram.model.User;
import org.springframework.stereotype.Component;
import org.telegram.telegrambots.meta.api.methods.PartialBotApiMethod;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.InlineKeyboardMarkup;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.InlineKeyboardButton;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static com.whiskels.telegram.bot.handler.RegistrationHandler.NAME_CHANGE;
import static com.whiskels.telegram.util.TelegramUtil.createInlineKeyboardButton;
import static com.whiskels.telegram.util.TelegramUtil.createMessageTemplate;

@Component
public class HelpHandler implements Handler {

    @Override
    public List<partialbotapimethod<? extends="" serializable="">> handle(User user, String message) {
        // Создаем кнопку для смены имени
        InlineKeyboardMarkup inlineKeyboardMarkup = new InlineKeyboardMarkup();

        List<inlinekeyboardbutton> inlineKeyboardButtonsRowOne = List.of(
                createInlineKeyboardButton("Change name", NAME_CHANGE));

        inlineKeyboardMarkup.setKeyboard(List.of(inlineKeyboardButtonsRowOne));

        return List.of(createMessageTemplate(user).setText(String.format("" +
                "You've asked for help %s? Here it comes!", user.getName()))
        .setReplyMarkup(inlineKeyboardMarkup));

    }

    @Override
    public State operatedBotState() {
        return State.NONE;
    }

    @Override
    public List<string> operatedCallBackQuery() {
        return Collections.emptyList();
    }
}

</string></inlinekeyboardbutton></partialbotapimethod<?>
QuizHandler (najgorszy
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION