Easy and modern Java Telegram bot API
- Setup Environment
- Your First Echo Bot
- Available Types
- Available Methods
- Listening Updates
- Filtering Updates
- Types of Handlers
- Markup
- Inline Bot
- Advanced Usages
- Error Handling
- Installation using maven
<dependecy>
<groupId>et.telebof</groupId>
<artifactId>telegrambot</artifactId>
<version>1.5.0</version>
</dependecy>
import et.telebof.BotClient;
public class MyFirstEchoBot {
static final String TOKEN = "YOUR BOT TOKEN HERE";
public static void main(String[] args) {
final BotClient bot = new BotClient(TOKEN);
// Listening for /start command
bot.onMessage(filter -> filter.commands("start"), (context, message) -> {
context.reply("Welcome!").exec();
});
// Listening for any text
bot.onMessage(filter -> filter.TEXT, (context, message) -> {
context.reply(message.text).exec();
});
bot.start(); // finally run the bot
}
}Do not worry if you do not understand what the above code mean, it will be explained in the next chapter.
All Telegram types are defined in et.telebof.types. And they are completely the same as Telegram types.
All Telegram methods are defined in et.telebof.request and implemented in et.telebof.BotContext class.
These methods can be used in 2 ways: Inside handler using context parameter and Outside handler using bot.context instance.
No need to pass chat_id or user_id to the methods need it as argument
chat_id or user_id must be passed to the methods need it as argument
/* Inside Handler */
// send message
context.sendMessage("Hello, World").exec(); // or
context.sendMessage(message.chat.id, "Hello, World").exec();
// send Photo
context.sendPhoto(new File("photo.png")).exec(); // or
context.sendPhoto(message.chat.id, new File("photo.png")).exec();
/* Outside Handler */
bot.context.sendMessage(123456789L, "Hello, World").exec();
bot.context.sendPhoto(123456789L, new File("photo.png")).exec();Assume that in our examples it is inside handler
Update is an event that bot receives like incoming messages, pressing button.
Updates are handled by registering one or more callback classes.
Each update has its own handler. These handlers take two parameters as argument: filter class
and callback class. The filter class is a lambda class of et.telebof.filter.FilterExecutor takes et.telebof.filter.Filter
as an argument and returns Boolean, so that if the condition of this filter
matches with the update sent from telegram, the callback class will be called and its body gets execute.
The callback class takes two parameters: BotContext class and type of class of an update which is being handled
Let's back to the first echo bot example.
import et.telebof.BotClient;
public class MyFirstEchoBot {
static final String TOKEN = "YOUR BOT TOKEN HERE";
public static void main(String[] args) {
final BotClient bot = new BotClient(TOKEN);
bot.onMessage(filter -> filter.commands("start"), (context, message) -> {
context.reply("Welcome!").exec();
});
bot.onMessage(filter -> filter.TEXT, (context, message) -> {
context.reply(message.text).exec();
});
bot.start();
}
}We have two handlers: /start command handler and text handler.
-
The first handler handles
/startcommand and send back a textWelcome!. -
The second handler handles any incoming text and echoes the text.
-
The
replymethod is a shortage ofsendMessageand replies message to thechat_id. -
exec()meaningexecuteis an enclosing and request sender method. This means before ending and sending request, you can pass optional parameters and then send a request to telegram. For examplesendMessagemethod has optional parameters like:parse_mode,reply_markup. So you can pass their value for these parameters and send request to telegram.
import et.telebof.enums.ParseMode;
context.sendMessage("*Hello, World*").parseMode(ParseMode.MARKDOWN).exec();Lastly we start our bot by using start() which does not take any parameter and run our bot via long polling.
IMPORTANT: All handlers are handled in the order in which they were registered.
In previous topic we have seen how to create handlers and how they work. In this section we will talk about how filters work and how we use them.
As previously discussed, all handlers take two parameters: filter class and callback class. These filter classes are used for filtering content of updates and separate the same update by content they hold.
filter.TEXT- filter filedmessage.textfiler.PHOTO- filter fieldmessage.photois not nullfilter.VIDEO- filter fieldmessage.videois not nullfilter.VOICE- filter fieldmessage.voiceis not nullfilter.AUDIO- filter fieldmessage.audiois not nullfilter.ANIMATION- filter fieldmessage.animaionis not nullfilter.DOCUMENT- filter fieldmessage.documentis not nullfilter.VIDEO_NOTE- filter fieldmessage.video_noteis not nullfilter.CONTACT- filter fieldmessage.contactis not nullfilter.LOCATION- filter fieldmessage.loactionis not nullfilter.GAME- filter fieldmessage.gameis not nullfilter.VENUE- filter fieldmessage.venueis not nullfilter.STICKER- filter fieldmessage.stickeris not nullfilter.DICE- filter fieldmessage.diceis not nullfilter.MEDIA- filter one of filed of media(photo, video, audio) is not null.filter.PASSPORT_DATA- filter fieldmessage.photois not nullfilter.INVOICE- filter fieldmessage.invoiceis not nullfilter.NEW_CHAT_MEMBER- filter fieldmessage.new_chat_membersis not nullfilter.LEFT_CHAT_MEMBER- filter fieldmessage.lef_chat_memberis not nullfilter.NEW_CHAT_PHOTO- filter fieldmessage.new_chat_photois not nullfilter.NEW_CHAT_TITLE- filter fieldmessage.new_chat_titleis not nullfilter.GROUP_CHAT_CREATED- filter fieldmessage.group_chat_createdis not nullfilter.SUPERGROUP_CHAT_CREATED- filter fieldmessage.supergroup_chat_createdis not nullfilter.CHANNEL_CHAT_CREATED- filter fieldmessage.channel_chat_createdis not nullfilter.MESSAGE_AUTO_DELETE_TIMER_CHANGED- filter fieldmessage.message_auto_timer_changedis not nullfilter.MIGRATED- filter fieldmessage.migrate_from_chat_idormessage.migrate_to_chat_idis not nullfilter.PINNED_MESSAGE- filter fieldmessage.pinned_messageis not nullfilter.SUCCESFULL_PAYMENT- filter fieldmessage.successfull_paymentis not nullfilter.CONNNECTED_WEBSITE- filter fieldmessage.connected_websiteis not nullfilter.PROXIMITY_ALERT_TRIGGERED- filter fieldmessage.proximity_alert_triggedis not nullfilter.FORUM_TOPIC_CREATED- filter fieldmessage.forum_topic_createdis not nullfilter.FORUM_TOPIC_CLOSED- filter fieldmessage.forum_topic_closedis not nullfilter.FORUM_TOPIC_EDITED- filter fieldmessage.forum_topic_editedis not nullfilter.FORUM_TOPIC_REOPNED- filter fieldmessage.forum_topic_reopenedis not nullfilter.WEB_APP_DATA- filter fieldmessage.web_pp_datais not nullfilter.VIDEO_CHAT_STARTED- filter fieldmessage.video_chat_startedis not nullfilter.VIDEO_CHAT_ENDED- filter fieldmessage.video_ehat_endedis not nullfilter.VIDEO_CHAT_PARTICIPANT_INVITED- filter fieldmessage.video_chat_participant_invitedis not nullfilter.VIDEO_CHAT_SCHEDULED- filter fieldmessage.video_chat_scheduledis not nullfilter.FORWARDED- filter fieldmessage.forward_originis not nullfilter.REPLIED- filter fieldmessage.reply_to_messageis not nullfilter.BOT- filter user is bot or filedmessage.from.is_botistruefilter.ZERO_INLINE_QUERY- filter filedinline_query.queryis empty or has no valuefilter.PRIVATE- filter chat type isprivatefilter.GROUP- filter chat type isgroupfilter.SUPERGROUP- filter chat type issupergroupfilter.CHANNEL- filter chat type ischannelfilter.commands(String ... cmds)- filter commands like/start,/help.filter.callbackData(String ... cds)- filter of inline buttons or filedcallback_query.datafilter.inlineQuery(String... iqs)- filter inline query or fieldinline_query.queryfilter.customFilter()- filter given filterfilter.state(String ... names)- filter current state.
// handles incoming texts
bot.onMessage(filter -> filter.TEXT, (context, message) -> {});
// handles incoming photos
bot.onMessage(filter -> filter.PHOTO, (context, message) -> {});
// handles incoming videos
bot.onMessage(filter -> filter.VIDEO, (context, message) -> {});You may want to handle text and photo in one handler or a text in different chats. To do so use logical operators
(&&, ||, !) and combine them together.
Here are some examples
// handles incoming text in private chat
bot.onMessage(filter -> filter.TEXT && filter.PRIVATE, (context, message) -> {});
// handles an incoming text or photo
bot.onMessage(filter -> filter.TEXT || filter.PHOTO, (context, message) -> {});
// handles incoming text in supergroup chat
bot.onMessage(filter -> filter.TEXT && filter.SUPERGROUP, (context, message) -> {});
// handles incoming audio or video in private chat
bot.onMessage(filter -> filter.PRIVATE && (filter.AUDIO || filter.VIDEO), (context, message) -> {});You can write your own filter using filter.customFilter.
This example will show you how you can write filters using et.telebof.filters.CustomFilter and filter.customFilter.
import et.telebof.BotContext;
import et.telebof.filters.CustomFilter;
import et.telebof.handlers.MessageHandler;
import et.telebof.types.Message;
import et.telebof.types.Update;
// Filter whether the incoming message text is number or not.
class IsNumberFilter implements CustomFilter {
@Override
public boolean check(Update update) {
Message message = update.message;
try {
int number = Integer.parseInt(message.text);
return true; // If it is parsed without any error, then it is number
} catch (NumberFormatException e) {
// If the text is not number
return false;
}
}
}
class FilterBot {
static void numberFilter(BotContext context, Message message){
context.sendMessage("It is number").exec();
}
public static void main(String[] args) {
// ...
bot.onMessage(filter -> filter.TEXT && filter.customFilter(new IsNumberFilter()),
FilterBot::numberFilter);
}
}There are some advanced filters for handling incoming command from user, pressing button(callback data), inline query. These are
filter.commands, filter.callbackData and filter.inlineQuery respectively.
Example for handling commands using filter.commands
// handles /start command
bot.onMessage(filter -> filter.commands("start"), (context, message) -> {});
// handles /help command
bot.onMessage(filter -> filter.commands("help"), (context, message) -> {});Example for handling inline button through its callback data using filter.callbackData
// handles inline button which its callback data equals with "a"
bot.onCallback(filter -> filter.callbackData("a"), (context, callback) -> {
context.answer("You pressed A button!").exec();
});Example for handling inline query using filter.inlineQuery
// handles an inline query which its query equals with a word "hello"
bot.onInline(filter -> filter.inlineQuery("hello"), (context, query) -> {});There is another special filter to make conversations with bot called state filter.
bot.onMessage(filter -> filter.commands("start"), (context, message) -> {
context.sendMessage("What is your name?").exec();
bot.setState(message.from.id, "name"); // set our state to `name`. You can set whatever
});
bot.onMessage(filter -> filter.state("name") && filter.TEXT, (context, message) -> {
context.sendMessage(String.format("Your name is %s", message.text)).exec();
context.clearState(message.from.id);
});There are 18 types of updates to be handled
bot.onMessage((context, message) -> {}); bot.onCallback((context, callback) -> {});bot.onInline((context, query) -> {} );bot.onPoll((context, poll) -> {});bot.onPoll((context, poll_answer) -> {});bot.onShipping((context, shipping) -> {});bot.onChannelPost((context, channel_post) -> {});bot.onPreCheckout((context, pre_checkout) -> {});bot.onEditedMessage((context, edited_message) -> {});bot.onEditedChannelPost((context, edited_c) -> {});bot.onMychatMember((context, my_chat) -> {});bot.onChatMember((context, chat_member) -> {});bot.onChosenInlineResult((context, chosen) -> {});bot.onReaction((context, reaction) -> {});bot.onReactionCount((context, reaction_count) -> {});bot.onChatBoost((context, chat_boost) -> {});bot.onRemovedChatBoost((context, removed_chat_boost) -> {});Example for using reply markup
ReplyKeyboardMarkup markup = new ReplyKeyboardMarkup()
.resizeKeyboard(true) // resize keyboard
markup.add("A", "B", "C"); // You can add String or
markup.add("D", "E");
markup.add(new KeyboardButton("F")); // KeybaordButton class
context.sendMssage("Hello, World!").replyMarkup(markup).exec();example for using InlineKeyboardMarkup
InlineKeybaordMarkup inlineMarkup = new InlineKeybaordMarkup();
inlineMarkup.addKeybaord(
new InlineKeybaordButton("A").callbackData("a"),
new InlineKeybaordButton("C").callbackData("b"),
new InlineKeybaordButton("Url").url("www.example.com")
); // 3 keyboards on a row
// also possible
InlineKeybaordMarkup inlineMarkup = new InlineKeybaordMarkup(new InlineKeybaordButton[]{
new InlineKeybaordButton("A").callbackData("a"),
new InlineKeybaordButton("B").callbackData("b")
}, 1); // 1 rowWidth
// also possible
InlineKeybaordMarkup inlineMarkup = new InlineKeybaordMarkup(new InlineKeybaordButton[][]{
new InlineKeybaordButton[]{
new InlineKeybaordButton("A").callbackData("a"),
new InlineKeybaordButton("B").callbackData("b")
}, // 2 rows
new InlineKeyboardButton[]{
new InlineKeyboardButton("Url").url("www.example.com")
} // 1 row
}
);
context.sendMessage("Press one button").replyMarkup(inlineMarkup).exec();context.sendMessage("Can you tell me your name please?")
.replyMarkup(new ForceReply())
.exec();context.sendMessage("There is no reply keyboard now")
.replyMarkup(new RemoveReplyKeybaord())
.exec(); import et.telebof.types.InlineQueryResult;
import et.telebof.types.InlineQueryResultArticle;
import et.telebof.types.InputTextMessageContent;
public class InlineBot {
public static void main(String[] args) {
//...
bot.onInline(filter -> filter.ZERO_INLINE_QUERY, (context, query) -> {
InlineQueryResultArticle article = new InlineQueryResultArticle("1")
.title("Write something")
.description("click here")
.inputTextMessageContent(new InputTextMessageContent("Please write something"));
context.answerInline(new InlineQueryResult[]{article}).exec();
});
}
}import et.telebof.Webhook;
import java.io.File;
class MyWebhookBot {
public static void main(String[] args) {
Webhook webhook = new Webhook("www.example.com", "/bot"); // URL and path respectively
//...
bot.setWebhook(webhook); // set webhook
//...
bot.start(); // start our bot using webhook
}
}import et.telebof.BotClient;
String url = "https://example.com/bot%s/%s";
BotClient bot = new BotClient.Builder(TOKEN)
.localBotApiUrl(url)
.build();You have to log out your bot from the Telegram server before switching to your local API server using bot.context.logOut().exec()
log current status of the bot.
import et.telebof.BotClient;
BotClient bot = new BotClient.Builder(TOKEN)
.log(true)
.build();import et.telebof.BotClient;
import java.net.InetSocketAddress;
import java.net.Proxy;
InetSocketAddress address = new InetSocketAddress(80, "127.97.91"); // port and hostname respectively
Proxy proxy = new Proxy(Proxy.Type.SOCKS, address);
BotClient bot = new BotClient
.Builder(TOKEN)
.proxy(proxy)
.build();import et.telebof.BotClient;
import et.telebof.enums.ParseMode;
import et.telebof.enums.Updates;
BotClient bot = new BotClient.Builder(TOKEN)
.log(true) // Log current status
.skipOldUpdates(false) // Receive updates sent last 24 hours
.parseMode(ParseMode.HTML) // Default parse mode passed to sendXyz methods
.limit(10) // Limiting how many updates should be received at maximum per request
.useTestServer(false) // Using test server
.timeout(30) // timeout
.offset(-1) // offset
.allowedUpdates(Updates.ALL) // Allowed updates
.proxy(null) // proxy
.build(); // build our clientimport et.telebof.TelegramApiException;
try{
context.sendMessage("Hello, World").exec();
} catch(TelegramApiException apiException){
System.out.println(apiException.description);
}