JavaRush /Blog Java /Random-MS /Mencipta bot telegram menggunakan Spring Boot Pt.2: Quiz ...
Whiskels
Tahap
Москва

Mencipta bot telegram menggunakan Spring Boot Pt.2: Quiz Bot

Diterbitkan dalam kumpulan
BAHAGIAN 1 Aloha! Dalam artikel sebelumnya, kami mencipta bot mudah yang mengalu-alukan kami ke sebarang acara. Kami telah pun menulis beribu-ribu baris kod, dan sudah tiba masanya untuk menambah fungsi yang lebih kompleks pada bot kami. Hari ini kami akan cuba menulis bot mudah supaya dalam masa lapang kami dapat mengasah pengetahuan kami tentang Java Core sebelum temu duga (yang menghairankan, saya tidak menemui satu bot yang berfungsi seperti ini). Untuk melakukan ini kami akan melakukan perkara berikut:
  • sambungkan pangkalan data Postgres luaran kepada Heroku;
  • Mari tulis skrip pertama kami untuk memulakan dan mengisi pangkalan data;
  • mari sambungkan Spring Boot Data JPA untuk berfungsi dengan pangkalan data;
  • Kami melaksanakan pelbagai senario tingkah laku bot.
Jika ini menarik untuk anda, dan selepas membaca artikel anda tidak mahu membuang tomato busuk, kemudian letakkan bintang dalam repositori saya , saya akan gembira! Jika anda mempunyai sebarang soalan, kami akan membincangkannya dalam ulasan. Inilah yang kita akan dapat pada akhirnya: Mencipta bot telegram menggunakan Spring Boot Pt.2: Quiz Bot - 1Mencipta bot telegram menggunakan Spring Boot Pt.2: Quiz Bot - 2Mencipta bot telegram menggunakan Spring Boot Pt.2: Quiz Bot - 3<h2>Jadi, mari kita pergi!</h2><h3>Mencipta pangkalan data pada Heroku</h3>Mari mulakan dengan mencipta pangkalan data luaran pertama kami. Untuk kerja tempatan, saya cadangkan menyemak pgAdmin . Tetapi saya mahu anda dibimbing oleh fakta bahawa pada masa hadapan anda akan menggunakan bot ke Heroku supaya ia tidak bergantung pada mesin tempatan anda, dan untuk ini mari kita berkenalan dengan perkhidmatan ini. Prosedur:
  • mendaftar di Heroku ;
  • Pergi ke papan pemuka kami -> Baharu -> Cipta aplikasi baharu dan buat aplikasi baharu;
  • Kami pergi ke aplikasi yang baru dibuat, kami takut dengan banyak butang, tetapi kami menumpukan pada panel "Add-ons yang dipasang" - di sebelahnya terdapat butang Konfigurasi Alat tambah, kami mengkliknya;
  • Masukkan "Heroku Postgres" ke dalam carian, pilih pelan "Hobby Dev - Free" -> Hantar Borang Pesanan;
  • Buka pangkalan data yang baru diperoleh -> Tetapan -> Lihat Kredensial. Tab ini akan mengandungi kunci kami untuk mengakses pangkalan data. Kami ingat lokasi mereka - kami memerlukan mereka untuk menyambungkan pangkalan data, seperti DataSource dalam IDEA.
<h3>Tambah kebergantungan pada pom.xml</h3>Sebagai sebahagian daripada kerja pada bot kami, kami akan menambah kebergantungan berikut pada pom kami: Lombok, Spring Boot Data JPA, PostgreSQL. Berhenti! Apakah semua ini dan mengapa kami menambahnya?
  • Lombok ialah perpustakaan yang mana kami akan mengurangkan jumlah kod yang berbeza dengan ketara. Dengan itu kita boleh mencipta pembina, penetap, pengambil dan banyak lagi secara automatik.
  • Spring Data JPA ialah rangka kerja untuk bekerja dengan pangkalan data (walaupun ia kedengaran terlalu mudah). Perihalan keupayaan Spring Data JPA akan berjumlah satu siri artikel, dan pergantungan yang kami nyatakan juga melibatkan Hibernate dan banyak lagi, jadi mari langkau butiran dan cuba tulis sesuatu menggunakan Spring JPA hari ini.
  • PostgreSQL - kami menarik perpustakaan untuk mendapatkan pemacu yang akan berfungsi dengan pangkalan data kami.
Pom.xml kami mula kelihatan seperti ini: Properties: Mencipta bot telegram menggunakan Spring Boot Pt.2: Quiz Bot - 1Dependencies: Mencipta bot telegram menggunakan Spring Boot Pt.2: Quiz Bot - 2Jika anda tidak membaca artikel sebelumnya, sila ambil perhatian bahawa kami menambah dependencies baharu di sini, jadi ini bukan struktur pom.xml yang lengkap. Jangan lupa untuk memuatkan kebergantungan ini ke dalam projek kami (contohnya, dengan pergi ke Maven -> Reimport all Maven projects window).<h3>Menyambungkan pangkalan data dalam IDEA</h3>Jika anda menggunakan IDEA Community Edition, anda boleh dayakan tab DataSource seperti berikut . Selepas menambah pemalam, kita perlu mengkonfigurasi DataSource. Untuk melakukan ini, mula-mula dayakan paparan pemalam: View -> Tool Windows -> DB Browser. Dalam tetingkap yang terbuka, klik pada tambah hijau (sambungan baharu) -> PostgreSQL. Di sini kita memerlukan kelayakan, yang telah kita lihat pada Heroku. Isi tetingkap: Mencipta bot telegram menggunakan Spring Boot Pt.2: Quiz Bot - 3Dan klik "Uji Sambungan". Jika semuanya dilakukan dengan betul, tetingkap pop timbul akan muncul yang menunjukkan bahawa sambungan ke pangkalan data telah berjaya. Simpan Sumber Data kami.<h3>Buat jadual dalam pangkalan data</h3>Sekarang mari buat jadual yang akan kami gunakan. Mula-mula, mari pasang PostgreSQL . Selepas pemasangan, buat fail initDB.sql dalam folder 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
);
Apakah skrip kami lakukan? Dua baris pertama memadamkan jadual, jika ada, untuk menciptanya semula. Baris ketiga mencipta urutan yang akan digunakan untuk mencipta entri id unik dalam pangkalan data kami. Seterusnya kami membuat dua jadual: untuk pengguna dan untuk soalan. Pengguna akan mempunyai id unik, id sembang telegram, nama, bilangan mata (semasa dan maksimum), serta status semasa bot. Soalan juga akan mempunyai id unik, serta medan yang bertanggungjawab untuk pilihan soalan dan jawapan untuknya. Kita boleh melaksanakan skrip yang terhasil dengan mengklik kanan padanya dan memilih "Execute SQL Script". Perhatian khusus harus diberikan kepada item "antara muka Cmd-Line" - di sini kita memerlukan PostgreSQL yang baru dipasang. Apabila mengkonfigurasi medan ini, pilih "Antara muka Baris Cmd Baharu" dan tentukan laluan ke psql.exe. Akibatnya, tetapan sepatutnya kelihatan seperti ini: Mencipta bot telegram menggunakan Spring Boot Pt.2: Quiz Bot - 4Kami melaksanakan skrip dan jika kami tidak membuat kesilapan di mana-mana, hasil kerja kami adalah seperti berikut: Mencipta bot telegram menggunakan Spring Boot Pt.2: Quiz Bot - 8<h3>Buat model</h3>Sekarang tiba masanya untuk kembali menulis kod Java. Untuk memendekkan artikel, saya akan meninggalkan penerangan tentang anotasi yang digunakan untuk menulis kelas supaya anda boleh membiasakan diri dengannya. Mari kita buat pakej model di mana kita akan mempunyai tiga kelas:
  • AbstractBaseEntity ialah kelas yang menerangkan sebarang objek yang boleh mempunyai id (kelas ini merupakan penyederhanaan yang kukuh tentang perkara yang mungkin anda lihat dalam latihan):
    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() {
        }
    }
  • pengguna :
    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;
        }
    }
  • Kelas soalan :
    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>Mencipta repositori</h3>Sekarang mari tulis repositori Spring Data Jpa. Kami mencipta pakej repositori yang akan mempunyai dua antara muka : JpaUserRepository, JpaQuestionRepository. Mereka akan mewarisi daripada JpaRepository, antara muka Data Spring yang membolehkan kami mencipta sihir secara praktikal. Untuk memahami kerja mereka, saya mengesyorkan menonton video oleh Evgeny Borisov . Kelas akan menjadi sangat kecil:
  • 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>Tambah kefungsian pada bot</h3>Dalam kelas Pengguna , kami mempunyai medan kelas Negeri yang belum dibuat , yang akan memberitahu kami di peringkat mana bekerja dengan bot pengguna itu sedang berada. Mari kita buat dalam pakej /bot:
package com.whiskels.telegram.bot;

public enum State {
    NONE,
    START,
    ENTER_NAME,
    PLAYING_QUIZ,
}
Seterusnya, kami akan mencipta pakej bot/pengendali di mana kami akan mengisytiharkan antara muka pengendali:
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<?>
Kami akan membuat pengendali sedikit kemudian, tetapi buat masa ini mari kita mewakilkan pemprosesan acara ke kelas UpdateReceiver baharu , yang akan kami cipta dalam akar pakej bot: PERHATIAN! Di sini dan seterusnya akan ada kaedah yang dipaparkan sebagai List> handle(args); sebenarnya mereka kelihatan seperti ini, tetapi pemformat kod memecahkannya:Mencipta bot telegram menggunakan 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>
Dan kami mewakilkan pemprosesan kepadanya dalam kelas 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<?>
Kini bot kami mewakilkan pemprosesan acara ke kelas UpdateReceiver , tetapi kami belum mempunyai sebarang pengendali lagi. Mari cipta mereka! PENAFIAN! Saya benar-benar ingin berkongsi kemungkinan menulis bot sedemikian, jadi kod lanjut (seperti pada dasarnya kod UpdateReceiver) boleh difaktorkan semula dengan sangat baik menggunakan pelbagai corak. Tetapi kami sedang belajar dan matlamat kami ialah bot yang berdaya maju minimum, jadi sebagai tugasan kerja rumah yang lain, anda boleh memfaktorkan semula semua yang anda lihat :) Cipta pakej util, dan di dalamnya - kelas 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);
    }
}
Kami akan menulis empat pengendali: 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<?>
Pengendali Pendaftaran:
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<?>
Pengendali Bantuan:
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 (yang paling teruk
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION