JavaRush /Blog Java /Random-FR /Création d'un bot de télégramme à l'aide de Spring Boot P...
Whiskels
Niveau 41
Москва

Création d'un bot de télégramme à l'aide de Spring Boot Pt.2 : Quiz Bot

Publié dans le groupe Random-FR
PARTIE 1 Aloha! Dans l’article précédent, nous avons créé un simple bot qui nous accueillait à n’importe quel événement. Nous avons déjà écrit des milliers de lignes de code et il est temps d'ajouter des fonctionnalités plus complexes à notre bot. Aujourd'hui, nous allons essayer d'écrire un bot simple afin que pendant notre temps libre, nous puissions perfectionner nos connaissances de Java Core avant les entretiens (étonnamment, je n'ai pas trouvé un seul bot fonctionnel de ce type). Pour ce faire, nous procéderons comme suit :
  • connecter une base de données Postgres externe à Heroku ;
  • Écrivons nos premiers scripts pour initialiser et remplir la base de données ;
  • connectons Spring Boot Data JPA pour travailler avec la base de données ;
  • Nous mettons en œuvre différents scénarios de comportement des robots.
Si cela vous intéresse et qu'après avoir lu l'article vous ne voulez pas jeter de tomates pourries, alors mettez une étoile dans mon référentiel , j'en serai ravi ! Si vous avez des questions, nous en discuterons dans les commentaires. Voici ce que nous obtiendrons au final : Création d'un bot de télégramme à l'aide de Spring Boot Pt.2 : Quiz Bot - 1Création d'un bot de télégramme à l'aide de Spring Boot Pt.2 : Quiz Bot - 2Création d'un bot de télégramme à l'aide de Spring Boot Pt.2 : Quiz Bot - 3<h2>Alors c'est parti !</h2><h3>Création d'une base de données sur Heroku</h3>Commençons par créer notre première base de données externe. Pour le travail local, je recommande de consulter pgAdmin . Mais je veux que vous soyez guidé par le fait qu'à l'avenir vous déployerez le bot sur Heroku afin qu'il ne dépende pas de votre machine locale, et pour cela faisons connaissance avec ce service. Procédure:
  • inscrivez-vous sur Heroku ;
  • Accédez à notre tableau de bord -> Nouveau -> Créer une nouvelle application et créez une nouvelle application ;
  • Nous entrons dans l'application nouvellement créée, nous sommes intimidés par les nombreux boutons, mais nous nous concentrons sur le panneau « Modules complémentaires installés » - à côté se trouve le bouton Configurer les modules complémentaires, nous cliquons dessus ;
  • Entrez « Heroku Postgres » dans la recherche, sélectionnez le plan « Hobby Dev - Free » -> Soumettre le formulaire de commande ;
  • Ouvrez la base de données nouvellement obtenue -> Paramètres -> Afficher les informations d'identification. Cet onglet contiendra nos clés d'accès à la base de données. Nous nous souvenons de leur emplacement - nous en aurons besoin pour connecter la base de données, comme DataSource dans IDEA.
<h3>Ajouter des dépendances à pom.xml</h3>Dans le cadre du travail sur notre bot, nous ajouterons les dépendances suivantes à notre pom : Lombok, Spring Boot Data JPA, PostgreSQL. Arrêt! Qu’est-ce que tout cela et pourquoi l’ajoutons-nous ?
  • Lombok est une bibliothèque grâce à laquelle nous réduirons considérablement la quantité de code différent. Avec lui, nous pouvons créer automatiquement des constructeurs, des setters, des getters et bien plus encore.
  • Spring Data JPA est un framework pour travailler avec des bases de données (même si cela semble trop simple). La description des capacités de Spring Data JPA équivaudrait à une série d'articles, et la dépendance que nous avons spécifiée implique également Hibernate et bien plus encore, ignorons donc les détails et essayons simplement d'écrire quelque chose en utilisant Spring JPA aujourd'hui.
  • PostgreSQL - nous extrayons la bibliothèque pour obtenir un pilote qui fonctionnera avec notre base de données.
Notre pom.xml commence à ressembler à ceci : Propriétés : Création d'un bot de télégramme à l'aide de Spring Boot Pt.2 : Quiz Bot - 1Dépendances : Création d'un bot de télégramme à l'aide de Spring Boot Pt.2 : Quiz Bot - 2Si vous n'avez pas lu l'article précédent, veuillez noter que nous ajoutons de nouvelles dépendances ici, ce n'est donc pas la structure complète de pom.xml. N'oubliez pas de charger ces dépendances dans notre projet (par exemple, en allant dans la fenêtre Maven -> Réimporter tous les projets Maven).<h3>Connexion de la base de données dans IDEA</h3>Si vous utilisez IDEA Community Edition, vous pouvez activez l'onglet DataSource comme suit . Après avoir ajouté le plugin, nous devons configurer le DataSource. Pour ce faire, activez d'abord l'affichage du plugin : View -> Tool Windows -> DB Browser. Dans la fenêtre qui s'ouvre, cliquez sur le plus vert (nouvelle connexion) -> PostgreSQL. Ici, nous aurons besoin d'informations d'identification, que nous avons déjà vues sur Heroku. Remplissez la fenêtre : Création d'un bot de télégramme à l'aide de Spring Boot Pt.2 : Quiz Bot - 3Et cliquez sur « Tester la connexion ». Si tout est fait correctement, une fenêtre pop-up apparaîtra indiquant que la connexion à la base de données a réussi. Enregistrez notre source de données.<h3>Créez des tables dans la base de données</h3>Créons maintenant les tables avec lesquelles nous allons travailler. Tout d’abord, installons PostgreSQL . Après l'installation, créez le fichier initDB.sql dans le dossier 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
);
Que fait notre script ? Les deux premières lignes effacent les tableaux, s'ils sont présents, pour les recréer. La troisième ligne crée une séquence qui sera utilisée pour créer des entrées d'identifiant uniques dans notre base de données. Ensuite, nous créons deux tableaux : pour les utilisateurs et pour les questions. L'utilisateur aura un identifiant unique, un identifiant de chat télégramme, un nom, un nombre de points (actuel et maximum), ainsi que l'état actuel du bot. Les questions auront également un identifiant unique, ainsi que des champs responsables des options de questions et de réponses. Nous pouvons exécuter le script résultant en cliquant dessus avec le bouton droit et en sélectionnant "Exécuter le script SQL". Une attention particulière doit être accordée à l'élément "Interface Cmd-Line" - ici, nous aurons besoin de PostgreSQL fraîchement installé. Lors de la configuration de ce champ, sélectionnez "Nouvelle interface Cmd-Line" et spécifiez le chemin d'accès à psql.exe. En conséquence, les paramètres devraient ressembler à ceci : Création d'un bot de télégramme à l'aide de Spring Boot Pt.2 : Quiz Bot - 4Nous exécutons le script et si nous n'avons commis d'erreur nulle part, le résultat de notre travail sera le suivant : Création d'un bot de télégramme à l'aide de Spring Boot Pt.2 : Quiz Bot - 8<h3>Créer un modèle</h3>Il est maintenant temps pour revenir à l'écriture du code Java. Pour raccourcir l'article, j'omettrai la description des annotations utilisées pour rédiger les cours afin que vous puissiez vous familiariser avec elles. Créons un package modèle dans lequel nous aurons trois classes :
  • AbstractBaseEntity est une classe qui décrit tout objet pouvant avoir un identifiant (cette classe est une forte simplification de ce que vous pourriez voir lors d'un stage) :
    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 - разберитесь в documentации каждой!
        @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() {
        }
    }
  • Utilisateur :
    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;
        }
    }
  • Classe de questions :
    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>Création de référentiels</h3>Écrivons maintenant les référentiels Spring Data Jpa. Nous créons un package de référentiel qui aura deux interfaces : JpaUserRepository, JpaQuestionRepository. Ils hériteront de JpaRepository, une interface Spring Data qui nous permet de créer pratiquement de la magie. Pour comprendre leur travail, je vous recommande de regarder la vidéo d'Evgeny Borisov . Les classes seront très réduites :
  • Référentiel JpaUser :
    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,>
  • Référentiel 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>Ajouter des fonctionnalités au bot</h3>Dans la classe User , nous avons un champ de la classe State non encore créée , qui nous dira à quelle étape du travail avec le bot se trouve actuellement l'utilisateur. Créons-le dans le package /bot :
package com.whiskels.telegram.bot;

public enum State {
    NONE,
    START,
    ENTER_NAME,
    PLAYING_QUIZ,
}
Ensuite, nous allons créer un package bot/handler dans lequel nous déclarerons l’interface du gestionnaire :
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();
// метод, который позволяет узнать, Howие команды CallBackQuery мы можем обработать в этом классе
    List<string> operatedCallBackQuery();
}

</string></partialbotapimethod<?>
Nous créerons les gestionnaires un peu plus tard, mais pour l'instant déléguons le traitement des événements à la nouvelle classe UpdateReceiver , que nous créerons à la racine du package du bot : ATTENTION ! Ici et plus loin, il y aura des méthodes affichées sous la forme List> handle(args); en réalité, ils ressemblent à ceci, mais le formateur de code les a cassés :Création d'un bot de télégramme à l'aide de 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>
Et nous lui déléguons le traitement dans la classe 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<?>
Désormais, notre bot délègue le traitement des événements à la classe UpdateReceiver , mais nous n'avons pas encore de gestionnaire. Créons-les ! CLAUSE DE NON-RESPONSABILITÉ! Je voulais vraiment partager les possibilités d'écriture d'un tel bot, afin que le code supplémentaire (comme en principe le code UpdateReceiver) puisse être très bien refactorisé en utilisant divers modèles. Mais nous apprenons et notre objectif est un bot minimalement viable, donc comme autre devoir, vous pouvez refactoriser tout ce que vous avez vu :) Créez un package util, et dedans - la classe 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);
    }
}
Nous écrirons quatre gestionnaires : HelpHandler, QuizHandler, RegistrationHandler, StartHandler. Gestionnaire de démarrage :
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<?>
Gestionnaire d'enregistrement :
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);

        // Doing кнопку для применения изменений
        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) {
        // При requestе изменения имени мы меняем 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<?>
Gestionnaire d'aide :
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 (le pire
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION