JavaRush /Блоги Java /Random-TG /Эҷоди боти телеграмма бо истифода аз Spring Boot Pt.2: Qu...
Whiskels
Сатҳи
Москва

Эҷоди боти телеграмма бо истифода аз Spring Boot Pt.2: Quiz Bot

Дар гурӯҳ нашр шудааст
КИСМИ 1 Ассалому алайкум! Дар мақолаи қаблӣ, мо як боти оддӣ эҷод кардем, ки моро дар ҳама гуна ҳодиса истиқбол мекард. Мо аллакай ҳазорҳо сатри рамз навиштаем ва вақти он расидааст, ки ба боти худ функсияҳои мураккабтар илова кунем. Имрӯз мо кӯшиш хоҳем кард, ки боти оддӣ нависем, то дар вақти холӣ мо дониши худро дар бораи Java Core пеш аз мусоҳиба такмил диҳем (ҳайратовар аст, ки ман ягон боти кории ин гунаро наёфтаам). Барои ин мо амалҳои зеринро иҷро мекунем:
  • як пойгоҳи додаҳои Postgres беруниро ба Heroku пайваст кунед;
  • Биёед скриптҳои аввалини худро барои оғоз ва пур кардани пойгоҳи додаҳо нависем;
  • биёед Spring Boot Data JPA-ро барои кор бо базаи маълумот пайваст кунем;
  • Мо сенарияҳои гуногуни рафтори ботро амалӣ мекунем.
Агар ин ба шумо ҷолиб бошад ва пас аз хондани мақола, шумо намехоҳед помидорҳои пӯсидаро партоед, пас дар анбори ман ситора гузоред , ман хушҳолам! Агар шумо ягон савол дошта бошед, мо онҳоро дар шарҳҳо муҳокима хоҳем кард. Ин аст он чизе ки мо дар охир ба даст меорем: Эҷоди боти телеграмма бо истифода аз Spring Boot Pt.2: Quiz Bot - 1Создаем телеграм-бота с использованием Spring Boot Pt.2: Quiz Bot - 2Создаем телеграм-бота с использованием Spring Boot Pt.2: Quiz Bot - 3<h2>Пас, биёед!</h2><h3>Эҷоди пойгоҳи додаҳо дар Heroku</h3>Биёед, бо эҷоди аввалин пойгоҳи додаи берунии худ оғоз кунем. Барои кори маҳаллӣ, ман тавсия медиҳам, ки pgAdmin -ро тафтиш кунед . Аммо ман мехоҳам, ки шумо бо он роҳнамоӣ кунед, ки дар оянда шумо ботро дар Ҳероку ҷойгир мекунед, то он аз мошини маҳаллии шумо вобаста набошад ва барои ин биёед бо ин хидмат шинос шавем. Тартиб:
  • дар Heroku сабти ном кунед ;
  • Ба панели панели мо гузаред -> Нав -> Эҷоди барномаи нав ва барномаи нав эҷод кунед;
  • Мо ба замимаи навтаъсис ворид мешавем, мо аз тугмаҳои зиёд тарсонем, аммо мо ба панели "Иловаҳои насбшуда" тамаркуз мекунем - дар паҳлӯи он тугмаи Танзими Иловаҳо мавҷуд аст, мо онро пахш мекунем;
  • Ба ҷустуҷӯ "Heroku Postgres" -ро ворид кунед, нақшаи "Hobby Dev - Free" -ро интихоб кунед -> Варақаи фармоишро пешниҳод кунед;
  • Пойгоҳи махзани нав ба даст овардашударо кушоед -> Танзимот -> Намоиши эътимоднома. Ин ҷадвал калидҳои моро барои дастрасӣ ба пойгоҳи додаҳо дар бар мегирад. Мо ҷойгиршавии онҳоро дар хотир дорем - ба мо барои пайваст кардани пойгоҳи додаҳо, ба монанди DataSource дар IDEA лозим аст.
<h3>Ба pom.xml вобастагӣ илова кунед</h3>Ҳамчун як қисми кор дар боти худ, мо вобастагиҳои зеринро ба pom илова мекунем: Lombok, Spring Boot Data JPA, PostgreSQL. Ист! Ин ҳама чист ва чаро мо онро илова мекунем?
  • Ломбок китобхонаест, ки ба туфайли он мо миқдори рамзҳои гуногунро ба таври назаррас коҳиш медиҳем. Бо он мо метавонем ба таври худкор конструкторҳо, сеттерҳо, гитерҳо ва ғайраро эҷод кунем.
  • Spring Data JPA чаҳорчӯбаи кор бо пойгоҳи додаҳост (гарчанде ки он хеле содда садо медиҳад). Тавсифи имкониятҳои Spring Data JPA як қатор мақолаҳоро дар бар мегирад ва вобастагӣ, ки мо нишон додем, инчунин Hibernate ва бисёр чизҳои дигарро дар бар мегирад, аз ин рӯ биёед тафсилотро сарфи назар кунем ва танҳо кӯшиш кунем, ки имрӯз бо истифода аз Spring JPA чизе нависем.
  • PostgreSQL - мо китобхонаро мекашем, то драйвереро гирем, ки бо пойгоҳи додаи мо кор кунад.
pom.xml-и мо чунин ба назар мерасад: Хусусиятҳо: Создаем телеграм-бота с использованием Spring Boot Pt.2: Quiz Bot - 1Вобастагӣ: Создаем телеграм-бота с использованием Spring Boot Pt.2: Quiz Bot - 2Агар шумо мақолаи қаблиро нахонда бошед, лутфан қайд кунед, ки мо дар ин ҷо вобастагии нав илова мекунем, бинобар ин ин сохтори пурраи pom.xml нест. Фаромӯш накунед, ки ин вобастагиҳоро ба лоиҳаи мо бор кунед (масалан, бо рафтан ба равзанаи Maven -> Reimport all projects Maven).<h3>Пайваст кардани базаи маълумот дар IDEA</h3>Агар шумо IDEA Community Edition -ро истифода баред, шумо метавонед ҷадвали DataSource-ро ба таври зерин фаъол созед . Пас аз илова кардани плагин, мо бояд DataSource-ро танзим кунем. Барои ин, аввал намоиши плагинро фаъол созед: Намоиш -> Воситаи Windows -> Browser DB. Дар равзанаи кушодашуда, плюс сабзро клик кунед (пайвасти нав) -> PostgreSQL. Дар ин ҷо ба мо эътимоднома лозим мешавад, ки мо аллакай дар Ҳероку дидаем. Равзанаро пур кунед: Создаем телеграм-бота с использованием Spring Boot Pt.2: Quiz Bot - 3Ва клик кунед "Пайвастшавии санҷиш". Агар ҳама чиз дуруст анҷом дода шавад, равзанаи поп-ап пайдо мешавад, ки нишон медиҳад, ки пайвастшавӣ ба пойгоҳи додаҳо муваффақ аст. Сарчашмаи маълумотҳои моро захира кунед.<h3>Дар базаи маълумот ҷадвалҳо эҷод кунед</h3>Акнун биёед ҷадвалҳоеро созем, ки бо онҳо кор хоҳем кард. Аввалан, биёед PostgreSQL -ро насб кунем . Пас аз насб, файли initDB.sql-ро дар папкаи 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
);
Скрипти мо чӣ кор мекунад? Ду сатри аввал ҷадвалҳоро, агар мавҷуд бошад, барои аз нав сохтани онҳо тоза мекунанд. Сатри сеюм пайдарпаӣ эҷод мекунад, ки барои эҷоди вурудоти беназири ID дар базаи мо истифода мешавад. Минбаъд мо ду ҷадвал эҷод мекунем: барои корбарон ва саволҳо. Истифодабаранда ID-и беназир, id-чати телеграмма, ном, шумораи холҳо (ҷори ва ҳадди аксар), инчунин ҳолати кунунии бот хоҳад дошт. Саволҳо инчунин ID-и беназир ва инчунин майдонҳое доранд, ки барои интихоби савол ва ҷавоб барои он масъуланд. Мо метавонем скрипти ҳосилшударо тавассути клики рости он ва интихоби "Иҷро кардани скрипти 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. Барои кӯтоҳ кардани мақола, ман тавсифи эзоҳҳоеро, ки барои навиштани дарсҳо истифода мешаванд, сарфи назар мекунам, то шумо бо онҳо шинос шавед. Биёед як бастаи намунавӣ созем, ки дар он мо се синф дорем:
  • AbstractBaseEntity синфест, ки ҳама гуна an objectеро тавсиф мекунад, ки метавонад ID дошта бошад (ин синф соддагардонии қавии он чизест, ки шумо дар таҷрибаомӯзӣ мебинед):
    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. Онҳо аз JpaRepository, интерфейси Spring Data мерос мегиранд, ки ба мо имкон медиҳад, ки амалан ҷоду эҷод кунем. Барои фаҳмидани кори онҳо, ман тавсия медиҳам, ки видеои Евгений Борисовро тамошо кунед . Синфҳо хеле хурд хоҳанд буд:
  • 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 вогузор кунем , ки мо онро дар решаи бастаи бот эҷод мекунем: ДИККАТ! Дар ин ҷо ва минбаъд усулҳое мавҷуданд, ки ҳамчун Рӯйхат> handle(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и минбаъда (ба мисли рамзи UpdateReceiver) метавонад бо истифода аз қолабҳои гуногун хеле хуб рефактор карда шавад. Аммо мо меомӯзем ва ҳадафи мо як боти ҳадди ақал қобor ҳаёт аст, аз ин рӯ шумо ҳамчун як вазифаи дигари хонагӣ, шумо метавонед ҳама чизеро, ки дидаед, рефактор кунед :) Бастаи утилӣ эҷод кунед ва дар он синфи 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<?>
Корманди бақайдгирӣ:
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