diff --git a/spring-boot-modules/spring-boot-telegram/.gitignore b/spring-boot-modules/spring-boot-telegram/.gitignore
new file mode 100644
index 0000000000..a8e6c9dbce
--- /dev/null
+++ b/spring-boot-modules/spring-boot-telegram/.gitignore
@@ -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/
diff --git a/spring-boot-modules/spring-boot-telegram/pom.xml b/spring-boot-modules/spring-boot-telegram/pom.xml
new file mode 100644
index 0000000000..b960137449
--- /dev/null
+++ b/spring-boot-modules/spring-boot-telegram/pom.xml
@@ -0,0 +1,45 @@
+
+
+ 4.0.0
+ com.baelding
+ spring-boot-telegram
+ 0.0.1-SNAPSHOT
+ spring-boot-telegram
+ Demo project for Spring Boot with Spring Data Redis
+
+
+ com.baeldung
+ parent-boot-3
+ 0.0.1-SNAPSHOT
+ ../../parent-boot-3
+
+
+
+
+ org.telegram
+ telegrambots-spring-boot-starter
+ 6.7.0
+
+
+ org.telegram
+ telegrambots-abilities
+ 6.7.0
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+ 17
+
+
+
diff --git a/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/Constants.java b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/Constants.java
new file mode 100644
index 0000000000..5c529bf15c
--- /dev/null
+++ b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/Constants.java
@@ -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";
+}
diff --git a/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/KeyboardFactory.java b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/KeyboardFactory.java
new file mode 100644
index 0000000000..367c5a4c7c
--- /dev/null
+++ b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/KeyboardFactory.java
@@ -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));
+ }
+}
diff --git a/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/PizzaBot.java b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/PizzaBot.java
new file mode 100644
index 0000000000..802cb586d7
--- /dev/null
+++ b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/PizzaBot.java
@@ -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 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;
+}
+}
diff --git a/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/ResponseHandler.java b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/ResponseHandler.java
new file mode 100644
index 0000000000..862edc962c
--- /dev/null
+++ b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/ResponseHandler.java
@@ -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 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);
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/SpringBootTelegramApplication.java b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/SpringBootTelegramApplication.java
new file mode 100644
index 0000000000..041478f42b
--- /dev/null
+++ b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/SpringBootTelegramApplication.java
@@ -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);
+ }
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/UserState.java b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/UserState.java
new file mode 100644
index 0000000000..a0b53a6a02
--- /dev/null
+++ b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/UserState.java
@@ -0,0 +1,5 @@
+package com.baeldung.telegram;
+
+public enum UserState {
+ AWAITING_NAME, FOOD_DRINK_SELECTION, PIZZA_TOPPINGS, AWAITING_CONFIRMATION
+}
diff --git a/spring-boot-modules/spring-boot-telegram/src/main/resources/application.properties b/spring-boot-modules/spring-boot-telegram/src/main/resources/application.properties
new file mode 100644
index 0000000000..6b2753c3a8
--- /dev/null
+++ b/spring-boot-modules/spring-boot-telegram/src/main/resources/application.properties
@@ -0,0 +1,2 @@
+server.port=8081
+BOT_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
\ No newline at end of file