ตอนที่ 1 อะโลฮ่า! ในบทความที่แล้วเราได้สร้างบอทธรรมดาที่คอยต้อนรับเราในทุกเหตุการณ์ เราได้เขียนโค้ดไปหลายพันบรรทัดแล้ว และถึงเวลาเพิ่มฟังก์ชันการทำงานที่ซับซ้อนมากขึ้นให้กับบอทของเรา วันนี้เราจะพยายามเขียนบอทง่ายๆ เพื่อที่เราจะได้ฝึกฝนความรู้เกี่ยวกับ Java Core ก่อนการสัมภาษณ์ในเวลาว่าง (น่าแปลกที่ผมไม่พบบอทประเภทนี้สักตัวเดียว) โดยเราจะทำสิ่งต่อไปนี้:
![การสร้างบอทโทรเลขโดยใช้ Spring Boot Pt.2: Quiz Bot - 1]()
![การสร้างบอทโทรเลขโดยใช้ Spring Boot Pt.2: Quiz Bot - 2]()
<h2>ไปกันเลย!</h2><h3>การสร้างฐานข้อมูลบน Heroku</h3>มาเริ่มต้นด้วยการสร้างฐานข้อมูลภายนอกฐานข้อมูลแรกของเรา สำหรับงาน ในพื้นที่ ฉันแนะนำให้ลองใช้pgAdmin แต่ฉันต้องการให้คุณได้รับคำแนะนำจากข้อเท็จจริงที่ว่าในอนาคตคุณจะปรับใช้บอทกับ Heroku เพื่อที่จะได้ไม่ขึ้นอยู่กับเครื่องในพื้นที่ของคุณและสำหรับสิ่งนี้เรามาทำความคุ้นเคยกับบริการนี้กันดีกว่า ขั้นตอน:
การพึ่งพา:
หากคุณไม่ได้อ่านบทความก่อนหน้านี้ โปรดทราบว่าเรากำลังเพิ่มการขึ้นต่อกันใหม่ที่นี่ ดังนั้นนี่ไม่ใช่โครงสร้าง pom.xml ที่สมบูรณ์ อย่าลืมโหลดการขึ้นต่อกันเหล่านี้ลงในโปรเจ็กต์ของเรา (เช่น โดยไปที่หน้าต่าง Maven -> นำเข้าโปรเจ็กต์ Maven ทั้งหมดอีกครั้ง)<h3>การเชื่อมต่อฐานข้อมูลใน IDEA</h3>หากคุณใช้ IDEA Community Edition คุณสามารถทำได้ เปิดใช้งานแท็บแหล่งข้อมูลดังต่อไปนี้ หลังจากเพิ่มปลั๊กอินแล้ว เราจำเป็นต้องกำหนดค่า DataSource ในการดำเนินการนี้ ขั้นแรกให้เปิดใช้งานการแสดงปลั๊กอิน: มุมมอง -> เครื่องมือ Windows -> เบราว์เซอร์ DB ในหน้าต่างที่เปิดขึ้น ให้คลิกเครื่องหมายบวกสีเขียว (การเชื่อมต่อใหม่) -> PostgreSQL ที่นี่เราจะต้องมีข้อมูลรับรองซึ่งเราได้เห็นแล้วใน Heroku กรอกหน้าต่าง:
และคลิก "ทดสอบการเชื่อมต่อ" หากทุกอย่างถูกต้อง หน้าต่างป๊อปอัปจะปรากฏขึ้นเพื่อระบุว่าการเชื่อมต่อกับฐานข้อมูลสำเร็จ บันทึกแหล่งข้อมูลของเรา<h3>สร้างตารางในฐานข้อมูล</h3>ตอนนี้เรามาสร้างตารางที่เราจะใช้งานกันดีกว่า ก่อนอื่น มาติดตั้งPostgreSQLกัน ก่อน หลังการติดตั้ง ให้สร้างไฟล์ initDB.sql ในโฟลเดอร์ src/main/resources:
เรารันสคริปต์ และหากเราไม่ได้ทำผิดพลาดใดๆ ผลลัพธ์ของงานของเราจะเป็นดังนี้:
<h3>สร้างแบบจำลอง</h3>ตอนนี้ถึงเวลาแล้ว เพื่อกลับไปเขียนโค้ด Java หากต้องการย่อบทความให้สั้นลง ฉันจะละคำอธิบายคำอธิบายประกอบที่ใช้ในการเขียนชั้นเรียนเพื่อให้คุณได้ทำความคุ้นเคยกับสิ่งเหล่านี้ มาสร้างแพ็คเกจโมเดลซึ่งเราจะมีสามคลาส:
- เชื่อมต่อฐานข้อมูล Postgres ภายนอกกับ Heroku
- มาเขียนสคริปต์แรกของเราเพื่อเริ่มต้นและเติมฐานข้อมูล
- มาเชื่อมต่อ Spring Boot Data JPA เพื่อทำงานกับฐานข้อมูลกันดีกว่า
- เราใช้สถานการณ์ต่างๆ ของพฤติกรรมบอท



- ลงทะเบียนกับHeroku ;
- ไปที่แดชบอร์ด ของเรา -> ใหม่ -> สร้างแอปใหม่และสร้างแอปพลิเคชันใหม่
- เราเข้าไปในแอปพลิเคชันที่สร้างขึ้นใหม่เราถูกข่มขู่ด้วยปุ่มต่างๆ แต่เรามุ่งเน้นไปที่แผง "ส่วนเสริมที่ติดตั้ง" - ถัดจากนั้นมีปุ่มกำหนดค่าส่วนเสริมให้คลิกมัน
- ป้อน “Heroku Postgres” ลงในการค้นหา เลือกแผน “Hobby Dev - ฟรี” -> ส่งแบบฟอร์มการสั่งซื้อ;
- เปิดฐานข้อมูลที่ได้รับใหม่ -> การตั้งค่า -> ดูข้อมูลรับรอง แท็บนี้จะมีคีย์ของเราสำหรับการเข้าถึงฐานข้อมูล เราจำตำแหน่งของพวกเขาได้ - เราจะต้องให้พวกเขาเชื่อมต่อฐานข้อมูล เช่น แหล่งข้อมูลใน IDEA
- ลอมบอกเป็นห้องสมุดซึ่งทำให้เราสามารถลดจำนวนโค้ดที่แตกต่างกันได้อย่างมาก ด้วยเครื่องมือนี้ เราสามารถสร้าง Constructor, Setters, Getters และอื่นๆ อีกมากมายได้โดยอัตโนมัติ
- Spring Data JPAเป็นเฟรมเวิร์กสำหรับการทำงานกับฐานข้อมูล (แม้ว่าจะฟังดูง่ายเกินไปก็ตาม) คำอธิบายความสามารถของ Spring Data JPA จะเท่ากับบทความหลายชุด และการขึ้นต่อกันที่เราระบุยังรวมถึง Hibernate และอื่นๆ อีกมากมาย ดังนั้น เรามาข้ามรายละเอียดและลองเขียนบางอย่างโดยใช้ Spring JPA เลยวันนี้
- PostgreSQL - เราดึงไลบรารี่เพื่อรับไดรเวอร์ที่จะทำงานกับฐานข้อมูลของเรา



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
);
สคริปต์ของเราทำอะไร? สองบรรทัดแรกจะลบตาราง ถ้ามี เพื่อสร้างใหม่ บรรทัดที่สามสร้างลำดับที่จะใช้เพื่อสร้างรายการรหัสที่ไม่ซ้ำกันในฐานข้อมูลของเรา ต่อไปเราจะสร้างตารางสองตาราง: สำหรับผู้ใช้และสำหรับคำถาม ผู้ใช้จะมีรหัสเฉพาะ รหัสแชทโทรเลข ชื่อ จำนวนคะแนน (ปัจจุบันและสูงสุด) รวมถึงสถานะปัจจุบันของบอท คำถามจะมีรหัสเฉพาะ รวมถึงช่องที่รับผิดชอบตัวเลือกคำถามและคำตอบ เราสามารถรันสคริปต์ผลลัพธ์ได้ด้วยการคลิกขวาที่มันแล้วเลือก "Execute SQL Script" ควรให้ความสนใจเป็นพิเศษกับรายการ "อินเทอร์เฟซ Cmd-Line" - ที่นี่เราจะต้องมี PostgreSQL ที่ติดตั้งใหม่ เมื่อกำหนดค่าฟิลด์นี้ ให้เลือก "อินเทอร์เฟซ Cmd-Line ใหม่" และระบุเส้นทางไปยัง psql.exe ด้วยเหตุนี้ การตั้งค่าควรมีลักษณะดังนี้: 

- 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 + '\'' + '}'; } }
- พื้นที่เก็บข้อมูล JpaUser:
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,>
- พื้นที่เก็บข้อมูล 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,>
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 ใหม่ ซึ่งเราจะสร้างในรูทของแพ็คเกจบอท: ATTENTION! ที่นี่และต่อไปจะมีวิธีการที่แสดงเป็น List> handle(args); ในความเป็นจริงพวกมันมีลักษณะเช่นนี้ แต่ตัวจัดรูปแบบโค้ดทำลายพวกมัน:
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 (ที่แย่ที่สุด
GO TO FULL VERSION