使用 Spring Boot 創建 Telegram 機器人
一、簡介
在本教程中,我們將使用 Spring Boot 創建一個 Telegram 機器人。
Telegram 機器人是一種在 Telegram 消息平台內運行的自動化程序。它利用Telegram Bot API與用戶交互並執行各種任務。我們將使用Java 庫,而不是直接與 API 交互。機器人幫助我們響應用戶命令、提供信息並執行自動化操作。
我們將從設置一個全新的機器人開始,然後繼續描述如何使用 Java 庫來實現簡單的操作。
2. 創建 Telegram 機器人
首先,我們需要在 Telegram 平台上創建一個新的機器人。我們直接使用 Telegram 消息應用程序並在搜索欄中搜索BotFather來完成此操作。打開後,我們將鍵入/newbot
命令來創建機器人並按照 BotFather 的說明進行操作。它會詢問我們要分配給機器人的用戶名,根據 Telegram 的政策,該用戶名需要以bot
結尾:
上面,BotFather 生成了一個令牌,我們必須將其保存在安全的地方,以便稍後用於配置我們的應用程序。
3. 設置應用程序
其次,我們必須有一個要集成 Telegram Bot 的 Spring Boot 項目。我們將修改pom.xml
文件並包含telegrambots-spring-boot-starter
和telegrambots-abilities
庫:
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-spring-boot-starter</artifactId>
<version>6.7.0</version>
</dependency>
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-abilities</artifactId>
<version>6.7.0</version>
</dependency>
在底層, AbilityBot 使用 webhooks 與 Telegrams API 進行通信,但我們不需要擔心這一點。事實上,該庫實現了Telegram Bot API提供的所有接口。
現在,我們可以實現我們的機器人了。
4. 解釋 PizzaBot
我們將實現一個模擬披薩店的簡單機器人,以演示如何使用 Spring Boot 庫。此外,我們將與機器人進行一組預定義的交互:
簡而言之,我們首先詢問用戶的姓名。然後,我們會提示他選擇披薩或飲料。如果是飲料,我們會顯示一條消息,說明我們不出售飲料。否則,我們會向他們詢問披薩的配料。選擇可用的配料後,我們將確認用戶是否想再次訂購。在這種情況下,我們將重複該流程。或者,我們會感謝他們並通過結束消息結束聊天。
5. 配置並註冊 PizzaBot
讓我們首先為我們的新 PizzaShop 配置AbilityBot
:
@Component
public class PizzaBot extends AbilityBot {
private final ResponseHandler responseHandler;
@Autowired
public PizzaBot(Environment env) {
super(env.getProperty("botToken"), "baeldungbot");
responseHandler = new ResponseHandler(silent, db);
}
@Override
public long creatorId() {
return 1L;
}
}
我們在構造函數中讀取作為環境變量注入的botToken
屬性。我們必須保證令牌的安全,不要將其推入代碼庫。在此示例中,我們在運行應用程序之前將其導出到我們的環境中。或者,我們可以在屬性文件中定義它。此外,我們必須提供一個唯一的creatorId
來描述我們的機器人。
此外,我們還擴展了AbilityBot
類,它減少了樣板代碼並通過ReplyFlow
提供狀態機等常用工具。但是,我們將僅使用嵌入式數據庫並在ResponseHandler
內顯式管理狀態:
public class ResponseHandler {
private final SilentSender sender;
private final Map<Long, UserState> chatStates;
public ResponseHandler(SilentSender sender, DBContext db) {
this.sender = sender;
chatStates = db.getMap(Constants.CHAT_STATES);
}
}
5.1. Spring Boot 3 兼容性問題
使用 Spring Boot 版本 3 時,當聲明為@Component
時,庫不會自動配置機器人。因此,我們必須在主應用程序類中手動初始化它:
TelegramBotsApi botsApi = new TelegramBotsApi(DefaultBotSession.class);
botsApi.registerBot(ctx.getBean("pizzaBot", TelegramLongPollingBot.class));
我們創建TelegramBotsApi
的新實例,然後從 Spring 應用程序上下文提供pizzaBot
組件實例。
6. 實現 PizzaBot
Telegram API 非常龐大,並且可能會重複執行新命令。因此,我們使用能力來簡化開發新能力的過程。在設計交互流程時,我們應該考慮最終用戶、必要條件和執行流程。
在我們的 PizzaBot 中,我們將僅使用一個功能來/start
與機器人的對話:
public Ability startBot() {
return Ability
.builder()
.name("start")
.info(Constants.START_DESCRIPTION)
.locality(USER)
.privacy(PUBLIC)
.action(ctx -> responseHandler.replyToStart(ctx.chatId()))
.build();
}
我們使用構建器模式來構建Ability
。首先,我們定義技能的名稱,該名稱與技能的命令相同。其次,我們提供這個新能力的描述字符串。當我們運行/commands
命令來獲取機器人的能力時,這將很有幫助。第三,我們定義機器人的位置和隱私。最後,我們定義收到命令後必須採取的操作。在此示例中,我們將聊天的 id 轉發到ResponseHandler
類。按照上圖的設計,我們將詢問用戶的姓名並將其以其初始狀態保存在地圖中:
public void replyToStart(long chatId) {
SendMessage message = new SendMessage();
message.setChatId(chatId);
message.setText(START_TEXT);
sender.execute(message);
chatStates.put(chatId, AWAITING_NAME);
}
在此方法中,我們創建一個SendMessage
命令並使用sender
執行它。然後,我們將聊天狀態設置為AWAITING_NAME,
表示我們正在等待用戶的名字:
private void replyToName(long chatId, Message message) {
promptWithKeyboardForState(chatId, "Hello " + message.getText() + ". What would you like to have?",
KeyboardFactory.getPizzaOrDrinkKeyboard(),
UserState.FOOD_DRINK_SELECTION);
}
用戶輸入姓名後,我們向他們發送一個ReplyKeyboardMarkup
,提示他們兩個選項:
public static ReplyKeyboard getPizzaToppingsKeyboard() {
KeyboardRow row = new KeyboardRow();
row.add("Margherita");
row.add("Pepperoni");
return new ReplyKeyboardMarkup(List.of(row));
}
這將隱藏鍵盤並向用戶顯示帶有兩個按鈕的界面:
現在,用戶可以選擇我們的披薩店不提供的披薩或飲料。當選擇兩個選項中的任何一個時,Telegram 會發送一條帶有響應的短信。
對於上圖中的所有綠色菱形元素,我們遵循類似的過程。因此,我們這裡不再重複。相反,讓我們專注於處理對按鈕的響應。
7. 處理用戶回复
對於所有傳入消息和聊天的當前狀態,我們在PizzaBot
類中以不同的方式處理響應:
public Reply replyToButtons() {
BiConsumer<BaseAbilityBot, Update> action = (abilityBot, upd) -> responseHandler.replyToButtons(getChatId(upd), upd.getMessage());
return Reply.of(action, Flag.TEXT,upd -> responseHandler.userIsActive(getChatId(upd)));
}
這 。 replyToButtons()
獲取所有TEXT
回复,並將它們與chatId
和傳入的Message
對像一起轉發到ResponseHandler
。然後,在ResponseHandler
內部, .replyToButtons()
方法決定如何處理消息:
public void replyToButtons(long chatId, Message message) {
if (message.getText().equalsIgnoreCase("/stop")) {
stopChat(chatId);
}
switch (chatStates.get(chatId)) {
case AWAITING_NAME -> replyToName(chatId, message);
case FOOD_DRINK_SELECTION -> replyToFoodDrinkSelection(chatId, message);
case PIZZA_TOPPINGS -> replyToPizzaToppings(chatId, message);
case AWAITING_CONFIRMATION -> replyToOrder(chatId, message);
default -> unexpectedMessage(chatId);
}
}
在switch,
我們檢查聊天的當前狀態並相應地回復用戶。例如,當用戶的當前狀態是FOOD_DRINK_SELECTION
時,我們會處理響應並在用戶點擊選項pizza
時轉到下一個狀態:
private void replyToFoodDrinkSelection(long chatId, Message message) {
SendMessage sendMessage = new SendMessage();
sendMessage.setChatId(chatId);
if ("drink".equalsIgnoreCase(message.getText())) {
sendMessage.setText("We don't sell drinks.\nBring your own drink!! :)");
sendMessage.setReplyMarkup(KeyboardFactory.getPizzaOrDrinkKeyboard());
sender.execute(sendMessage);
} else if ("pizza".equalsIgnoreCase(message.getText())) {
sendMessage.setText("We love Pizza in here.\nSelect the toppings!");
sendMessage.setReplyMarkup(KeyboardFactory.getPizzaToppingsKeyboard());
sender.execute(sendMessage);
chatStates.put(chatId, UserState.PIZZA_TOPPINGS);
} else {
sendMessage.setText("We don't sell " + message.getText() + ". Please select from the options below.");
sendMessage.setReplyMarkup(KeyboardFactory.getPizzaOrDrinkKeyboard());
sender.execute(sendMessage);
}
}
另外,裡面。 replyToButtons()
,我們立即檢查用戶是否發送了/stop
命令。在這種情況下,我們停止聊天並從chatStates
映射中刪除chatId
:
private void stopChat(long chatId) {
SendMessage sendMessage = new SendMessage();
sendMessage.setChatId(chatId);
sendMessage.setText("Thank you for your order. See you soon!\nPress /start to order again");
chatStates.remove(chatId);
sendMessage.setReplyMarkup(new ReplyKeyboardRemove(true));
sender.execute(sendMessage);
}
這將從數據庫中刪除用戶的狀態。要再次交互,用戶必須編寫/start
命令。
八、結論
在本教程中,我們討論了使用 Spring Boot 實現 Telegram 機器人。
首先,我們使用 BotFather 在 Telegram 平台上創建了一個新的機器人。其次,我們設置了 Spring Boot 項目並解釋了 PizzaBot 的功能以及它如何與用戶交互。然後,我們使用簡化新命令開發的功能來實現 PizzaBot。最後,我們處理了用戶的回复,並根據聊天狀態提供了適當的響應。
與往常一樣,本文的源代碼可以 在 GitHub 上獲取。