JavaRush /Blog Java /Random-VI /Tạo bot telegram bằng Spring Boot Pt.2: Quiz Bot
Whiskels
Mức độ
Москва

Tạo bot telegram bằng Spring Boot Pt.2: Quiz Bot

Xuất bản trong nhóm
PHẦN 1 Aloha! Trong bài viết trước, chúng tôi đã tạo một bot đơn giản chào đón chúng tôi đến bất kỳ sự kiện nào. Chúng tôi đã viết hàng nghìn dòng mã và đã đến lúc bổ sung thêm chức năng phức tạp hơn cho bot của chúng tôi. Hôm nay chúng ta sẽ cố gắng viết một bot đơn giản để trong thời gian rảnh rỗi, chúng ta có thể trau dồi kiến ​​​​thức về Java Core trước khi phỏng vấn (thật ngạc nhiên là tôi chưa tìm thấy một bot nào hoạt động được loại này). Để làm điều này chúng ta sẽ làm như sau:
  • kết nối cơ sở dữ liệu Postgres bên ngoài với Heroku;
  • Hãy viết các tập lệnh đầu tiên của chúng ta để khởi tạo và điền vào cơ sở dữ liệu;
  • hãy kết nối Spring Boot Data JPA để làm việc với cơ sở dữ liệu;
  • Chúng tôi thực hiện nhiều kịch bản khác nhau về hành vi của bot.
Nếu điều này khiến bạn thú vị và sau khi đọc bài viết mà bạn không muốn ném cà chua thối thì hãy đánh dấu một ngôi sao vào kho lưu trữ của tôi , tôi sẽ rất vui! Nếu bạn có bất kỳ câu hỏi nào, chúng tôi sẽ thảo luận chúng trong phần bình luận. Đây là những gì chúng ta sẽ nhận được cuối cùng: Tạo bot telegram bằng Spring Boot Pt.2: Quiz Bot - 1Tạo bot telegram bằng Spring Boot Pt.2: Quiz Bot - 2Tạo bot telegram bằng Spring Boot Pt.2: Quiz Bot - 3<h2>Vì vậy, hãy bắt đầu!</h2><h3>Tạo cơ sở dữ liệu trên Heroku</h3>Hãy bắt đầu bằng cách tạo cơ sở dữ liệu bên ngoài đầu tiên của chúng ta. Đối với công việc địa phương, tôi khuyên bạn nên kiểm tra pgAdmin . Nhưng tôi muốn bạn được hướng dẫn bởi thực tế là trong tương lai bạn sẽ triển khai bot lên Heroku để nó không phụ thuộc vào máy cục bộ của bạn và để làm được điều này, hãy làm quen với dịch vụ này. Thủ tục:
  • đăng ký trên Heroku ;
  • Đi tới trang tổng quan của chúng tôi -> Mới -> Tạo ứng dụng mới và tạo ứng dụng mới;
  • Chúng tôi đi vào ứng dụng mới tạo, chúng tôi bị choáng ngợp bởi nhiều nút, nhưng chúng tôi tập trung vào bảng “Tiện ích bổ sung đã cài đặt” - bên cạnh có nút Định cấu hình tiện ích bổ sung, chúng tôi nhấp vào nó;
  • Nhập “Heroku Postgres” vào tìm kiếm, chọn gói “Hobby Dev - Free” -> Gửi mẫu đơn đặt hàng;
  • Mở cơ sở dữ liệu mới thu được -> Cài đặt -> Xem thông tin xác thực. Tab này sẽ chứa các khóa của chúng tôi để truy cập cơ sở dữ liệu. Chúng tôi nhớ vị trí của chúng - chúng tôi sẽ cần chúng để kết nối cơ sở dữ liệu, như DataSource trong IDEA.
<h3>Thêm các phần phụ thuộc vào pom.xml</h3>Là một phần trong quá trình làm việc với bot của chúng tôi, chúng tôi sẽ thêm các phần phụ thuộc sau vào pom của mình: Lombok, Spring Boot Data JPA, PostgreSQL. Dừng lại! Tất cả những điều này là gì và tại sao chúng ta lại thêm nó?
  • Lombok là một thư viện nhờ đó chúng ta sẽ giảm đáng kể số lượng mã khác nhau. Với nó, chúng ta có thể tự động tạo các hàm tạo, setters, getters và nhiều hơn thế nữa.
  • Spring Data JPAmột framework để làm việc với cơ sở dữ liệu (mặc dù nghe có vẻ quá đơn giản). Mô tả về các khả năng của Spring Data JPA sẽ bao gồm một loạt bài viết và phần phụ thuộc mà chúng tôi đã chỉ định cũng đòi hỏi Hibernate và nhiều hơn thế nữa, vì vậy hãy bỏ qua chi tiết và thử viết thứ gì đó bằng Spring JPA ngay hôm nay.
  • PostgreSQL - chúng tôi lấy thư viện để có trình điều khiển hoạt động với cơ sở dữ liệu của chúng tôi.
Pom.xml của chúng tôi bắt đầu trông như thế này: Thuộc tính: Tạo bot telegram bằng Spring Boot Pt.2: Quiz Bot - 1Phần phụ thuộc: Tạo bot telegram bằng Spring Boot Pt.2: Quiz Bot - 2Nếu bạn chưa đọc bài viết trước, vui lòng lưu ý rằng chúng tôi đang thêm các phần phụ thuộc mới vào đây, vì vậy đây không phải là cấu trúc pom.xml hoàn chỉnh. Đừng quên tải các phần phụ thuộc này vào dự án của chúng ta (ví dụ: bằng cách đi tới cửa sổ Maven -> Nhập lại tất cả các dự án Maven).<h3>Kết nối cơ sở dữ liệu trong IDEA</h3>Nếu bạn sử dụng IDEA Community Edition, bạn có thể bật tab DataSource như sau . Sau khi thêm plugin, chúng ta cần định cấu hình DataSource. Để thực hiện việc này, trước tiên hãy bật hiển thị plugin: Xem -> Công cụ Windows -> Trình duyệt DB. Trong cửa sổ mở ra, nhấp vào dấu cộng màu xanh lục (kết nối mới) -> PostgreSQL. Ở đây chúng tôi sẽ cần thông tin xác thực mà chúng tôi đã thấy trên Heroku. Điền vào cửa sổ: Tạo bot telegram bằng Spring Boot Pt.2: Quiz Bot - 3Và nhấp vào "Kiểm tra kết nối". Nếu mọi thứ được thực hiện chính xác, một cửa sổ bật lên sẽ xuất hiện cho biết kết nối với cơ sở dữ liệu đã thành công. Lưu Nguồn dữ liệu của chúng tôi.<h3>Tạo bảng trong cơ sở dữ liệu</h3>Bây giờ, hãy tạo các bảng mà chúng tôi sẽ làm việc. Đầu tiên, hãy cài đặt PostgreSQL . Sau khi cài đặt, tạo tệp initDB.sql trong thư mục 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
);
Kịch bản của chúng tôi làm gì? Hai dòng đầu tiên xóa các bảng nếu có để tạo lại chúng. Dòng thứ ba tạo một chuỗi sẽ được sử dụng để tạo các mục id duy nhất trong cơ sở dữ liệu của chúng tôi. Tiếp theo chúng ta tạo hai bảng: dành cho người dùng và bảng dành cho câu hỏi. Người dùng sẽ có một id duy nhất, id trò chuyện điện tín, tên, số điểm (hiện tại và tối đa), cũng như trạng thái hiện tại của bot. Các câu hỏi cũng sẽ có một id duy nhất, cũng như các trường chịu trách nhiệm về các tùy chọn câu hỏi và câu trả lời cho nó. Chúng ta có thể thực thi tập lệnh kết quả bằng cách nhấp chuột phải vào tập lệnh đó và chọn "Thực thi tập lệnh SQL". Cần đặc biệt chú ý đến mục “Giao diện dòng Cmd” - ở đây chúng ta sẽ cần PostgreSQL mới được cài đặt. Khi định cấu hình trường này, hãy chọn "Giao diện dòng Cmd mới" và chỉ định đường dẫn đến psql.exe. Do đó, các cài đặt sẽ trông giống như thế này: Tạo bot telegram bằng Spring Boot Pt.2: Quiz Bot - 4Chúng tôi thực thi tập lệnh và nếu chúng tôi không mắc lỗi ở đâu, kết quả công việc của chúng tôi sẽ như sau: Tạo bot telegram bằng Spring Boot Pt.2: Quiz Bot - 8<h3>Tạo mô hình</h3>Bây giờ là lúc để quay lại viết mã Java. Để rút ngắn bài viết, tôi sẽ lược bỏ phần mô tả các chú thích dùng để viết các lớp để các bạn có thể làm quen với chúng. Hãy tạo một gói mô hình trong đó chúng ta sẽ có ba lớp:
  • Tóm tắtBaseEntity là một lớp mô tả bất kỳ đối tượng nào có thể có id (lớp này là sự đơn giản hóa mạnh mẽ những gì bạn có thể thấy trong quá trình thực tập):
    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() {
        }
    }
  • Người dùng :
    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;
        }
    }
  • Lớp câu hỏi :
    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>Tạo kho lưu trữ</h3>Bây giờ chúng ta hãy viết kho lưu trữ Spring Data Jpa. Chúng tôi tạo một gói kho lưu trữ sẽ có hai giao diện : JpaUserRepository, JpaQuestionRepository. Chúng sẽ kế thừa từ JpaRepository, một giao diện Spring Data cho phép chúng ta tạo ra phép thuật một cách thực tế. Để hiểu công việc của họ, tôi khuyên bạn nên xem video của Evgeny Borisov . Các lớp học sẽ rất nhỏ:
  • Kho lưu trữ người dùng Jpa:
    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,>
  • Kho lưu trữ JpaQuestion:
    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>Thêm chức năng cho cả hai</h3>Trong lớp Người dùng , chúng ta có một trường thuộc lớp Trạng thái chưa được tạo , trường này sẽ cho chúng ta biết người dùng hiện đang ở giai đoạn làm việc nào với bot. Hãy tạo nó trong gói /bot:
package com.whiskels.telegram.bot;

public enum State {
    NONE,
    START,
    ENTER_NAME,
    PLAYING_QUIZ,
}
Tiếp theo, chúng ta sẽ tạo một gói bot/handler trong đó chúng ta sẽ khai báo giao diện trình xử lý:
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<?>
Chúng ta sẽ tạo các trình xử lý sau đó một chút, nhưng bây giờ hãy ủy thác việc xử lý sự kiện cho lớp UpdateReceiver mới mà chúng ta sẽ tạo trong thư mục gốc của gói bot: CHÚ Ý! Ở đây và hơn thế nữa sẽ có các phương thức được hiển thị dưới dạng List> Handle(args); trong thực tế chúng trông như thế này, nhưng trình định dạng mã đã phá vỡ chúng:Tạo bot telegram bằng 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>
Và chúng tôi ủy quyền xử lý nó trong lớp 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<?>
Bây giờ bot của chúng tôi ủy quyền xử lý sự kiện cho lớp UpdateReceiver , nhưng chúng tôi chưa có bất kỳ trình xử lý nào. Hãy tạo ra chúng! TUYÊN BỐ TỪ CHỐI TRÁCH NHIỆM! Tôi thực sự muốn chia sẻ khả năng viết một bot như vậy, để mã tiếp theo (về nguyên tắc là mã UpdateReceiver) có thể được tái cấu trúc rất tốt bằng cách sử dụng nhiều mẫu khác nhau. Nhưng chúng tôi đang học và mục tiêu của chúng tôi là một bot khả thi ở mức tối thiểu, vì vậy, như một bài tập về nhà khác, bạn có thể cấu trúc lại mọi thứ bạn đã thấy :) Tạo một gói tiện ích và trong đó - lớp 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);
    }
}
Chúng tôi sẽ viết bốn trình xử lý: 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<?>
Trình xử lý đăng ký:
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<?>
Trình xử lý trợ giúp:
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 (tệ nhất
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION