JavaRush /Java blogi /Random-UZ /Spring Boot Pt.2 yordamida telegram bot yaratish: Quiz Bo...
Whiskels
Daraja
Москва

Spring Boot Pt.2 yordamida telegram bot yaratish: Quiz Bot

Guruhda nashr etilgan
1-QISM Assalomu alaykum! Oldingi maqolada biz har qanday tadbirda bizni kutib oladigan oddiy bot yaratdik. Biz allaqachon minglab qator kodlarni yozdik va botimizga yanada murakkab funksiyalarni qo‘shish vaqti keldi. Bugun biz oddiy bot yozishga harakat qilamiz, shunda bo'sh vaqtimizda Java Core bo'yicha bilimlarimizni intervyu oldidan chuqurlashtirishimiz mumkin (hayratlanarlisi, men bunday turdagi bitta ishlaydigan botni topmadim). Buning uchun biz quyidagilarni bajaramiz:
  • tashqi Postgres ma'lumotlar bazasini Heroku-ga ulang;
  • Keling, ma'lumotlar bazasini ishga tushirish va to'ldirish uchun birinchi skriptlarimizni yozaylik;
  • ma'lumotlar bazasi bilan ishlash uchun Spring Boot Data JPA ni ulaymiz;
  • Biz bot harakatining turli stsenariylarini amalga oshiramiz.
Agar bu siz uchun qiziq bo'lsa va maqolani o'qib chiqqandan so'ng, siz chirigan pomidorlarni tashlamoqchi bo'lmasangiz, unda mening omborimga yulduz qo'ying , men mamnun bo'laman! Agar sizda biron bir savol bo'lsa, biz ularni sharhlarda muhokama qilamiz. Oxir-oqibat, biz buni olamiz: Spring Boot Pt.2 yordamida telegram bot yaratish: Quiz Bot - 1Spring Boot Pt.2 yordamida telegram bot yaratish: Quiz Bot - 2Spring Boot Pt.2 yordamida telegram bot yaratish: Quiz Bot - 3<h2>Demak, ketaylik!</h2><h3>Heroku-da ma'lumotlar bazasini yaratish</h3>Keling, birinchi tashqi ma'lumotlar bazasini yaratishdan boshlaylik. Mahalliy ish uchun pgAdmin ni tekshirishni tavsiya etaman . Ammo kelajakda siz mahalliy mashinangizga bog'liq bo'lmasligi uchun botni Heroku-ga joylashtirasiz va buning uchun ushbu xizmat bilan tanishib chiqamiz. Jarayon:
  • Heroku -da ro'yxatdan o'tish ;
  • Boshqaruv panelimizga o'ting -> Yangi -> Yangi ilova yarating va yangi ilova yarating;
  • Biz yangi yaratilgan dasturga kiramiz, bizni ko'plab tugmalar qo'rqitadi, lekin biz "O'rnatilgan qo'shimchalar" paneliga e'tibor qaratamiz - uning yonida Qo'shimchalarni sozlash tugmasi mavjud, biz uni bosamiz;
  • Qidiruvga “Heroku Postgres” ni kiriting, “Hobbi Dev - Free” rejasini tanlang -> Buyurtma shaklini yuborish;
  • Yangi olingan ma'lumotlar bazasini oching -> Sozlamalar -> Hisob ma'lumotlarini ko'rish. Ushbu yorliqda ma'lumotlar bazasiga kirish uchun kalitlarimiz mavjud. Biz ularning joylashuvini eslaymiz - bizga IDEA-dagi DataSource kabi ma'lumotlar bazasini ulash uchun kerak bo'ladi.
<h3>Pom.xml-ga bog'liqliklar qo'shing</h3>Botimiz ustida ishlashning bir qismi sifatida biz pom-ga quyidagi bog'liqliklarni qo'shamiz: Lombok, Spring Boot Data JPA, PostgreSQL. STOP! Bularning barchasi nima va nima uchun biz uni qo'shmoqdamiz?
  • Lombok - bu kutubxona, uning yordamida biz turli xil kodlar miqdorini sezilarli darajada kamaytiramiz. Uning yordamida biz avtomatik ravishda konstruktorlar, setterlar, oluvchilar va boshqa ko'p narsalarni yaratishimiz mumkin.
  • Spring Data JPA ma'lumotlar bazalari bilan ishlash uchun asosdir ( garchi u juda oddiy bo'lsa ham). Spring Data JPA imkoniyatlarining tavsifi bir qator maqolalarni tashkil qiladi va biz ko'rsatgan qaramlik Hibernate va boshqa ko'p narsalarni o'z ichiga oladi, shuning uchun tafsilotlarni o'tkazib yuboramiz va bugun Spring JPA yordamida biror narsa yozishga harakat qilaylik.
  • PostgreSQL - biz ma'lumotlar bazasi bilan ishlaydigan drayverni olish uchun kutubxonani tortamiz.
Bizning pom.xml quyidagicha ko'rinishni boshlaydi: Xususiyatlar: Spring Boot Pt.2 yordamida telegram bot yaratish: Quiz Bot - 1Bog'liqliklar: Spring Boot Pt.2 yordamida telegram bot yaratish: Quiz Bot - 2Agar oldingi maqolani o'qimagan bo'lsangiz, iltimos, biz bu erga yangi bog'liqliklar qo'shayotganimizni unutmang, shuning uchun bu to'liq pom.xml tuzilmasi emas. Ushbu bog'liqliklarni loyihamizga yuklashni unutmang (masalan, Maven -> Barcha Maven loyihalarini qayta import qilish oynasiga o'tish orqali).<h3>Ma'lumotlar bazasini IDEA-ga ulash</h3>Agar IDEA Community Edition-dan foydalansangiz, DataSource yorlig'ini quyidagi tarzda yoqing . Plaginni qo'shgandan so'ng, biz DataSource-ni sozlashimiz kerak. Buning uchun avval plagin displeyini yoqing: View -> Tool Windows -> DB Browser. Ochilgan oynada yashil plyus (yangi ulanish) -> PostgreSQL-ni bosing. Bu erda bizga Heroku-da ko'rgan hisob ma'lumotlari kerak bo'ladi. Oynani to'ldiring: Spring Boot Pt.2 yordamida telegram bot yaratish: Quiz Bot - 3Va "Ulanishni sinab ko'rish" tugmasini bosing. Har bir narsa to'g'ri bajarilgan bo'lsa, ma'lumotlar bazasiga ulanish muvaffaqiyatli bo'lganligini ko'rsatadigan qalqib chiquvchi oyna paydo bo'ladi. Ma'lumotlar manbamizni saqlang.<h3>Ma'lumotlar bazasida jadvallar yarating</h3>Endi biz ishlaydigan jadvallarni yarataylik. Birinchidan, PostgreSQL ni o'rnatamiz . O'rnatishdan so'ng src/main/resources papkasida initDB.sql faylini yarating:
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
);
Bizning skriptimiz nima qiladi? Birinchi ikkita satr, agar mavjud bo'lsa, ularni qayta yaratish uchun jadvallarni o'chiradi. Uchinchi qator ma'lumotlar bazasida noyob identifikator yozuvlarini yaratish uchun foydalaniladigan ketma-ketlikni yaratadi. Keyin ikkita jadval yaratamiz: foydalanuvchilar va savollar uchun. Foydalanuvchining noyob identifikatori, telegram chat identifikatori, ismi, ochkolar soni (joriy va maksimal), shuningdek, botning joriy holatiga ega bo‘ladi. Savollar, shuningdek, noyob identifikatorga ega bo'ladi, shuningdek, uning savol va javob variantlari uchun mas'ul bo'lgan maydonlar. Olingan skriptni sichqonchaning o'ng tugmasi bilan bosish va "SQL skriptini bajarish" bandini tanlash orqali bajarishimiz mumkin. "Cmd-Line interfeysi" bandiga alohida e'tibor berilishi kerak - bu erda bizga yangi o'rnatilgan PostgreSQL kerak bo'ladi. Ushbu maydonni sozlashda "Yangi Cmd-Line interfeysi" ni tanlang va psql.exe yo'lini belgilang. Natijada, sozlamalar quyidagicha ko'rinishi kerak: Spring Boot Pt.2 yordamida telegram bot yaratish: Quiz Bot - 4Biz skriptni bajaramiz va agar biror joyda xato qilmagan bo'lsak, ishimizning natijasi quyidagicha bo'ladi: Spring Boot Pt.2 yordamida telegram bot yaratish: Quiz Bot - 8<h3>Model yaratish</h3>Endi vaqt keldi. Java kodini yozishga qaytish uchun. Maqolani qisqartirish uchun siz ular bilan tanishishingiz uchun sinflarni yozishda foydalanilgan izohlarning tavsifini o'tkazib yuboraman. Keling, uchta sinfga ega bo'lgan namunaviy paketni yarataylik:
  • AbstractBaseEntity - bu identifikatorga ega bo'lishi mumkin bo'lgan har qanday ob'ektni tavsiflovchi sinf (bu sinf stajirovkada ko'rishingiz mumkin bo'lgan narsalarni kuchli soddalashtirishdir):
    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() {
        }
    }
  • Foydalanuvchi :
    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;
        }
    }
  • Savollar 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>Omborlarni yaratish</h3>Endi Spring Data Jpa omborlarini yozamiz. Biz ikkita interfeysga ega bo'lgan ombor paketini yaratamiz : JpaUserRepository, JpaQuestionRepository. Ular JpaRepository-dan, Spring Data interfeysidan meros bo'lib, bizga amalda sehr yaratish imkonini beradi. Ularning ishlarini tushunish uchun men Evgeniy Borisov tomonidan videoni tomosha qilishni maslahat beraman . Sinflar juda kichik bo'ladi:
  • 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>Botga funksiya qo'shish</h3> Foydalanuvchi sinfida bizda hali yaratilmagan Davlat klassining maydoni mavjud bo'lib , u foydalanuvchi hozirda bot bilan ishlashning qaysi bosqichida ekanligini aytib beradi. Keling, uni /bot paketida yaratamiz:
package com.whiskels.telegram.bot;

public enum State {
    NONE,
    START,
    ENTER_NAME,
    PLAYING_QUIZ,
}
Keyinchalik, biz ishlov beruvchi interfeysini e'lon qiladigan bot/ishlovchi paketini yaratamiz:
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 ishlov beruvchilarni birozdan keyin yaratamiz, ammo hozircha biz bot paketining ildizida yaratadigan yangi UpdateReceiver sinfiga hodisalarni qayta ishlashni topshiramiz : DIQQAT! Bu erda va keyin List> handle(args) sifatida ko'rsatiladigan usullar mavjud bo'ladi; aslida ular shunday ko'rinadi, lekin kod formatlovchi ularni buzdi:Spring Boot Pt.2 yordamida telegram bot yaratish: 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>
Va biz unga ishlov berishni Bot sinfida topshiramiz:
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<?>
Endi bizning bot delegatlarimiz hodisani UpdateReceiver sinfiga qayta ishlaydi , ammo bizda hali ishlov beruvchilar yo‘q. Keling, ularni yarataylik! Ogohlantirish! Men bunday botni yozish imkoniyatlarini baham ko'rishni juda xohlardim, shuning uchun keyingi kod (odatda UpdateReceiver kodi kabi) turli naqshlar yordamida juda yaxshi refaktoratsiya qilinishi mumkin. Lekin biz o'rganyapmiz va bizning maqsadimiz - minimal hayotiy bot, shuning uchun boshqa uy vazifasi sifatida siz ko'rgan hamma narsani qayta ko'rib chiqishingiz mumkin :) Util paketini va unda - TelegramUtil sinfini yarating :
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 to'rtta ishlov beruvchini yozamiz: 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<?>
Yordamchi:
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 (eng yomoni
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION