JavaRush /Java блогы /Random-KK /Spring Boot Pt.2 көмегімен телеграмма ботын жасау: Quiz B...
Whiskels
Деңгей
Москва

Spring Boot Pt.2 көмегімен телеграмма ботын жасау: Quiz Bot

Топта жарияланған
1-БӨЛІМ Аллох! Алдыңғы мақалада біз кез келген оқиғаны қарсы алатын қарапайым бот жасадық. Біз мыңдаған code жолын жазып қойдық және біздің ботқа күрделірек функцияларды қосатын кез келді. Бүгін біз қарапайым бот жазуға тырысамыз, осылайша бос уақытымызда Java Core туралы білімімізді сұхбатқа дейін жетілдіре аламыз (бір қызығы, мен мұндай жұмыс істейтін бірде-бір бот таппадым). Ол үшін келесі әрекеттерді орындаймыз:
  • сыртқы Postgres дерекқорын Heroku-ға қосу;
  • Дерекқорды инициализациялау және толтыру үшін алғашқы сценарийлерімізді жазайық;
  • дерекқормен жұмыс істеу үшін Spring Boot Data JPA қосайық;
  • Біз бот әрекетінің әртүрлі сценарийлерін орындаймыз.
Егер бұл сізге қызықты болса және мақаланы оқығаннан кейін сіз шірік қызанақтарды тастағыңыз келмесе, онда менің репозиторийге жұлдызша қойыңыз , мен риза боламын! Егер сізде сұрақтар туындаса, біз оларды түсініктемелерде талқылаймыз. Соңында мынаны аламыз: Spring Boot Pt.2 көмегімен телеграмма ботын құру: Quiz Bot - 1Spring Boot Pt.2 көмегімен телеграмма ботын құру: Quiz Bot - 2Spring Boot Pt.2 көмегімен телеграмма ботын құру: Quiz Bot - 3<h2>Ендеше, кеттік!</h2><h3>Heroku-да дерекқор жасау</h3>Бірінші сыртқы дерекқорды жасаудан бастайық. Жергілікті жұмыс үшін pgAdmin тексеруді ұсынамын . Бірақ мен сізге болашақта жергілікті машинаңызға тәуелді болмас үшін ботты Герокуға орналастыратындығыңызды басшылыққа алғаныңызды қалаймын және ол үшін осы қызметпен танысайық. Процедура:
  • Heroku сайтында тіркелу ;
  • Біздің бақылау тақтасына өтіңіз -> Жаңа -> Жаңа қолданба жасаңыз және жаңа қолданба жасаңыз;
  • Біз жаңадан жасалған қолданбаға кіреміз, бізді көптеген түймелер қорқытады, бірақ біз «Орнатылған қондырмалар» панеліне назар аударамыз - оның жанында «Қосымшаларды конфигурациялау» түймесі бар, біз оны басамыз;
  • Іздеуге «Heroku Postgres» енгізіңіз, «Hobby Dev - Tagін» жоспарын таңдаңыз -> Тапсырыс формасын жіберу;
  • Жаңадан алынған дерекқорды ашыңыз -> Параметрлер -> Тіркелгі деректерін қарау. Бұл қойындыда дерекқорға кіруге арналған кілттеріміз болады. Біз олардың орналасқан жерін есте сақтаймыз - IDEA жүйесіндегі DataSource сияқты дерекқорды қосу үшін бізге қажет болады.
<h3>Pom.xml-ге тәуелділіктерді қосу</h3>Ботпен жұмыс істеудің бір бөлігі ретінде біз помға келесі тәуелділіктерді қосамыз: Lombok, Spring Boot Data JPA, PostgreSQL. Тоқта! Мұның бәрі не және біз оны не үшін қосып жатырмыз?
  • Ломбок - бұл кітапхана, оның арқасында біз әртүрлі codeтардың көлемін айтарлықтай азайтамыз. Оның көмегімен біз автоматты түрде конструкторларды, орнатушыларды, гетерлерді және т.б. жасай аламыз.
  • Spring Data JPA дерекқорлармен жұмыс істеуге арналған негіз болып табылады (бірақ ол өте қарапайым болып көрінеді). Spring Data JPA мүмкіндіктерінің сипаттамасы мақалалар сериясын құрайды және біз көрсеткен тәуелділік күту күйін және тағы басқаларды қамтиды, сондықтан егжей-тегжейлерді өткізіп жіберіп, бүгін Spring JPA көмегімен бірдеңе жазуға тырысайық.
  • PostgreSQL - біз дерекқормен жұмыс істейтін драйверді алу үшін кітапхананы тартамыз.
Біздің pom.xml келесідей бола бастайды: Сипаттар: Spring Boot Pt.2 көмегімен телеграмма ботын құру: Quiz Bot - 1Тәуелділіктер: Spring Boot Pt.2 көмегімен телеграмма ботын құру: Quiz Bot - 2Егер сіз алдыңғы мақаланы оқымаған болсаңыз, біз мұнда жаңа тәуелділіктерді қосып жатқанымызды ескеріңіз, сондықтан бұл толық pom.xml құрылымы емес. Бұл тәуелділіктерді жобамызға жүктеуді ұмытпаңыз (мысалы, Maven -> Барлық Maven жобаларын қайта импорттау терезесіне өту арқылы).<h3>Дерекқорды IDEA жүйесінде қосу</h3>Егер IDEA Community Edition пайдалансаңыз, DataSource қойындысын төмендегідей қосыңыз . Плагинді қосқаннан кейін біз DataSource конфигурациялауымыз керек. Ол үшін алдымен плагин дисплейін қосыңыз: View -> Tool Windows -> DB Browser. Ашылған терезеде жасыл плюс (жаңа қосылым) -> PostgreSQL түймесін басыңыз. Мұнда бізге Heroku-да көрген тіркелгі деректері қажет болады. Терезені толтырыңыз: Spring Boot Pt.2 көмегімен телеграмма ботын құру: Quiz Bot - 3«Қосылымды тексеру» түймесін басыңыз. Егер бәрі дұрыс орындалса, дерекқорға қосылу сәтті болғанын көрсететін қалқымалы терезе пайда болады. Деректер көзімізді сақтаңыз.<h3>Дерекқорда кестелер жасаңыз</h3>Енді біз жұмыс істейтін кестелерді жасайық. Алдымен PostgreSQL орнатайық . Орнатқаннан кейін src/main/resources қалтасында initDB.sql файлын жасаңыз:
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
);
Біздің сценарий не істейді? Алғашқы екі жол кестелерді, егер бар болса, оларды қайта жасау үшін өшіреді. Үшінші жол дерекқорымызда бірегей идентификатор жазбаларын жасау үшін пайдаланылатын реттілікті жасайды. Содан кейін біз екі кесте жасаймыз: пайдаланушылар үшін және сұрақтар үшін. Пайдаланушының бірегей идентификаторы, телеграмма чатының идентификаторы, аты, ұпай саны (ағымдағы және максималды), сондай-ақ боттың ағымдағы күйі болады. Сұрақтардың бірегей идентификаторы, сондай-ақ оған сұрақ пен жауап опцияларына жауапты өрістер болады. Алынған сценарийді тінтуірдің оң жақ түймешігімен басып, «SQL сценарийін орындау» опциясын таңдау арқылы орындай аламыз. «Cmd-Line интерфейсі» тармағына ерекше назар аудару керек - мұнда бізге жаңадан орнатылған PostgreSQL қажет. Бұл өрісті конфигурациялау кезінде «Жаңа Cmd-Line интерфейсін» таңдап, psql.exe жолын көрсетіңіз. Нәтижесінде параметрлер келесідей болуы керек: Spring Boot Pt.2 көмегімен телеграмма ботын құру: Quiz Bot - 4Біз сценарийді орындаймыз және еш жерде қателеспесек, жұмысымыздың нәтижесі келесідей болады: Spring Boot Pt.2 көмегімен телеграмма ботын құру: Quiz Bot - 8<h3>Модель жасау</h3>Енді уақыт келді. Java codeын жазуға оралу үшін. Мақаланы қысқарту үшін мен сіз олармен танысуыңыз үшін сабақтарды жазу үшін қолданылатын annotationлардың сипаттамасын қалдырамын. Үш сынып болатын үлгі пакетін жасайық:
  • AbstractBaseEntity — идентификаторы болуы мүмкін кез келген нысанды сипаттайтын сынып (бұл сынып тағылымдамадан көруге болатын нәрсені жеңілдетеді):
    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() {
        }
    }
  • Қолданушы :
    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;
        }
    }
  • Сұрақ сыныбы :
    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>Репозиторийлерді құру</h3>Енді Spring Data Jpa репозиторийлерін жазайық. Біз екі интерфейсі бар репозиторий бумасын жасаймыз : JpaUserRepository, JpaQuestionRepository. Олар бізге іс жүзінде сиқыр жасауға мүмкіндік беретін Spring Data интерфейсі JpaRepository мұрагері болады. Олардың жұмысын түсіну үшін Евгений Борисовтың бейнесін қарауды ұсынамын . Сабақтар өте аз болады:
  • 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>Ботқа функционалдық қосу</h3> Пайдаланушы сыныбында бізде әлі жасалмаған күй сыныбының өрісі бар , ол бізге қазіргі уақытта ботпен жұмыс істеудің қай кезеңінде екенін көрсетеді. Оны /bot бумасында жасайық:
package com.whiskels.telegram.bot;

public enum State {
    NONE,
    START,
    ENTER_NAME,
    PLAYING_QUIZ,
}
Содан кейін біз өңдеуші интерфейсін жариялайтын бот/өңдеуші пакетін жасаймыз:
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<?>
Біз өңдеушілерді сәл кейінірек жасаймыз, бірақ әзірге біз бот бумасының түбірінде жасайтын жаңа UpdateReceiver сыныбына оқиғаны өңдеуді тапсырайық : НАЗАР АУДАРЫҢЫЗ! Мұнда және одан әрі тізім> дескриптор(args) ретінде көрсетілетін әдістер болады; шын мәнінде олар осылай көрінеді, бірақ code пішімдеуші оларды бұзды: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>
Біз оны 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<?>
Енді біздің бот оқиғаны UpdateReceiver сыныбына өңдеуді тапсырады , бірақ бізде әлі өңдеушілер жоқ. Оларды жасайық! БАС ТАРТУ! Мен шынымен осындай бот жазу мүмкіндіктерімен бөліскім келді, сондықтан әрі қарай codeты (негізінде ЖаңартуҚабылдағыш codeы сияқты) әртүрлі үлгілер арқылы өте жақсы рефакторизациялауға болады. Бірақ біз үйреніп жатырмыз және біздің мақсатымыз - ең аз өміршең бот, сондықтан үй тапсырмасының басқа тапсырмасы ретінде сіз көргендердің барлығын қайта өңдей аласыз :) Пайдалы пакетті жасаңыз және оның ішінде - 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);
    }
}
Біз төрт өңдеушілерді жазамыз: 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);

        // 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<?>
Анықтама өңдеушісі:
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 (ең нашар
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION