Terminal BAEL-6520: Implement Telegram Bot using Spring-boot (#14595)
This commit is contained in:
parent
93988220ea
commit
11c984b995
35
spring-boot-modules/spring-boot-telegram/.gitignore
vendored
Normal file
35
spring-boot-modules/spring-boot-telegram/.gitignore
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
HELP.md
|
||||||
|
target/
|
||||||
|
.mvn
|
||||||
|
mvnw
|
||||||
|
mvnw.cmd
|
||||||
|
!**/src/main/**/target/
|
||||||
|
!**/src/test/**/target/
|
||||||
|
|
||||||
|
### STS ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
45
spring-boot-modules/spring-boot-telegram/pom.xml
Normal file
45
spring-boot-modules/spring-boot-telegram/pom.xml
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>com.baelding</groupId>
|
||||||
|
<artifactId>spring-boot-telegram</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<name>spring-boot-telegram</name>
|
||||||
|
<description>Demo project for Spring Boot with Spring Data Redis</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<artifactId>parent-boot-3</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<relativePath>../../parent-boot-3</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<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>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<java.version>17</java.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,9 @@
|
|||||||
|
package com.baeldung.telegram;
|
||||||
|
|
||||||
|
public class Constants {
|
||||||
|
|
||||||
|
public static final String START_DESCRIPTION = "Starts the bot";
|
||||||
|
|
||||||
|
public static final String CHAT_STATES = "chatStates";
|
||||||
|
public static final String START_TEXT = "Welcome to Baeldung Pizza Bot.\nPlease enter your name";
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package com.baeldung.telegram;
|
||||||
|
|
||||||
|
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ReplyKeyboard;
|
||||||
|
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ReplyKeyboardMarkup;
|
||||||
|
import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.KeyboardRow;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class KeyboardFactory {
|
||||||
|
public static ReplyKeyboard getPizzaToppingsKeyboard() {
|
||||||
|
KeyboardRow row = new KeyboardRow();
|
||||||
|
row.add("Margherita");
|
||||||
|
row.add("Pepperoni");
|
||||||
|
return new ReplyKeyboardMarkup(List.of(row));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ReplyKeyboard getPizzaOrDrinkKeyboard(){
|
||||||
|
KeyboardRow row = new KeyboardRow();
|
||||||
|
row.add("Pizza");
|
||||||
|
row.add("Drink");
|
||||||
|
return new ReplyKeyboardMarkup(List.of(row));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ReplyKeyboard getYesOrNo() {
|
||||||
|
KeyboardRow row = new KeyboardRow();
|
||||||
|
row.add("Yes");
|
||||||
|
row.add("No");
|
||||||
|
return new ReplyKeyboardMarkup(List.of(row));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package com.baeldung.telegram;
|
||||||
|
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.telegram.abilitybots.api.bot.AbilityBot;
|
||||||
|
import org.telegram.abilitybots.api.bot.BaseAbilityBot;
|
||||||
|
import org.telegram.abilitybots.api.objects.Ability;
|
||||||
|
import org.telegram.abilitybots.api.objects.Flag;
|
||||||
|
import org.telegram.abilitybots.api.objects.Reply;
|
||||||
|
import org.telegram.telegrambots.meta.api.objects.Update;
|
||||||
|
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
|
import static org.telegram.abilitybots.api.objects.Locality.USER;
|
||||||
|
import static org.telegram.abilitybots.api.objects.Privacy.PUBLIC;
|
||||||
|
import static org.telegram.abilitybots.api.util.AbilityUtils.getChatId;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class PizzaBot extends AbilityBot {
|
||||||
|
|
||||||
|
private final ResponseHandler responseHandler;
|
||||||
|
|
||||||
|
public PizzaBot(Environment environment) {
|
||||||
|
super(environment.getProperty("BOT_TOKEN"), "baeldungbot");
|
||||||
|
responseHandler = new ResponseHandler(silent, db);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Ability startBot() {
|
||||||
|
return Ability
|
||||||
|
.builder()
|
||||||
|
.name("start")
|
||||||
|
.info(Constants.START_DESCRIPTION)
|
||||||
|
.locality(USER)
|
||||||
|
.privacy(PUBLIC)
|
||||||
|
.action(ctx -> responseHandler.replyToStart(ctx.chatId()))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
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)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long creatorId() {
|
||||||
|
return 1L;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,132 @@
|
|||||||
|
package com.baeldung.telegram;
|
||||||
|
|
||||||
|
import org.telegram.abilitybots.api.db.DBContext;
|
||||||
|
import org.telegram.abilitybots.api.sender.SilentSender;
|
||||||
|
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
|
||||||
|
import org.telegram.telegrambots.meta.api.objects.Message;
|
||||||
|
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ReplyKeyboard;
|
||||||
|
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ReplyKeyboardRemove;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.baeldung.telegram.Constants.START_TEXT;
|
||||||
|
import static com.baeldung.telegram.UserState.*;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void replyToStart(long chatId) {
|
||||||
|
SendMessage message = new SendMessage();
|
||||||
|
message.setChatId(chatId);
|
||||||
|
message.setText(START_TEXT);
|
||||||
|
sender.execute(message);
|
||||||
|
chatStates.put(chatId, AWAITING_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unexpectedMessage(long chatId) {
|
||||||
|
SendMessage sendMessage = new SendMessage();
|
||||||
|
sendMessage.setChatId(chatId);
|
||||||
|
sendMessage.setText("I did not expect that.");
|
||||||
|
sender.execute(sendMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void replyToOrder(long chatId, Message message) {
|
||||||
|
SendMessage sendMessage = new SendMessage();
|
||||||
|
sendMessage.setChatId(chatId);
|
||||||
|
if ("yes".equalsIgnoreCase(message.getText())) {
|
||||||
|
sendMessage.setText("We will deliver it soon. Thank you!\nOrder another?");
|
||||||
|
sendMessage.setReplyMarkup(KeyboardFactory.getPizzaOrDrinkKeyboard());
|
||||||
|
sender.execute(sendMessage);
|
||||||
|
chatStates.put(chatId, FOOD_DRINK_SELECTION);
|
||||||
|
} else if ("no".equalsIgnoreCase(message.getText())) {
|
||||||
|
stopChat(chatId);
|
||||||
|
} else {
|
||||||
|
sendMessage.setText("Please select yes or no");
|
||||||
|
sendMessage.setReplyMarkup(KeyboardFactory.getYesOrNo());
|
||||||
|
sender.execute(sendMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void replyToPizzaToppings(long chatId, Message message) {
|
||||||
|
if ("margherita".equalsIgnoreCase(message.getText())) {
|
||||||
|
promptWithKeyboardForState(chatId, "You selected Margherita Pizza.\nWe will deliver it soon. Thank you!\nOrder again?",
|
||||||
|
KeyboardFactory.getYesOrNo(), AWAITING_CONFIRMATION);
|
||||||
|
} else if ("pepperoni".equalsIgnoreCase(message.getText())) {
|
||||||
|
promptWithKeyboardForState(chatId, "We finished the Pepperoni Pizza.\nSelect another Topping",
|
||||||
|
KeyboardFactory.getPizzaToppingsKeyboard(), PIZZA_TOPPINGS);
|
||||||
|
} else {
|
||||||
|
SendMessage sendMessage = new SendMessage();
|
||||||
|
sendMessage.setChatId(chatId);
|
||||||
|
sendMessage.setText("We don't sell " + message.getText() + " Pizza.\nSelect the toppings!");
|
||||||
|
sendMessage.setReplyMarkup(KeyboardFactory.getPizzaToppingsKeyboard());
|
||||||
|
sender.execute(sendMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void promptWithKeyboardForState(long chatId, String text, ReplyKeyboard YesOrNo, UserState awaitingReorder) {
|
||||||
|
SendMessage sendMessage = new SendMessage();
|
||||||
|
sendMessage.setChatId(chatId);
|
||||||
|
sendMessage.setText(text);
|
||||||
|
sendMessage.setReplyMarkup(YesOrNo);
|
||||||
|
sender.execute(sendMessage);
|
||||||
|
chatStates.put(chatId, awaitingReorder);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void replyToName(long chatId, Message message) {
|
||||||
|
promptWithKeyboardForState(chatId, "Hello " + message.getText() + ". What would you like to have?",
|
||||||
|
KeyboardFactory.getPizzaOrDrinkKeyboard(),
|
||||||
|
UserState.FOOD_DRINK_SELECTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean userIsActive(Long chatId) {
|
||||||
|
return chatStates.containsKey(chatId);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package com.baeldung.telegram;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.telegram.abilitybots.api.bot.AbilityBot;
|
||||||
|
import org.telegram.telegrambots.meta.TelegramBotsApi;
|
||||||
|
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
|
||||||
|
import org.telegram.telegrambots.updatesreceivers.DefaultBotSession;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class SpringBootTelegramApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
ConfigurableApplicationContext ctx = SpringApplication.run(SpringBootTelegramApplication.class, args);
|
||||||
|
try {
|
||||||
|
TelegramBotsApi botsApi = new TelegramBotsApi(DefaultBotSession.class);
|
||||||
|
botsApi.registerBot(ctx.getBean("pizzaBot", AbilityBot.class));
|
||||||
|
} catch (TelegramApiException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.baeldung.telegram;
|
||||||
|
|
||||||
|
public enum UserState {
|
||||||
|
AWAITING_NAME, FOOD_DRINK_SELECTION, PIZZA_TOPPINGS, AWAITING_CONFIRMATION
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
server.port=8081
|
||||||
|
BOT_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
Loading…
x
Reference in New Issue
Block a user