JavaRush /Java Blogu /Random-AZ /Spring Boot Pt.2 istifadə edərək teleqram botunun yaradıl...
Whiskels
Səviyyə
Москва

Spring Boot Pt.2 istifadə edərək teleqram botunun yaradılması: Quiz Bot

Qrupda dərc edilmişdir
HİSSƏ 1 Aloha! Əvvəlki məqalədə bizi istənilən tədbirdə qarşılayan sadə bir bot yaratmışdıq. Biz artıq minlərlə kod sətirini yazmışıq və botumuza daha mürəkkəb funksionallıq əlavə etməyin vaxtıdır. Bu gün biz sadə bir bot yazmağa çalışacağıq ki, boş vaxtlarımızda müsahibələrdən əvvəl Java Core haqqında biliklərimizi təkmilləşdirək (təəccüblüdür ki, mən belə bir işlək bot tapmadım). Bunu etmək üçün aşağıdakıları edəcəyik:
  • xarici Postgres verilənlər bazasını Heroku-ya qoşun;
  • Verilənlər bazasını işə salmaq və doldurmaq üçün ilk skriptlərimizi yazaq;
  • verilənlər bazası ilə işləmək üçün Spring Boot Data JPA-nı birləşdirək;
  • Biz bot davranışının müxtəlif ssenarilərini həyata keçiririk.
Bu sizin üçün maraqlıdırsa və məqaləni oxuduqdan sonra çürük pomidorları atmaq istəmirsinizsə, o zaman anbarıma bir ulduz qoyun , mən məmnun qalacağam! Hər hansı bir sualınız varsa, şərhlərdə onları müzakirə edəcəyik. Sonda əldə edəcəyimiz budur: Spring Boot Pt.2 istifadə edərək teleqram botunun yaradılması: Quiz Bot - 1Spring Boot Pt.2 istifadə edərək teleqram botunun yaradılması: Quiz Bot - 2Spring Boot Pt.2 istifadə edərək teleqram botunun yaradılması: Quiz Bot - 3<h2>Beləliklə, gedək!</h2><h3>Heroku-da verilənlər bazası yaratmaq</h3>İlk xarici verilənlər bazamızı yaratmaqla başlayaq. Yerli iş üçün pgAdmin-i yoxlamağı məsləhət görürəm . Ancaq gələcəkdə yerli maşınınızdan asılı olmaması üçün botu Heroku-ya yerləşdirəcəyinizi rəhbər tutmağınızı istəyirəm və bunun üçün bu xidmətlə tanış olaq. Prosedur:
  • Heroku -da qeydiyyatdan keçmək ;
  • İdarə panelimizə keçin -> Yeni -> Yeni proqram yaradın və yeni proqram yaradın;
  • Yeni yaradılmış proqrama daxil oluruq, bir çox düymələrdən qorxuruq, amma diqqətimizi "Quraşdırılmış əlavələr" panelinə cəmləyirik - onun yanında Əlavələri konfiqurasiya et düyməsi var, onu vururuq;
  • Axtarışa “Heroku Postgres” daxil edin, “Hobby Dev - Pulsuz” planını seçin -> Sifariş Formasını Göndər;
  • Yeni əldə edilmiş verilənlər bazasını açın -> Parametrlər -> Etibarnamələrə baxın. Bu tab verilənlər bazasına daxil olmaq üçün açarlarımızı ehtiva edəcəkdir. Biz onların yerini xatırlayırıq - IDEA-da DataSource kimi verilənlər bazasına qoşulmaq üçün onlara ehtiyacımız olacaq.
<h3>Pom.xml-ə asılılıqlar əlavə edin</h3>Bizim botumuz üzərində işləməyin bir hissəsi olaraq biz pomumuza aşağıdakı asılılıqları əlavə edəcəyik: Lombok, Spring Boot Data JPA, PostgreSQL. Dayan! Bütün bunlar nədir və niyə əlavə edirik?
  • Lombok bir kitabxanadır, bunun sayəsində fərqli kodun miqdarını əhəmiyyətli dərəcədə azaldacağıq. Bununla biz avtomatik olaraq konstruktorlar, tənzimləyicilər, alıcılar və s. yarada bilərik.
  • Spring Data JPA verilənlər bazası ilə işləmək üçün çərçivədir ( çox sadə səslənsə də). Spring Data JPA-nın imkanlarının təsviri bir sıra məqalələr təşkil edəcək və qeyd etdiyimiz asılılıq Hibernate və daha çoxunu ehtiva edir, ona görə də təfərrüatları atlayaq və sadəcə bu gün Spring JPA-dan istifadə edərək nəsə yazmağa çalışaq.
  • PostgreSQL - verilənlər bazamızla işləyəcək bir sürücü əldə etmək üçün kitabxananı çəkirik.
Bizim pom.xml belə görünməyə başlayır: Xüsusiyyətlər: Spring Boot Pt.2 istifadə edərək teleqram botunun yaradılması: Quiz Bot - 1Asılılıqlar: Spring Boot Pt.2 istifadə edərək teleqram botunun yaradılması: Quiz Bot - 2Əvvəlki məqaləni oxumamısınızsa, zəhmət olmasa qeyd edin ki, biz buraya yeni asılılıqlar əlavə edirik, ona görə də bu, tam pom.xml strukturu deyil. Bu asılılıqları layihəmizə yükləməyi unutmayın (məsələn, Maven -> Bütün Maven layihələrinin yenidən idxalı pəncərəsinə keçməklə).<h3>Verilənlər bazasını IDEA-da birləşdirin</h3>Əgər IDEA Community Edition istifadə edirsinizsə, edə bilərsiniz. DataSource nişanını aşağıdakı kimi aktivləşdirin . Plugini əlavə etdikdən sonra DataSource-u konfiqurasiya etməliyik. Bunu etmək üçün əvvəlcə plagin ekranını aktivləşdirin: View -> Tool Windows -> DB Browser. Açılan pəncərədə yaşıl plus (yeni əlaqə) -> PostgreSQL üzərinə klikləyin. Burada artıq Heroku-da gördüyümüz etimadnamələrə ehtiyacımız olacaq. Pəncərəni doldurun: Spring Boot Pt.2 istifadə edərək teleqram botunun yaradılması: Quiz Bot - 3Və "Bağlantıyı test et" düyməsini basın. Hər şey düzgün aparılırsa, verilənlər bazasına qoşulmanın uğurlu olduğunu göstərən bir pop-up pəncərəsi görünəcəkdir. Məlumat Mənbəmizi yadda saxlayın.<h3>Verilənlər bazasında cədvəllər yaradın</h3>İndi işləyəcəyimiz cədvəlləri yaradaq. Əvvəlcə PostgreSQL-i quraşdıraq . Quraşdırıldıqdan sonra src/main/resources qovluğunda initDB.sql faylını yaradın:
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
);
Skriptimiz nə edir? İlk iki sətir, əgər varsa, onları yenidən yaratmaq üçün cədvəlləri silir. Üçüncü sətir verilənlər bazamızda unikal id qeydləri yaratmaq üçün istifadə ediləcək ardıcıllıq yaradır. Sonra iki cədvəl yaradırıq: istifadəçilər üçün və suallar üçün. İstifadəçinin unikal identifikatoru, teleqram çat id-si, adı, xalların sayı (cari və maksimum), həmçinin botun cari statusu olacaq. Sualların eyni zamanda unikal identifikatoru, eləcə də sual və cavab seçimlərinə cavabdeh olan sahələr olacaq. Yaranan skripti siçanın sağ düyməsini sıxıb “Execute SQL Script”-i seçməklə icra edə bilərik. "Cmd-Line interfeysi" maddəsinə xüsusi diqqət yetirilməlidir - burada bizə təzə quraşdırılmış PostgreSQL lazımdır. Bu sahəni konfiqurasiya edərkən "Yeni Cmd-Line interfeysi" seçin və psql.exe-yə gedən yolu göstərin. Nəticədə, parametrlər belə görünməlidir: Spring Boot Pt.2 istifadə edərək teleqram botunun yaradılması: Quiz Bot - 4Skripti icra edirik və heç bir yerdə səhv etməmişiksə, işimizin nəticəsi aşağıdakı kimi olacaq: Spring Boot Pt.2 istifadə edərək teleqram botunun yaradılması: Quiz Bot - 8<h3>Model yaradın</h3>İndi vaxtdır Java kodunu yazmağa qayıtmaq üçün. Məqaləni qısaltmaq üçün dərsləri yazmaq üçün istifadə olunan şərhlərin təsvirini buraxacağam ki, siz onlarla tanış ola biləsiniz. Üç sinifimizin olacağı bir model paketi yaradaq:
  • AbstractBaseEntity identifikasiyası ola bilən hər hansı obyekti təsvir edən sinifdir (bu sinif təcrübədə görə biləcəyiniz şeylərin güclü sadələşdirilməsidir):
    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() {
        }
    }
  • İstifadəçi :
    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;
        }
    }
  • Sual sinfi :
    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>Repozitoriyaların yaradılması</h3>İndi isə Spring Data Jpa repozitoriyalarını yazaq. Biz iki interfeysə malik olan repozitoriya paketi yaradırıq : JpaUserRepository, JpaQuestionRepository. Onlar bizə praktiki olaraq sehr yaratmağa imkan verən Spring Data interfeysi olan JpaRepository-dən miras alacaqlar. Onların işini başa düşmək üçün Yevgeni Borisov tərəfindən videoya baxmağı məsləhət görürəm . Dərslər çox kiçik olacaq:
  • 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>Bota funksionallıq əlavə edin</h3> İstifadəçi sinfində bizdə hələ yaradılmamış Dövlət sinifinin sahəsi var , o bizə istifadəçinin hazırda botla işləməyin hansı mərhələdə olduğunu söyləyəcək. Gəlin onu /bot paketində yaradaq:
package com.whiskels.telegram.bot;

public enum State {
    NONE,
    START,
    ENTER_NAME,
    PLAYING_QUIZ,
}
Sonra, işləyici interfeysini elan edəcəyimiz bir bot/işləyici paketi yaradacağıq:
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<?>
Biz işləyiciləri bir az sonra yaradacağıq, lakin hələlik hadisə emalını bot paketinin kökündə yaradacağımız yeni UpdateReceiver sinfinə həvalə edək: DİQQƏT! Burada və daha sonra List> handle(args) kimi göstərilən üsullar olacaq; əslində onlar belə görünürlər, lakin kod formatlayıcı onları pozdu:Spring Boot Pt.2 istifadə edərək teleqram botunun yaradılması: 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>
Biz Bot sinfində emal etməyi ona həvalə edirik:
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<?>
İndi botumuz hadisəni UpdateReceiver sinfinə emal edir , lakin hələ heç bir işləyicimiz yoxdur. Gəlin onları yaradaq! MƏDDƏT! Mən həqiqətən belə bir bot yazma imkanlarını bölüşmək istədim, ona görə də əlavə kod (prinsipcə UpdateReceiver kodu kimi) müxtəlif nümunələrdən istifadə edərək çox yaxşı refaktorlaşdırıla bilər. Amma biz öyrənirik və məqsədimiz minimal dərəcədə işlək botdur, ona görə də başqa bir ev tapşırığı olaraq gördüyünüz hər şeyi yenidən nəzərdən keçirə bilərsiniz :) Util paketi yaradın və orada TelegramUtil sinfi :
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);
    }
}
Biz dörd işləyici yazacağıq: 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<?>
Registration Handler:
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<?>
Köməkçi:
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 (ən pis
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION