I’m new to spring boot and webhooks and I can’t put the project together, I collected this monster piece by piece on the Internet to figure out how it all works, I’ve been doing my own research for two weeks now but there’s no result, I’m turning to my colleagues for help. Here's the code, don't judge too harshly: - The purpose of the bot is to greet, request a link from the user and make and send a QR code in response
Main class
package com.xakerz.QrCode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan(basePackages = "com.xakerz.QrCode")
public class QrCodeApplication {
public static void main(String[] args) {
SpringApplication.run(QrCodeApplication.class, args);
}
}
WebHookController
package com.xakerz.QrCode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan(basePackages = "com.xakerz.QrCode")
public class QrCodeApplication {
public static void main(String[] args) {
SpringApplication.run(QrCodeApplication.class, args);
}
}
AppConfig
package com.xakerz.QrCode;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.telegram.telegrambots.meta.api.methods.updates.SetWebhook;
@Configuration
public class AppConfig {
private final TelegramBotConfig botConfig;
public AppConfig(TelegramBotConfig botConfig) {
this.botConfig = botConfig;
}
@Bean
public SetWebhook setWebhookInstance() {
return SetWebhook.builder().url(botConfig.getWebHookPath()).build();
}
@Bean
public QrCode springWebhookBot(SetWebhook setWebhook, TelegramFacade telegramFacade) {
QrCode bot = new QrCode(telegramFacade, setWebhook);
bot.setBotToken(botConfig.getBotToken());
bot.setBotUsername(botConfig.getUserName());
bot.setBotPath(botConfig.getWebHookPath());
return bot;
}
}
Bot config
package com.xakerz.QrCode;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.experimental.FieldDefaults;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component // Добавьте аннотацию @Component
@Getter
@FieldDefaults(level = AccessLevel.PRIVATE)
public class TelegramBotConfig {
@Value("${telegrambot.webHookPath}")
String webHookPath;
@Value("${telegrambot.userName}")
String userName;
@Value("${telegrambot.botToken}")
String botToken;
public void setWebHookPath(String webHookPath) {
this.webHookPath = webHookPath;
}
public void setUserName(String userName) {
this.userName = userName;
}
public void setBotToken(String botToken) {
this.botToken = botToken;
}
public String getWebHookPath() {
return webHookPath;
}
public String getUserName() {
return userName;
}
public String getBotToken() {
return botToken;
}
}
Aplication
package com.xakerz.QrCode;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.FieldDefaults;
import net.glxn.qrgen.QRCode;
import net.glxn.qrgen.image.ImageType;
import org.springframework.beans.factory.annotation.Autowired;
import org.telegram.telegrambots.bots.DefaultBotOptions;
import org.telegram.telegrambots.bots.TelegramWebhookBot;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.methods.send.SendAudio;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.methods.send.SendPhoto;
import org.telegram.telegrambots.meta.api.methods.updates.SetWebhook;
import org.telegram.telegrambots.meta.api.objects.InputFile;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.InlineKeyboardMarkup;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.InlineKeyboardButton;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
@FieldDefaults(level = AccessLevel.PRIVATE)
public class QrCode extends TelegramWebhookBot {
String botPath;
String botUsername;
String botToken;
int count = 0;
private final TelegramBotConfig telegramBotConfig = new TelegramBotConfig();
private TelegramFacade telegramFacade;
@Autowired
public QrCode(TelegramFacade telegramFacade, DefaultBotOptions options, SetWebhook setWebhook) {
super(options, String.valueOf(setWebhook));
this.telegramFacade = telegramFacade;
}
@Autowired
public QrCode(TelegramFacade telegramFacade, SetWebhook setWebhook) {
super(String.valueOf(setWebhook));
this.telegramFacade = telegramFacade;
}
@Override
public String getBotUsername() {
return telegramBotConfig.getUserName();
}
@Override
public String getBotToken() {
return telegramBotConfig.getBotToken();
}
@Override
public BotApiMethod<?> onWebhookUpdateReceived(Update update) {
Message message = update.getMessage();
if (update.hasMessage() && update.getMessage().hasText() && update.getMessage().getText().equals("/start")) {
long id = message.getChatId();
sendTextMessage(id, "Теперь можно отправить ссылку и бот сделает QrCode для неё.");
} else if (update.hasMessage() && update.getMessage().hasText() && !update.getMessage().getText().equals("/start")) {
long id = message.getChatId();
sendTextMessage(id, " ✅QrCode успешно создан");
doQrCode(id, update.getMessage().getText());
sendTextMessage(id, "Создадим еще один❔");
count++;
if ((count & 3) == 0){
sendTextMessage(id, "В благодарность ты можешь подписаться на два моих канала ---> https://t.me/CalmHorizons и ");
}
}
return telegramFacade.handleUpdate(update);
}
private void messageText(Long chatId, String newTextForMessage, String newTextForButtonOne, String newTextForCallbackOne, String newTextForButtonTwo, String newTextForCallbackTwo) {
SendMessage sendMessage = new SendMessage();
sendMessage.setChatId(chatId);
sendMessage.setText(newTextForMessage);
sendMessage.setReplyMarkup(getInlineKeyboard(newTextForButtonOne, newTextForButtonTwo, newTextForCallbackOne, newTextForCallbackTwo));
try {
execute(sendMessage);
} catch (TelegramApiException e) {
System.out.println(e.getMessage());
}
}
private InlineKeyboardMarkup getInlineKeyboard(String newTextForButtonOne, String newTextForButtonTwo, String newTextForCallbackOne, String newTextForCallbackTwo) {
InlineKeyboardMarkup markup = new InlineKeyboardMarkup();
List<List<InlineKeyboardButton>> keyboard = new ArrayList<>();
List<InlineKeyboardButton> row = new ArrayList<>();
List<InlineKeyboardButton> row1 = new ArrayList<>();
InlineKeyboardButton inlineKeyboardButton = new InlineKeyboardButton();
inlineKeyboardButton.setText(newTextForButtonOne);
inlineKeyboardButton.setCallbackData(String.valueOf(newTextForCallbackOne));
row.add(inlineKeyboardButton);
InlineKeyboardButton inlineKeyboardButton1 = new InlineKeyboardButton();
inlineKeyboardButton1.setText(newTextForButtonTwo);
inlineKeyboardButton1.setCallbackData(String.valueOf(newTextForCallbackTwo));
row.add(inlineKeyboardButton1);
keyboard.add(row);
keyboard.add(row1);
markup.setKeyboard(keyboard);
return markup;
}
private void sendTextMessage(long chatId, String textMessage) {
SendMessage sendMessage = new SendMessage();
sendMessage.setChatId(chatId);
sendMessage.setText(textMessage);
try {
execute(sendMessage);
} catch (TelegramApiException e) {
throw new RuntimeException(e);
}
}
private void sendAudio(long chatId, String pathToAudioFile) {
SendAudio sendAudio = new SendAudio();
sendAudio.setChatId(chatId);
InputFile audio = new InputFile(pathToAudioFile);
sendAudio.setAudio(audio);
try {
execute(sendAudio);
} catch (TelegramApiException e) {
throw new RuntimeException(e);
}
}
private SendPhoto sendPhotoMessage(long chatId, File file) {
SendPhoto sendPhoto = new SendPhoto();
InputFile inputFile = new InputFile(String.valueOf(file));
sendPhoto.setChatId(chatId);
sendPhoto.setPhoto(inputFile);
return sendPhoto;
}
public void doQrCode(long id, String str) {
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
QRCode.from(str).withCharset(StandardCharsets.UTF_8.name()).withSize(250, 250).to(ImageType.PNG).writeTo(outputStream);
File file = File.createTempFile("qrcode", ".png");
try (FileOutputStream fos = new FileOutputStream(file)) {
outputStream.writeTo(fos);
}
SendPhoto sendPhoto = new SendPhoto();
sendPhoto.setChatId(id);
sendPhoto.setPhoto(new InputFile(file));
try {
execute(sendPhoto);
} catch (TelegramApiException e) {
e.printStackTrace();
}
// Удаляем временный файл после отправки
file.delete();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public String getBotPath() {
return telegramBotConfig.getWebHookPath();
}
public void setBotToken(String botToken) {
}
public void setBotUsername(String userName) {
}
public void setBotPath(String webHookPath) {
}
}
class for more detailed processing - not yet used
package com.xakerz.QrCode;
import lombok.AccessLevel;
import lombok.experimental.FieldDefaults;
import org.springframework.stereotype.Component;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.objects.CallbackQuery;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.Update;
@Component
@FieldDefaults(level = AccessLevel.PRIVATE)
public class TelegramFacade {
public BotApiMethod<?> handleUpdate(Update update) {
if (update.hasCallbackQuery()) {
CallbackQuery callbackQuery = update.getCallbackQuery();
return null;
} else {
Message message = update.getMessage();
SendMessage sendMessage = new SendMessage();
sendMessage.setChatId(String.valueOf(message.getChatId()));
if (message.hasText()) {
sendMessage.setText("Hello world");
return sendMessage;
}
}
return null;
}
}
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.0-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.xakerz</groupId>
<artifactId>QrCode</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>QrCode</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>21</java.version>
</properties>
<dependencies>
<!-- Оставляем только одну зависимость spring-boot-starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
</dependency>
<!-- Удаляем дублирующуюся зависимость -->
<!-- Удаляем зависимость spring-boot-starter, так как она уже включена в spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots-spring-boot-starter</artifactId>
<version>6.7.0</version>
</dependency>
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots</artifactId>
<version>6.9.7.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.glxn</groupId>
<artifactId>qrgen</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</pluginRepository>
</pluginRepositories>
</project>
it gives the following error -----
2024-02-27T07:42:54.834+03:00 ERROR 23828 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.lang.RuntimeException: Error executing org.telegram.telegrambots.meta.api.methods.send.SendMessage query: [404] Not Found] with root cause
org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException: Error executing org.telegram.telegrambots.meta.api.methods.send.SendMessage query: [404] Not Found at org.telegram.telegrambots.meta.api.methods.PartialBotApiMethod.deserializeResponseInternal(PartialBotApiMethod.java:54) ~[telegrambots-meta-6.9.7.1.jar:na] at org.telegram.telegrambots.meta.api.methods.PartialBotApiMethod.deserializeResponse(PartialBotApiMethod.java:34) ~[telegrambots-meta-6.9.7.1.jar:na] at org.telegram.telegrambots.meta.api.methods.botapimethods.BotApiMethodMessage.deserializeResponse(BotApiMethodMessage.java:20) ~[telegrambots-meta-6.9.7.1.jar:na] at org.telegram.telegrambots.meta.api.methods.botapimethods.BotApiMethodMessage.deserializeResponse(BotApiMethodMessage.java:15) ~[telegrambots-meta-6.9.7.1.jar:na] at org.telegram.telegrambots.bots.DefaultAbsSender.sendApiMethod(DefaultAbsSender.java:1182) ~[telegrambots-6.9.7.1.jar:na] at org.telegram.telegrambots.meta.bots.AbsSender.execute(AbsSender.java:61) ~[telegrambots-meta-6.9.7.1.jar:na] at com.xakerz.QrCode.QrCode.sendTextMessage(QrCode.java:138) ~[classes/:na] at com.xakerz.QrCode.QrCode.onWebhookUpdateReceived(QrCode.java:77) ~[classes/:na] at com.xakerz.QrCode.WebhookController.onUpdateReceived(WebhookController.java:30) ~[classes/:na] at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na] at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:259) ~[spring-web-6.1.4.jar:6.1.4] at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:192) ~[spring-web-6.1.4.jar:6.1.4] at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) ~[spring-webmvc-6.1.4.jar:6.1.4] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:920) ~[spring-webmvc-6.1.4.jar:6.1.4] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:830) ~[spring-webmvc-6.1.4.jar:6.1.4] at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-6.1.4.jar:6.1.4] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) ~[spring-webmvc-6.1.4.jar:6.1.4] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) ~[spring-webmvc-6.1.4.jar:6.1.4] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) ~[spring-webmvc-6.1.4.jar:6.1.4] at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914) ~[spring-webmvc-6.1.4.jar:6.1.4] at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590) ~[tomcat-embed-core-10.1.19.jar:6.0] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) ~[spring-webmvc-6.1.4.jar:6.1.4] at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) ~[tomcat-embed-core-10.1.19.jar:6.0] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205) ~[tomcat-embed-core-10.1.19.jar:10.1.19] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.19.jar:10.1.19] at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) ~[tomcat-embed-websocket-10.1.19.jar:10.1.19] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.19.jar:10.1.19] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.19.jar:10.1.19] at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-6.1.4.jar:6.1.4] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.4.jar:6.1.4] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.19.jar:10.1.19] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.19.jar:10.1.19] at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-6.1.4.jar:6.1.4] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.4.jar:6.1.4] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.19.jar:10.1.19] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.19.jar:10.1.19] at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-6.1.4.jar:6.1.4] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.4.jar:6.1.4] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.19.jar:10.1.19] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.19.jar:10.1.19] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167) ~[tomcat-embed-core-10.1.19.jar:10.1.19] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) ~[tomcat-embed-core-10.1.19.jar:10.1.19] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482) ~[tomcat-embed-core-10.1.19.jar:10.1.19] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115) ~[tomcat-embed-core-10.1.19.jar:10.1.19] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[tomcat-embed-core-10.1.19.jar:10.1.19] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-10.1.19.jar:10.1.19] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344) ~[tomcat-embed-core-10.1.19.jar:10.1.19] at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391) ~[tomcat-embed-core-10.1.19.jar:10.1.19] at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-10.1.19.jar:10.1.19] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:896) ~[tomcat-embed-core-10.1.19.jar:10.1.19] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1744) ~[tomcat-embed-core-10.1.19.jar:10.1.19] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-10.1.19.jar:10.1.19] at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-10.1.19.jar:10.1.19] at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-10.1.19.jar:10.1.19] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63) ~[tomcat-embed-core-10.1.19.jar:10.1.19] at java.base/java.lang.Thread.run(Thread.java:1583) ~[na:na]
I tried different settings for annotations, collected the code piece by piece, but I can’t understand what’s wrong with the code