JavaRush /Java 博客 /Random-ZH /使用 Spring Boot 创建电报机器人第 2 部分:测验机器人
Whiskels
第 41 级
Москва

使用 Spring Boot 创建电报机器人第 2 部分:测验机器人

已在 Random-ZH 群组中发布
第 1 部分 阿罗哈! 在上一篇文章中,我们创建了一个简单的机器人来欢迎我们参加任何活动。我们已经编写了数千行代码,是时候向我们的机器人添加更复杂的功能了。今天我们将尝试编写一个简单的机器人,以便在空闲时间我们可以在面试前磨练我们对 Java Core 的知识(令人惊讶的是,我还没有找到这种类型的工作机器人)。为此,我们将执行以下操作:
  • 将外部 Postgres 数据库连接到 Heroku;
  • 让我们编写第一个脚本来初始化和填充数据库;
  • 让我们连接 Spring Boot Data JPA 来处理数据库;
  • 我们实现了机器人行为的各种场景。
如果你对此感兴趣,并且读完这篇文章后你不想扔掉烂番茄,那么请在我的存储库中加一颗星,我会很高兴!如果您有任何疑问,我们将在评论中讨论。这就是我们最终将得到的结果:使用 Spring Boot 创建电报机器人第 2 部分:测验机器人 - 1使用 Spring Boot 创建电报机器人第 2 部分:测验机器人 - 2使用 Spring Boot 创建电报机器人第 2 部分:测验机器人 - 3<h2>那么,我们开始吧!</h2><h3>在 Heroku 上创建数据库</h3>让我们从创建第一个外部数据库开始。对于本地工作,我建议查看pgAdmin。但我希望您遵循以下事实:将来您将把机器人部署到 Heroku,以便它不依赖于您的本地计算机,为此让我们熟悉一下这项服务。程序:
  • 在Heroku上注册;
  • 进入我们的仪表板->新建->创建新应用程序并创建一个新应用程序;
  • 我们进入新创建的应用程序,我们被许多按钮吓到了,但我们专注于“已安装的附加组件”面板 - 旁边有一个配置附加组件按钮,我们单击它;
  • 搜索中输入“Heroku Postgres”,选择“Hobby Dev - Free”计划 -> 提交订单;
  • 打开新获取的数据库->设置->查看凭据。该选项卡将包含用于访问数据库的密钥。我们记住它们的位置 - 我们将需要它们来连接数据库,就像 IDEA 中的 DataSource 一样。
<h3>向 pom.xml 添加依赖项</h3>作为开发机器人的一部分,我们将向 pom 添加以下依赖项:Lombok、Spring Boot Data JPA、PostgreSQL。停止!这一切是什么?我们为什么要添加它?
  • Lombok是一个库,借助它我们将显着减少不同代码的数量。有了它,我们可以自动创建构造函数、setter、getter 等等。
  • Spring Data JPA一个用于处理数据库的框架(尽管听起来太简单)。对 Spring Data JPA 功能的描述将需要一系列文章,而且我们指定的依赖项还需要 Hibernate 等等,所以让我们跳过细节,今天尝试使用 Spring JPA 编写一些东西。
  • PostgreSQL - 我们提取该库以获得可与我们的数据库配合使用的驱动程序。
我们的 pom.xml 开始看起来像这样: 属性:使用 Spring Boot 创建电报机器人第 2 部分:测验机器人 - 1依赖项:使用 Spring Boot 创建电报机器人第 2 部分:测验机器人 - 2如果您没有阅读上一篇文章,请注意我们在这里添加新的依赖项,因此这不是完整的 pom.xml 结构。不要忘记将这些依赖项加载到我们的项目中(例如,通过转到 Maven -> 重新导入所有 Maven 项目窗口)。<h3>在 IDEA 中连接数据库</h3>如果您使用 IDEA 社区版,您可以启用数据源选项卡,如下所示。添加插件后,我们需要配置数据源。为此,首先启用插件显示:视图 -> 工具窗口 -> 数据库浏览器。在打开的窗口中,单击绿色加号(新连接)-> PostgreSQL。这里我们需要凭证,我们已经在 Heroku 上看到过这些凭证。填写窗口:使用 Spring Boot 创建电报机器人第 2 部分:测验机器人 - 3然后单击“测试连接”。如果一切正确,将会出现一个弹出窗口,表明数据库连接成功。保存我们的数据源。<h3>在数据库中创建表</h3>现在让我们创建我们将使用的表。首先,让我们安装PostgreSQL。安装后,在 src/main/resources 文件夹中创建 initDB.sql 文件:
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 interface”项 - 这里我们需要新安装的 PostgreSQL。配置此字段时,选择“新建 Cmd-Line 界面”并指定 psql.exe 的路径。因此,设置应该如下所示:使用 Spring Boot 创建电报机器人第 2 部分:测验机器人 - 4我们执行脚本,如果我们没有在任何地方犯错误,我们的工作结果将如下所示:使用 Spring Boot 创建电报机器人第 2 部分:测验机器人 - 8<h3>创建模型</h3>现在是时候了返回编写 Java 代码。为了缩短本文,我将省略用于编写类的注释的描述,以便您可以熟悉它们。让我们创建一个模型包,其中包含三个类:
  • AbstractBaseEntity是一个类,它描述任何可以有 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 接口,允许我们实际创造魔法。要了解他们的工作,我建议观看Evgeny Borisov 的视频。班级规模将非常小:
  • 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,>
  • Jpa问题存储库:
    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>在User类中,我们有一个尚未创建的State类字段,它将告诉我们用户当前处于使用机器人的哪个阶段。让我们在 /bot 包中创建它:
package com.whiskels.telegram.bot;

public enum State {
    NONE,
    START,
    ENTER_NAME,
    PLAYING_QUIZ,
}
接下来,我们将创建一个 bot/handler 包,在其中声明处理程序接口:
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类,我们将在 bot 包的根目录中创建该类: 注意!这里以及进一步的方法将显示为 List> handle(args); 实际上它们看起来像这样,但是代码格式化程序破坏了它们:使用 Spring Boot 创建电报机器人第 2 部分:测验机器人 - 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类,但我们还没有任何处理程序。让我们来创建它们吧!免责声明!我真的很想分享编写这样一个机器人的可能性,因此可以使用各种模式很好地重构进一步的代码(原则上是 UpdateReceiver 代码)。但我们正在学习,我们的目标是一个最小可行的机器人,因此作为另一项家庭作业,您可以重构您看到的所有内容:) 创建一个 util 包,并在其中 - 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。启动处理程序:
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