-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Telegrambost springboot mapping starter #1493
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from 16 commits
9a67e3b
122a54c
1548699
7b8c90b
8b1f0cd
f0cf39c
ae6d26c
31e74f4
5b312e2
17e5d4f
7ca4692
1a8c0f9
2333e93
c0285ca
c27ce3a
edf7f83
bdf6955
ca6bd64
8eed278
9c8fe56
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| # Telegram Bot Auto Configuration | ||
|
|
||
| ## Overview | ||
| This module provides auto-configuration for integrating Telegram Long Polling Bots into a Spring Boot application. It simplifies the setup and management of Telegram bots by automatically registering necessary beans and components. | ||
|
|
||
| ## Features | ||
| - Auto-configuration for Telegram Long Polling Bots | ||
| - Spring-managed `SpringLongPollingBot` instances | ||
| - Centralized `BotRequestProcessor` for handling incoming updates | ||
| - Custom annotation-based bot request mapping (`@BotRequestMapping`) | ||
| - Integration with `OkHttpClient` for network communication | ||
|
|
||
| ## Installation | ||
| ### Maven | ||
| Add the following dependency to your `pom.xml`: | ||
|
|
||
| ```xml | ||
| <dependency> | ||
| <groupId>org.telegram</groupId> | ||
| <artifactId>telegrambost-springboot-mapping-starter</artifactId> | ||
| <version>${current.version}</version> | ||
| </dependency> | ||
| ``` | ||
|
|
||
| ### Gradle | ||
| Add the dependency to your `build.gradle`: | ||
|
|
||
| ```gradle | ||
| dependencies { | ||
| implementation 'org.telegram:telegrambost-springboot-mapping-starter:1.0.0' | ||
| } | ||
| ``` | ||
|
|
||
| ## Configuration | ||
| ### Properties | ||
| Define your bot token in `application.yml`: | ||
|
|
||
| ```yaml | ||
| telegram: | ||
| bot: | ||
| token: YOUR_BOT_TOKEN | ||
| ``` | ||
|
|
||
| or in `application.properties`: | ||
|
|
||
| ```properties | ||
| telegram.bot.token=YOUR_BOT_TOKEN | ||
| ``` | ||
|
|
||
| ## Usage | ||
| ### Defining a Bot Request Controller | ||
| To handle bot commands, define a class annotated with `@Component` and use `@BotRequestMapping`: | ||
|
|
||
| ```java | ||
| import com.flux.spring.boot.telegram.mapping.annotation.BotRequestMapping; | ||
| import lombok.extern.slf4j.Slf4j; | ||
| import org.springframework.stereotype.Component; | ||
| import org.telegram.telegrambots.meta.api.objects.Update; | ||
|
|
||
| @Slf4j | ||
| @Component | ||
| public class BotRequestController { | ||
|
|
||
| @BotRequestMapping("/start") | ||
| public void startCommand(Update update) { | ||
| log.info("/start command received from: {}", update.getMessage().getFrom().getUserName()); | ||
| } | ||
|
|
||
| @BotRequestMapping("/help") | ||
| public void helpCommand(Update update) { | ||
| log.info("/help command received from: {}", update.getMessage().getFrom().getUserName()); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Components | ||
| ### `SpringLongPollingBot` | ||
| This interface is implemented as a Spring Bean and manages long polling updates. | ||
|
|
||
| ### `BotRequestProcessor` | ||
| Handles incoming bot updates and routes them to appropriate handlers. | ||
|
|
||
| ### `@BotRequestMapping` | ||
| Custom annotation for defining bot command handlers. | ||
|
|
||
| ## Running the Application | ||
| Start the Spring Boot application as usual: | ||
| ```sh | ||
| mvn spring-boot:run | ||
| ``` | ||
| or | ||
| ```sh | ||
| ./gradlew bootRun | ||
| ``` | ||
|
|
||
| Once the application is running, the bot will listen for incoming Telegram updates and handle commands accordingly. | ||
|
|
||
| ## License | ||
| This project is licensed under the MIT License. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| <?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| <modelVersion>4.0.0</modelVersion> | ||
| <parent> | ||
| <groupId>org.telegram</groupId> | ||
| <artifactId>Bots</artifactId> | ||
| <version>8.2.0</version> | ||
| </parent> | ||
|
|
||
| <artifactId>telegrambost-springboot-mapping-starter</artifactId> | ||
|
|
||
| <properties> | ||
| <spring-boot.version>3.2.3</spring-boot.version> | ||
| <jackson.version>2.17.2</jackson.version> | ||
| </properties> | ||
|
|
||
| <dependencies> | ||
| <dependency> | ||
| <groupId>org.telegram</groupId> | ||
| <artifactId>telegrambots-springboot-longpolling-starter</artifactId> | ||
| <version>${project.version}</version> | ||
| </dependency> | ||
|
|
||
| <dependency> | ||
| <groupId>org.springframework.boot</groupId> | ||
| <artifactId>spring-boot-starter</artifactId> | ||
| </dependency> | ||
|
Comment on lines
+26
to
+29
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| <dependency> | ||
| <groupId>org.projectlombok</groupId> | ||
| <artifactId>lombok</artifactId> | ||
| <scope>provided</scope> | ||
| </dependency> | ||
| </dependencies> | ||
|
|
||
|
|
||
| <dependencyManagement> | ||
| <dependencies> | ||
| <dependency> | ||
| <groupId>org.springframework.boot</groupId> | ||
| <artifactId>spring-boot-dependencies</artifactId> | ||
| <version>${spring-boot.version}</version> | ||
| <type>pom</type> | ||
| <scope>import</scope> | ||
| </dependency> | ||
| </dependencies> | ||
| </dependencyManagement> | ||
|
|
||
| <build> | ||
| <directory>${project.basedir}/target</directory> | ||
| <outputDirectory>${project.build.directory}/classes</outputDirectory> | ||
| <finalName>${project.artifactId}-${project.version}</finalName> | ||
| <testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory> | ||
| <sourceDirectory>${project.basedir}/src/main/java</sourceDirectory> | ||
| <plugins> | ||
| <plugin> | ||
| <artifactId>maven-clean-plugin</artifactId> | ||
| </plugin> | ||
| <plugin> | ||
| <artifactId>maven-assembly-plugin</artifactId> | ||
| </plugin> | ||
| <plugin> | ||
| <groupId>org.apache.maven.plugins</groupId> | ||
| <artifactId>maven-source-plugin</artifactId> | ||
| </plugin> | ||
| <plugin> | ||
| <groupId>org.apache.maven.plugins</groupId> | ||
| <artifactId>maven-dependency-plugin</artifactId> | ||
| </plugin> | ||
| <plugin> | ||
| <groupId>org.apache.maven.plugins</groupId> | ||
| <artifactId>maven-surefire-plugin</artifactId> | ||
| </plugin> | ||
| <plugin> | ||
| <groupId>org.apache.maven.plugins</groupId> | ||
| <artifactId>maven-javadoc-plugin</artifactId> | ||
| </plugin> | ||
| </plugins> | ||
| </build> | ||
|
|
||
| </project> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| package org.telegram.telegrambots.mapping.starter.annotation; | ||
|
|
||
| import org.springframework.core.annotation.AliasFor; | ||
|
|
||
| import java.lang.annotation.ElementType; | ||
| import java.lang.annotation.Retention; | ||
| import java.lang.annotation.RetentionPolicy; | ||
| import java.lang.annotation.Target; | ||
|
|
||
| @Target({ElementType.METHOD}) | ||
| @Retention(RetentionPolicy.RUNTIME) | ||
| public @interface BotRequestMapping { | ||
|
|
||
| @AliasFor("command") | ||
| String[] value() default {}; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| package org.telegram.telegrambots.mapping.starter.config; | ||
|
|
||
| import lombok.AllArgsConstructor; | ||
| import okhttp3.OkHttpClient; | ||
| import org.springframework.beans.factory.ObjectProvider; | ||
| import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; | ||
| import org.springframework.boot.context.properties.EnableConfigurationProperties; | ||
| import org.springframework.context.annotation.Bean; | ||
| import org.springframework.context.annotation.Configuration; | ||
| import org.telegram.telegrambots.longpolling.TelegramBotsLongPollingApplication; | ||
| import org.telegram.telegrambots.longpolling.interfaces.LongPollingUpdateConsumer; | ||
| import org.telegram.telegrambots.longpolling.starter.SpringLongPollingBot; | ||
| import org.telegram.telegrambots.longpolling.starter.TelegramBotInitializer; | ||
| import org.telegram.telegrambots.mapping.starter.core.BotRequestProcessor; | ||
|
|
||
| import java.util.Collections; | ||
| import java.util.List; | ||
|
|
||
| @Configuration | ||
| @AllArgsConstructor | ||
| @EnableConfigurationProperties(TelegramBotProperties.class) | ||
| public class TelegramBotAutoConfiguration { | ||
|
|
||
| @Bean | ||
| @ConditionalOnMissingBean | ||
| public BotRequestProcessor botRequestProcessor() { | ||
| return new BotRequestProcessor(); | ||
| } | ||
|
|
||
| @Bean | ||
| @ConditionalOnMissingBean | ||
| public OkHttpClient okHttpClient() { | ||
| return new OkHttpClient(); | ||
| } | ||
|
Comment on lines
+30
to
+34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is |
||
|
|
||
| @Bean | ||
| public SpringLongPollingBot springLongPollingBot(TelegramBotProperties properties, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would add |
||
| BotRequestProcessor botRequestProcessor) { | ||
| return new SpringLongPollingBot() { | ||
| @Override | ||
| public String getBotToken() { | ||
| return properties.getToken(); | ||
| } | ||
|
|
||
| @Override | ||
| public LongPollingUpdateConsumer getUpdatesConsumer() { | ||
| return updates -> updates.forEach(botRequestProcessor::handleUpdate); | ||
| } | ||
| }; | ||
| } | ||
|
|
||
| @Bean | ||
| @ConditionalOnMissingBean(TelegramBotsLongPollingApplication.class) | ||
| public TelegramBotsLongPollingApplication telegramBotsApplication() { | ||
| return new TelegramBotsLongPollingApplication(); | ||
| } | ||
|
|
||
| @Bean | ||
| @ConditionalOnMissingBean | ||
| public TelegramBotInitializer telegramBotInitializer(TelegramBotsLongPollingApplication telegramBotsApplication, | ||
| ObjectProvider<List<SpringLongPollingBot>> longPollingBots) { | ||
| return new TelegramBotInitializer(telegramBotsApplication, | ||
| longPollingBots.getIfAvailable(Collections::emptyList)); | ||
| } | ||
|
Comment on lines
+52
to
+64
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since |
||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can be a |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| package org.telegram.telegrambots.mapping.starter.config; | ||
|
|
||
| import lombok.Getter; | ||
| import lombok.Setter; | ||
| import org.springframework.boot.context.properties.ConfigurationProperties; | ||
|
|
||
| @Getter | ||
| @Setter | ||
| @ConfigurationProperties(prefix = "telegram.bot") | ||
| public class TelegramBotProperties { | ||
|
|
||
| private String token; | ||
| } |
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| package org.telegram.telegrambots.mapping.starter.core; | ||
|
|
||
| import lombok.extern.slf4j.Slf4j; | ||
| import org.jetbrains.annotations.NotNull; | ||
| import org.springframework.beans.factory.config.BeanPostProcessor; | ||
| import org.springframework.core.annotation.AnnotationUtils; | ||
| import org.springframework.stereotype.Component; | ||
| import org.telegram.telegrambots.mapping.starter.annotation.BotRequestMapping; | ||
| import org.telegram.telegrambots.meta.api.objects.Update; | ||
|
|
||
| import java.lang.reflect.Method; | ||
| import java.util.HashMap; | ||
| import java.util.Map; | ||
|
|
||
| @Slf4j | ||
| @Component | ||
| public class BotRequestProcessor implements BeanPostProcessor { | ||
|
|
||
| private final Map<String, BotHandlerMethod> handlers = new HashMap<>(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would replace |
||
|
|
||
| @Override | ||
| public Object postProcessAfterInitialization(Object bean, @NotNull String beanName) { | ||
| for (Method method : bean.getClass().getDeclaredMethods()) { | ||
| BotRequestMapping annotation = AnnotationUtils.findAnnotation(method, BotRequestMapping.class); | ||
| if (annotation != null) { | ||
| for (String command : annotation.value()) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What will happen if a user creates a method annotated with |
||
| handlers.put(command, new BotHandlerMethod(bean, method)); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we check if a |
||
| log.debug("✅ Registered command handler '{}': {}.{}", command, bean.getClass().getSimpleName(), method.getName()); | ||
| } | ||
| } | ||
| } | ||
| return bean; | ||
| } | ||
|
|
||
| public void handleUpdate(Update update) { | ||
| if (update.hasMessage() && update.getMessage().hasText()) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's |
||
| String text = update.getMessage().getText().trim(); | ||
| BotHandlerMethod handlerMethod = handlers.get(text); | ||
| if (handlerMethod != null) { | ||
| try { | ||
| handlerMethod.invoke(update); | ||
| } catch (Exception e) { | ||
| log.error("Error on calling handler '{}': {}", text, e.getMessage(), e); | ||
| } | ||
| } else { | ||
| log.warn("No handler found for: {}", text); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private record BotHandlerMethod(Object bean, Method method) { | ||
|
|
||
| void invoke(Update update) throws Exception { | ||
| method.invoke(bean, update); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| com.flux.spring.boot.telegram.mapping.config.TelegramBotAutoConfiguration |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo:
telegrambots