JavaRush /Java Blog /Random EN /Creating a Telegram bot in Java: from idea to deployment
John Watson
Level 27

Creating a Telegram bot in Java: from idea to deployment

Published in the Random EN group
What are bots anyway? You can read about this in detail here . First, you need to read the official documentation for the library for developing bots on Telegram (hereinafter referred to as API). She lies here . Creating a Telegram bot in Java: from idea to deployment - 1Everything there is very accessible and understandable. It would seem that write and rejoice! But it's not that simple. After spending a lot of time in search engines, I found snippets of knowledge on bot development, for example, how to make a keyboard, process CallbackQuery, and the like. I have never found a complete and comprehensive guide for developing bots in Java. This prompted me to write this article. There are many sites on the Internet where you can create your own bot with a ready-made deployment. But the point is. that for the most part, bots are created that can provide background information and so on. Our bot is a full-fledged web application to which you can bind a database, make requests to various APIs, parse sites, perform complex calculations, etc. The matter is limited only by your imagination. I hope that in these lines I have explained to you a little what I am going to write about. Registering a bot in Telegram is very simple; this process is described in detail in the documentation at the link above. For our application you only need to know the name of the bot and the token that you will receive upon registration. Essentially, a bot is just a console web application. No frontend, pure command processing. If you want to master Hibernate well or learn how to parse JSON, then this project is for you. Let's start by including the dependency in pom.xml (we assume that you are using Maven). You can do it like this:
<dependency>
            <groupId>org.telegram</groupId>
            <artifactId>telegrambots</artifactId>
            <version>3.5</version>
</dependency>
Then we create a class Bot, inherit it from the class TelegramLongPollingBot, overriding its methods:
public class Bot extends TelegramLongPollingBot {

    /**
     * Method for receiving messages.
     * @param update Contains a message from the user.
     */
    @Override
    public void onUpdateReceived(Update update) {
	String message = update.getMessage().getText();
	sendMsg(update.getMessage().getChatId().toString(), message);
    }

    /**
     * Method for setting up a message and sending it.
     * @param chatId chat id
     * @param s The string to send as a message.
     */
    public synchronized void sendMsg(String chatId, String s) {
        SendMessage sendMessage = new SendMessage();
        sendMessage.enableMarkdown(true);
        sendMessage.setChatId(chatId);
        sendMessage.setText(s);
        try {
            sendMessage(sendMessage);
        } catch (TelegramApiException e) {
            log.log(Level.SEVERE, "Exception: ", e.toString());
        }
    }

    /**
     * The method returns the name of the bot specified during registration.
     * @return bot name
     */
    @Override
    public String getBotUsername() {
        returnBotName;
    }

    /**
     * The method returns the bot's token to communicate with the Telegram server
     * @return token for the bot
     */
    @Override
    public String getBotToken() {
        returnBotToken;
    }
}
Well, the contents of the method main:
public static void main(String[] args) {
        ApiContextInitializer.init();
        TelegramBotsApi telegramBotsApi = new TelegramBotsApi();
        try {
            telegramBotsApi.registerBot(Bot.getBot());
        } catch (TelegramApiRequestException e) {
            e.printStackTrace();
        }
}
By entering it into the methods getBotUsername(), getBotToken()we launch the bot. For now, he only redirects to us any messages that we send to him, a kind of “mirror”. It all works as follows: when you launch the application, it starts sending a GET request to the Telegram server once every n number of seconds at the following URL: https://api.telegram.org/BotToken/getMe, where BotToken is the token of your bot, receiving into a JSON response containing all the messages. Each such message is processed by the library and comes to the method OnUpdateReceived(Update update)as an object Update. That's what we work with. This is the beauty of Telegram bots, they can work on any computer, for testing you just need to launch the application, you do not need to deploy it to the hosting after each change. It is very comfortable. Of course, the bot can be configured to work using a webhook; the manual can be found on the Internet; for simplicity, we will work using LongPolling. How to process messages and what to send in response is limited only by the language tools and the library, everything else is at your discretion. You can make a bot that will search for videos on YouTube for you, you can make a bot that every day will send you what you send to yourself, for example, in a year, a kind of time capsule. Or you can learn how to integrate into CRM systems and make bots for small businesses, everything is limited by your imagination. Go ahead. Those who have used bots know that it is convenient to interact with them using commands starting with the sign «/», for example /start. But there is a more convenient way - buttons. There are two kinds of buttons: those that appear below the input field, ReplyKeyboardMarkupand buttons that appear directly below the message to which they are linked InlineKeyboardMarkup. In the documentation you can briefly familiarize yourself with their description. ReplyKeyboardMarkup. Essentially this is an array of button arrays, List<KeyboardRow<KeyboardButton>>. Here is an example code that creates the keyboard
public synchronized void setButtons(SendMessage sendMessage) {
        // Create a keyboard
        ReplyKeyboardMarkup replyKeyboardMarkup = new ReplyKeyboardMarkup();
        sendMessage.setReplyMarkup(replyKeyboardMarkup);
        replyKeyboardMarkup.setSelective(true);
        replyKeyboardMarkup.setResizeKeyboard(true);
        replyKeyboardMarkup.setOneTimeKeyboard(false);

        // Create a list of keyboard strings
        List<KeyboardRow> keyboard = new ArrayList<>();

        // First line of the keyboard
        KeyboardRow keyboardFirstRow = new KeyboardRow();
        // Add buttons to the first line of the keyboard
        keyboardFirstRow.add(new KeyboardButton(“Привет”));

        // Second line of the keyboard
        KeyboardRow keyboardSecondRow = new KeyboardRow();
        // Add buttons to the second line of the keyboard
        keyboardSecondRow.add(new KeyboardButton(“Помощь”);

        // Add all keyboard strings to the list
        keyboard.add(keyboardFirstRow);
        keyboard.add(keyboardSecondRow);
        // and set this list to our keyboard
        replyKeyboardMarkup.setKeyboard(keyboard);
    }
In a method sendMsg(), we call this method by passing a message to it, thus setting the keyboard for that message. When we send this message to the user, he will see the message text that we set, as well as 2 buttons that say Hello and Help, next to each other. By clicking on these buttons, a message will be sent to the bot, the text of which is what is written on the button. That is, if the client clicks “Help”, the bot will receive a message with the text “Help”. For him, it’s as if the client himself wrote the text “Help” and sent it to him. Well, then you process such messages. InlineKeyboardMarkup This is also an array of arrays, it is similar to the previous Markup, but the operating logic here is slightly different. Such a keyboard is tied to a specific message and exists only for it. Here is the method to install Inline keyboard
private void setInline() {
        List<List<InlineKeyboardButton>> buttons = new ArrayList<>();
        List<InlineKeyboardButton> buttons1 = new ArrayList<>();
        buttons1.add(new InlineKeyboardButton().setText(“Кнопка“).setCallbackData(17));
        buttons.add(buttons1);

        InlineKeyboardMarkup markupKeyboard = new InlineKeyboardMarkup();
        markupKeyboard.setKeyboard(buttons);
    }
Create Listin List, add an Inline button to the first line. Such a button can contain a URL, a link to a channel, or CallbackQuery, which I will write about a little later. Here we set the text for our button that the user will see and then set the data that will be sent to the bot. In our example, the user sees “Hello”, and when clicked, the bot will be sent the number 17, this is our CallbackQuery. A few words about CallbackQuery. To obtain such data from an object, Updateyou need to execute update.getCallbackQuery(), this method returns CallbackQuery, from which you can already get the data transferred to the bot. There is no need to try to get this data through the method update.getMessage().getText(), get NullPointerException.
@Override
    public void onUpdateReceived(Update update) {
        if(update.hasMessage()) {
            ThreadClass thread = new ThreadClass(update.getMessage());
        } else  if(update.hasCallbackQuery()) {
            AnswerCallbackThread answerThread = new AnswerCallbackThread(update.getCallbackQuery());
        }
    }
If there is a message, we send the message for processing to a new thread; if there is a message CallbackQuery, we send it for processing to the appropriate thread. You CallbackQuerycan send a reply. Each object in Telegram has its own id. To send a response to a specific one, CallbackQuerywe only need to know its id, which we will receive from the corresponding object. To send a response, call this method:
public synchronized void answerCallbackQuery(String callbackId, String message) {
        AnswerCallbackQuery answer = new AnswerCallbackQuery();
        answer.setCallbackQueryId(callbackId);
        answer.setText(message);
        answer.setShowAlert(true);
        try {
            answerCallbackQuery(answer);
        } catch (TelegramApiException e) {
            e.printStackTrace();
        }
    }
IMPORTANT:The text in the answer CallbackQueryshould not be longer than 200 characters! When sending such a response, the client will receive a pop-up window in which the message will be written. Such a window may disappear a few seconds after it appears, or it may hang until the user presses OK. To switch these modes, we call the answer.setShowAlert(true). When truethe window hangs until you press OK, when falseit disappears after 5 seconds. In principle, these are all the basic features of the Telegram bot library. If you wish, you can learn such things as sending multimedia, geolocation, etc. from the documentation. Let's move on to deploying our bot on hosting. For my project, I chose Heroku, because in my opinion it is a fairly convenient hosting that has its own CLI. It is free, but at this rate your bot will go into hibernation after 30 minutes if there are no requests. When a request is sent to him, he wakes up. This happens quite quickly, you won’t even notice (unless, of course, the connection to the database is re-established). The limit on the free plan is 5MB database, 100MB disk space, 2TB traffic per month, 1 dino. Dino is your running application. I’ll say right away that it was the deployment stage that caused difficulties for me, since I had never deployed my applications before. When deploying, Heroku requires a file named Procfile (without extension). worker: sh target/bin/workerBot We create it in the root of the project, write workerBot there - the name that we specify in pom.xml The sh script generated using the Maven plugin appassembler-maven-plugin will be launched. The script describes running the compiled jar. The name of the class to be launched is indicated between <mainClass></mainClass>, the name of the script between <name></name> pom.xml:
...
<build>
    <plugins>
        ...
       <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>appassembler-maven-plugin</artifactId>
            <version>1.1.1</version>
            <configuration>
                <assembleDirectory>target</assembleDirectory>
                <programs>
                    <program>
                        <mainClass>com.home.server.TelegramBot</mainClass>
                        <name>workerBot</name>
                    </program>
                </programs>
            </configuration>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>assemble</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
Before starting this process, you should register on Heroku, install Git and the Heroku CLI. If your application requires a database, then when registering a new application, do not forget to add the database you need. Next, you need to find out the host, username, password and port of your database, and then specify it in your application. Next, before deploying, build your project using Maven.
mvn clean install
To begin, we go to the directory of our project, initialize the repository with the command git init Then we add our project to this repository
git add .
After we commit the changes
git commit -m “First commit in project”
Next you need to log in to heroku, write in the command line
heroku login
Enter your data specified during registration. Then you need to find out the URL of your repository on Heroku, this is done in the settings. Then we write
git remote add heroku [url]
The heroku remote repository will be added to your repository. Next we write
git push heroku master
We are waiting... If the deployment of the application is successful, we execute the command
heroku ps:scale worker=1
And that's it, your application is running. If this does not happen, look carefully at the logs; most likely there is an error in your application that caused it to crash. Thank you for reading such a long article, I hope someone finds it useful and saves a lot of time in places where I stumbled during development.
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION