JavaRush /Java-Blog /Random-DE /Erstellen eines Telegram-Bots mit Spring Boot Teil 2: Qui...
Whiskels
Level 41
Москва

Erstellen eines Telegram-Bots mit Spring Boot Teil 2: Quiz-Bot

Veröffentlicht in der Gruppe Random-DE
TEIL 1 Aloha! Im vorherigen Artikel haben wir einen einfachen Bot erstellt, der uns bei jeder Veranstaltung willkommen heißt. Wir haben bereits Tausende Codezeilen geschrieben und es ist an der Zeit, unserem Bot komplexere Funktionen hinzuzufügen. Heute werden wir versuchen, einen einfachen Bot zu schreiben, damit wir in unserer Freizeit vor Vorstellungsgesprächen unsere Kenntnisse über Java Core verfeinern können (überraschenderweise habe ich keinen einzigen funktionierenden Bot dieser Art gefunden). Dazu werden wir Folgendes tun:
  • eine externe Postgres-Datenbank mit Heroku verbinden;
  • Schreiben wir unsere ersten Skripte, um die Datenbank zu initialisieren und zu füllen;
  • Lassen Sie uns Spring Boot Data JPA verbinden, um mit der Datenbank zu arbeiten.
  • Wir implementieren verschiedene Szenarien des Bot-Verhaltens.
Wenn das für Sie interessant ist und Sie nach der Lektüre des Artikels keine Lust haben, mit faulen Tomaten wegzuwerfen, dann setzen Sie einen Stern in mein Repository , ich werde mich freuen! Wenn Sie Fragen haben, werden wir diese in den Kommentaren besprechen. Das bekommen wir am Ende: Erstellen eines Telegram-Bots mit Spring Boot Teil 2: Quiz Bot – 1Erstellen eines Telegram-Bots mit Spring Boot Teil 2: Quiz Bot – 2Erstellen eines Telegram-Bots mit Spring Boot Teil 2: Quiz Bot – 3<h2>Also los geht's!</h2><h3>Eine Datenbank auf Heroku erstellen</h3>Beginnen wir mit der Erstellung unserer ersten externen Datenbank. Für die lokale Arbeit empfehle ich, pgAdmin auszuprobieren . Aber ich möchte Sie davon leiten lassen, dass Sie den Bot in Zukunft auf Heroku bereitstellen, damit er nicht von Ihrem lokalen Computer abhängt, und machen wir uns dazu mit diesem Dienst vertraut. Verfahren:
  • auf Heroku registrieren ;
  • Gehen Sie zu unserem Dashboard -> Neu -> Neue App erstellen und erstellen Sie eine neue Anwendung.
  • Wir gehen in die neu erstellte Anwendung, sind von den vielen Schaltflächen eingeschüchtert, konzentrieren uns aber auf das Panel „Installierte Add-Ons“ – daneben befindet sich die Schaltfläche „Add-Ons konfigurieren“, wir klicken darauf;
  • Geben Sie „Heroku Postgres“ in die Suche ein, wählen Sie den Plan „Hobby Dev – Free“ -> Bestellformular absenden;
  • Öffnen Sie die neu erhaltene Datenbank -> Einstellungen -> Anmeldeinformationen anzeigen. Diese Registerkarte enthält unsere Schlüssel für den Zugriff auf die Datenbank. Wir merken uns ihren Standort – wir benötigen sie, um die Datenbank zu verbinden, wie DataSource in IDEA.
<h3>Abhängigkeiten zu pom.xml hinzufügen</h3>Im Rahmen der Arbeit an unserem Bot werden wir die folgenden Abhängigkeiten zu unserem Pom hinzufügen: Lombok, Spring Boot Data JPA, PostgreSQL. Stoppen! Was ist das alles und warum fügen wir es hinzu?
  • Lombok ist eine Bibliothek, dank der wir die Menge an unterschiedlichem Code erheblich reduzieren können. Damit können wir automatisch Konstruktoren, Setter, Getter und vieles mehr erstellen.
  • Spring Data JPA ist ein Framework für die Arbeit mit Datenbanken (auch wenn es zu einfach klingt). Die Beschreibung der Funktionen von Spring Data JPA würde einer Reihe von Artikeln gleichkommen, und die von uns angegebene Abhängigkeit beinhaltet auch Hibernate und vieles mehr. Lassen Sie uns also die Details überspringen und einfach versuchen, heute etwas mit Spring JPA zu schreiben.
  • PostgreSQL – wir rufen die Bibliothek ab, um einen Treiber zu erhalten, der mit unserer Datenbank funktioniert.
Unsere pom.xml sieht zunächst so aus: Eigenschaften: Erstellen eines Telegram-Bots mit Spring Boot Teil 2: Quiz Bot – 1Abhängigkeiten: Erstellen eines Telegram-Bots mit Spring Boot Teil 2: Quiz Bot – 2Wenn Sie den vorherigen Artikel nicht gelesen haben, beachten Sie bitte, dass wir hier neue Abhängigkeiten hinzufügen, sodass dies nicht die vollständige pom.xml-Struktur ist. Vergessen Sie nicht, diese Abhängigkeiten in unser Projekt zu laden (z. B. indem Sie zum Fenster „Maven -> Alle Maven-Projekte erneut importieren“ gehen).<h3>Verbinden der Datenbank in IDEA</h3>Wenn Sie IDEA Community Edition verwenden, können Sie dies tun Aktivieren Sie die Registerkarte „Datenquelle“ wie folgt . Nachdem wir das Plugin hinzugefügt haben, müssen wir die DataSource konfigurieren. Aktivieren Sie dazu zunächst die Plugin-Anzeige: Ansicht -> Werkzeugfenster -> DB-Browser. Klicken Sie im sich öffnenden Fenster auf das grüne Plus (neue Verbindung) -> PostgreSQL. Hier benötigen wir Zugangsdaten, die wir bereits auf Heroku gesehen haben. Füllen Sie das Fenster aus: Erstellen eines Telegram-Bots mit Spring Boot Teil 2: Quiz Bot – 3Und klicken Sie auf „Verbindung testen“. Wenn alles richtig gemacht wurde, erscheint ein Popup-Fenster, das anzeigt, dass die Verbindung zur Datenbank erfolgreich war. Speichern Sie unsere Datenquelle.<h3>Erstellen Sie Tabellen in der Datenbank</h3>Jetzt erstellen wir die Tabellen, mit denen wir arbeiten werden. Zuerst installieren wir PostgreSQL . Erstellen Sie nach der Installation die Datei initDB.sql im Ordner 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
);
Was macht unser Skript? Die ersten beiden Zeilen löschen Tabellen, falls vorhanden, um sie neu zu erstellen. Die dritte Zeile erstellt eine Sequenz, die zum Erstellen eindeutiger ID-Einträge in unserer Datenbank verwendet wird. Als nächstes erstellen wir zwei Tabellen: für Benutzer und für Fragen. Der Benutzer erhält eine eindeutige ID, eine Telegram-Chat-ID, einen Namen, die Anzahl der Punkte (aktuell und maximal) sowie den aktuellen Status des Bots. Fragen haben außerdem eine eindeutige ID sowie Felder, die für die Frage- und Antwortoptionen dafür verantwortlich sind. Wir können das resultierende Skript ausführen, indem wir mit der rechten Maustaste darauf klicken und „SQL-Skript ausführen“ auswählen. Besonderes Augenmerk sollte auf den Punkt „Cmd-Line-Schnittstelle“ gelegt werden – hier benötigen wir frisch installiertes PostgreSQL. Wählen Sie bei der Konfiguration dieses Feldes „Neue Cmd-Line-Schnittstelle“ und geben Sie den Pfad zu psql.exe an. Als Ergebnis sollten die Einstellungen etwa so aussehen: Erstellen eines Telegram-Bots mit Spring Boot Teil 2: Quiz Bot – 4Wir führen das Skript aus und wenn wir nirgendwo einen Fehler gemacht haben, wird das Ergebnis unserer Arbeit wie folgt aussehen: Erstellen eines Telegram-Bots mit Spring Boot Teil 2: Quiz Bot – 8<h3>Modell erstellen</h3>Jetzt ist es soweit um zum Schreiben von Java-Code zurückzukehren. Um den Artikel zu kürzen, werde ich die Beschreibung der Anmerkungen weglassen, die zum Schreiben der Klassen verwendet wurden, damit Sie sich mit ihnen vertraut machen können. Lassen Sie uns ein Modellpaket erstellen, in dem wir drei Klassen haben werden:
  • AbstractBaseEntity ist eine Klasse, die jedes Objekt beschreibt, das eine ID haben kann (diese Klasse ist eine starke Vereinfachung dessen, was Sie in einem Praktikum sehen könnten):
    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 - разберитесь в dokumentierenации каждой!
        @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() {
        }
    }
  • Benutzer :
    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;
        }
    }
  • Frageklasse : _
    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>Repositories erstellen</h3>Jetzt schreiben wir die Spring Data Jpa-Repositories. Wir erstellen ein Repository-Paket, das zwei Schnittstellen hat : JpaUserRepository, JpaQuestionRepository. Sie erben von JpaRepository, einer Spring Data-Schnittstelle, die es uns ermöglicht, praktisch Magie zu erschaffen. Um ihre Arbeit zu verstehen, empfehle ich, das Video von Evgeny Borisov anzusehen . Die Klassen werden sehr klein sein:
  • JpaUserRepository:
    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,>
  • JpaQuestionRepository:
    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>Funktionalität zum Bot hinzufügen</h3>In der User- Klasse haben wir ein Feld der noch nicht erstellten State- Klasse , das uns sagt, in welcher Phase der Arbeit mit dem Bot sich der Benutzer gerade befindet. Erstellen wir es im /bot-Paket:
package com.whiskels.telegram.bot;

public enum State {
    NONE,
    START,
    ENTER_NAME,
    PLAYING_QUIZ,
}
Als nächstes erstellen wir ein Bot/Handler-Paket, in dem wir die Handler-Schnittstelle deklarieren:
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();
// метод, который позволяет узнать, Wieие команды CallBackQuery мы можем обработать в этом классе
    List<string> operatedCallBackQuery();
}

</string></partialbotapimethod<?>
Wir werden die Handler etwas später erstellen, aber zunächst delegieren wir die Ereignisverarbeitung an die neue UpdateReceiver- Klasse , die wir im Stammverzeichnis des Bot-Pakets erstellen werden: ACHTUNG! Hier und darüber hinaus wird es Methoden geben, die als List> handle(args); In Wirklichkeit sehen sie so aus, aber der Codeformatierer hat sie kaputt gemacht:Erstellen eines Telegram-Bots mit Spring Boot Teil 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>
Und wir delegieren die Verarbeitung in der Bot-Klasse daran:
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<?>
Jetzt delegiert unser Bot die Ereignisverarbeitung an die UpdateReceiver- Klasse , aber wir haben noch keine Handler. Lasst uns sie erschaffen! HAFTUNGSAUSSCHLUSS! Ich wollte unbedingt die Möglichkeiten teilen, einen solchen Bot zu schreiben, damit weiterer Code (wie im Prinzip der UpdateReceiver-Code) mithilfe verschiedener Muster sehr gut umgestaltet werden kann. Aber wir lernen und unser Ziel ist ein minimal lebensfähiger Bot. Als weitere Hausaufgabe können Sie also alles umgestalten, was Sie gesehen haben :) Erstellen Sie ein Util-Paket und darin die TelegramUtil- Klasse :
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);
    }
}
Wir werden vier Handler schreiben: 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<?>
RegistrationHandler:
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) {
        // Если пользователь принял Name - меняем статус и сохраняем
        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) {
        // При проверке имени мы превентивно сохраняем пользователю новое Name в базе
        // идея для рефакторинга - добавить временное хранение имени
        user.setName(message);
        userRepository.save(user);

        // Tun кнопку для применения изменений
        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) {
        // При Anfrageе изменения имени мы меняем 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<?>
Hilfehandler:
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 (das Schlimmste
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION