@Override
public void onUpdateReceived(Update update) {
UpdatesReceiver.handleUpdates(update);
}
جنهن کي مان هينڊلر ڏانهن موڪليان ٿو (پنهنجي UpdatesReceiver ڪلاس):
public static void handleUpdates(Update update) {
...
if (update.hasMessage() && update.getMessage().hasText()){
log.info("[Update (id {}) типа \"Текстовое сообщение\"]", update.getUpdateId());
new TextMessageHandler(update, replyGenerator).handleTextMessage();
}
else if (update.hasCallbackQuery()) {
//логгирование
new CallbackQueryHandler(update, replyGenerator).handleCallBackQuery();
}
else {
//логгирование
replyGenerator.sendTextMessage(update.getMessage().getChatId(), "Я могу принимать только текстовые messages!");
}
}
UpdatesReceiver هڪ مرڪزي هينڊلر آهي، جيڪو تازه ڪاري جي قسم تي منحصر ڪري ٿو، ڪنٽرول کي ٻئي خاص هينڊلر ڏانهن منتقل ڪري ٿو: TextMessageHandler يا CallbackQueryHandler، جن جي تعمير ڪندڙن کي آئون تازه ڪاري جاري ڪريان ٿو چين کي وڌيڪ هيٺ. اپ ڊيٽ سڀ کان اهم شيءِ آهي جڏهن بوٽ سان ڪم ڪيو وڃي ۽ وڃائجي نه ٿو سگهجي، ڇاڪاڻ ته اپڊيٽ ۾ محفوظ ڪيل معلومات جي مدد سان، اسان اهو ڳوليندا آهيون ته ڪهڙي صارف ۽ ڪهڙي چيٽ ڏانهن جواب موڪليو وڃي. صارف کي جواب ڏيڻ لاء، مون هڪ الڳ ڪلاس لکيو. اهو باقاعده ٽيڪسٽ پيغام، ان لائن ڪيبورڊ سان پيغام، تصوير سان پيغام ۽ جوابي ڪيبورڊ سان پيغام موڪلي سگھي ٿو. هڪ ان لائن ڪيبورڊ هن طرح ڏسڻ ۾ اچي ٿو: اهو بٽڻن جي وضاحت ڪري ٿو، انهن تي ڪلڪ ڪندي، صارف سرور ڏانهن هڪ ڪال بڪ موڪلي ٿو، جيڪو تقريبا ساڳئي طريقي سان عمل ڪري سگهجي ٿو جيئن باقاعده پيغامن ۾. ان کي ”برقرار رکڻ“ لاءِ توهان کي پنهنجي سنڀاليندڙ جي ضرورت آهي. اسان هر بٽڻ لاء هڪ عمل مقرر ڪيو، جيڪو پوء اپڊيٽ اعتراض ڏانهن لکيو ويو آهي. اهي. "قيمت" بٽڻ لاءِ اسان ڪال بڪ لاءِ وضاحت "/قيمت" سيٽ ڪريون ٿا، جيڪو اسان بعد ۾ تازه ڪاري مان حاصل ڪري سگھون ٿا. اڳيون، هڪ الڳ ڪلاس ۾، مان اڳ ۾ ئي هن ڪال بڪ تي عمل ڪري سگهان ٿو:
public void handleCallBackQuery() {
String call_data = update.getCallbackQuery().getData();
long message_id = update.getCallbackQuery().getMessage().getMessageId();
long chat_id = update.getCallbackQuery().getMessage().getChatId();
switch (call_date){
case "/price" :
//тут что-то сделать
break;
...
جوابي ڪيبورڊ هن طرح ڏسڻ ۾ اچي ٿو: ۽ جوهر ۾، اهو صارف جي ٽائپنگ کي تبديل ڪري ٿو. "لائبريري" بٽڻ تي ڪلڪ ڪرڻ سان جلدي جلدي "لائبريري" پيغام موڪليندو بوٽ ڏانهن. هر قسم جي ڪيبورڊ لاءِ، مون پنهنجو ڪلاس لکيو، بلڊر جي نموني کي لاڳو ڪندي: ان لائن ۽ جواب . نتيجي طور، توھان پنھنجي ضرورتن جي بنياد تي گھربل ڪيبورڊ ”ڊرا“ ڪري سگھو ٿا. اهو انتهائي آسان آهي، ڇاڪاڻ ته ڪيبورڊ مختلف ٿي سگهن ٿا، پر اصول ساڳيو رهي ٿو. هتي هڪ ان لائن ڪيبورڊ سان پيغام موڪلڻ لاء هڪ غير معمولي طريقو آهي:
public synchronized void sendInlineKeyboardMessage(long chat_id, String gameTitle) {
SendMessage keyboard = InlineKeyboardMarkupBuilder.create(chat_id)
.setText("Вы может узнать следующую информацию об игре " + gameTitle)
.row()
.button("Стоимость " + "\uD83D\uDCB0", "/price " + gameTitle)
.button("Обновлено " + "\uD83D\uDDD3", "/updated " + gameTitle)
.button("Версия " + "\uD83D\uDEE0", "/version " + gameTitle)
.endRow()
.row()
.button("Требования " + "\uD83D\uDCF5", "/requirements " + gameTitle)
.button("Покупки " + "\uD83D\uDED2", "/iap " + gameTitle)
.button("Размер " + "\uD83D\uDD0E", "/size " + gameTitle)
.endRow()
.row()
.button("Получить всю информацию об игре" + "\uD83D\uDD79", "/all " + gameTitle)
.endRow()
.row()
.button("Скрыть клавиатуру", "close")
.endRow()
.build();
try {
execute(keyboard);
} catch (TelegramApiException e) {
log.error("[Не удалось отправить сообщение с -inline- клавиатурой]: {}", e.getMessage());
}
}
بوٽ کي سخت ڪارڪردگي ڏيڻ لاء، سليش ڪردار استعمال ڪندي خاص حڪم ايجاد ڪيا ويا: /لائبريري، /مدد، /گيم، وغيره. ٻي صورت ۾، اسان کي ڪنهن به گندگي کي پروسيس ڪرڻو پوندو جيڪو صارف لکي سگهي ٿو. دراصل، اھو اھو آھي جنھن لاء MessageHandler لکيو ويو آھي:
if (message.equals(ChatCommands.START.getDescription())) {
replyGenerator.sendTextMessage(chat_id, new StartMessageHandler().reply());
replyGenerator.sendReplyKeyboardMessage(chat_id);
}
else if (message.equals(ChatCommands.HELP.getDescription())
|| message.equalsIgnoreCase("Помощь")) {
replyGenerator.sendTextMessage(chat_id, new HelpMessageHandler().reply());
}
...
ان ڪري، ان تي منحصر آھي ته توھان بوٽ ڏانھن ڪھڙو حڪم موڪليو، ھڪڙو خاص ھٿيار ڪم ۾ شامل ڪيو ويندو. اچو ته اڳتي وڌون ۽ پارسر ۽ لائبريري جي ڪم کي ڏسو. جيڪڏهن توهان بوٽ موڪليندا آهيو هڪ راند جي لنڪ Google Play Store ۾، هڪ خاص هينڊلر خودڪار طريقي سان ڪم ڪندو . جواب ۾، صارف ھيٺ ڏنل فارم ۾ راند بابت معلومات حاصل ڪندو: ساڳئي وقت، ھڪڙو طريقو سڏيو ويندو جيڪو راند کي بوٽ جي لائبريري ۾ شامل ڪرڻ جي ڪوشش ڪندو (پهريون مقامي نقشي ڏانھن، پوء ڏانھن -> json فائل ). جيڪڏهن راند اڳ ۾ ئي لائبريري ۾ آهي، پوء هڪ چيڪ ڪيو ويندو (جيئن هڪ باقاعده هش ميپ ۾)، ۽ جيڪڏهن فيلڊ ڊيٽا (مثال طور، نسخي نمبر تبديل ٿي وئي آهي)، پوء لائبريري ۾ راند کي ختم ڪيو ويندو. جيڪڏهن ڪا تبديلي نه ملي، ته پوءِ ڪا به داخلا نه ٿيندي. جيڪڏهن لائبريري ۾ ڪا به راند نه هئي، ته پوء اهو پهريون ڀيرو مقامي نقشي تي لکيو ويو آهي (هڪ اعتراض جهڙو tyk )، ۽ پوء هڪ json فائل ڏانهن لکيو ويو آهي، ڇاڪاڻ ته جيڪڏهن سرور تي ايپليڪيشن غير متوقع طور تي بند ٿي ويندي آهي، ڊيٽا ٿي ويندي. گم ٿي ويو، پر اهو هميشه فائل استعمال ڪندي پڙهي سگهجي ٿو. دراصل، جڏهن پروگرام شروع ٿئي ٿو، لائبريري هميشه هڪ مستحڪم بلاڪ مان فائل مان پهريون ڀيرو لوڊ ڪيو ويندو آهي:
static {
TypeFactory typeFactory = mapper.getTypeFactory();
MapType mapType = typeFactory.constructMapType(ConcurrentSkipListMap.class, String.class, GooglePlayGame.class);
try {
Path path = Paths.get(LIBRARY_PATH);
if (!Files.exists(path)) {
Files.createDirectories(path.getParent());
Files.createFile(path);
log.info("[Файл библиотеки создан]");
}
else {
ConcurrentMap<string, googleplaygame=""> temporary = mapper.readValue(new File(LIBRARY_PATH), mapType);
games.putAll(temporary);
log.info("[Количество игр в загруженной библиотеке] = " + games.size());
}
}
catch (IOException e) {
log.error("[Ошибка при чтении/записи file] {}", e.getMessage());
}
}
هتي توهان کي اضافي طور تي فائل مان ڊيٽا کي هڪ عارضي نقشي ۾ پڙهڻو پوندو، جنهن کي پوءِ مڪمل نقشي ۾ ”ڪاپي“ ڪيو ويندو آهي ته جيئن فائل ۾ راند جي ڳولا دوران ڪيس جي غير حساسيت کي برقرار رکڻ لاءِ (tITan QuEST لکڻ سان، بوٽ اڃا به ڳولي سگهندو. راند ٽائيٽن ڪوئسٽ لائبريري ۾). اهو ٻيو حل ڳولڻ ممڪن نه هو، اهي آهن ڊيسيريلائيزيشن جون خاصيتون جڪسن کي استعمال ڪندي. تنهن ڪري، لنڪ جي هر درخواست سان، راند کي لائبريري ۾ شامل ڪيو ويو آهي، جيڪڏهن ممڪن هجي، ۽ لائبريري انهي سان وڌايو وڃي. ھڪڙي مخصوص راند بابت وڌيڪ معلومات حاصل ڪري سگھجي ٿو ڪمانڊ استعمال ڪندي /libraryGame_Name. توهان ڳولي سگهو ٿا هڪ مخصوص پيٽرولر (مثال طور، موجوده نسخو) ۽ سڀني پيٽرولن کي هڪ ڀيرو ۾. اهو ان لائن ڪيبورڊ استعمال ڪندي لاڳو ڪيو ويو آهي، جيڪو اڳ ۾ بحث ڪيو ويو آهي. ڪم دوران، مون هتي حاصل ڪيل صلاحيتن کي پڻ لاڳو ڪيو جڏهن ته مسئلا حل ڪيو. مثال طور، لائبريري ۾ واقع بي ترتيب راندين جي نالن جي هڪ فهرست (اختيار موجود آهي / لائبريري ڪمانڊ استعمال ڪندي):
private String getRandomTitles(){
if (LibraryService.getLibrary().size() < 10){
return String.join("\n", LibraryService.getLibrary().keySet());
}
List<string> keys = new ArrayList<>(LibraryService.getLibrary().keySet());
Collections.shuffle(keys);
List<string> randomKeys = keys.subList(0, 10);
return String.join("\n", randomKeys);
}
بوٽ پروسيس ڪيئن ڳنڍيندو آهي؟ اهو انهن کي چيڪ ڪري ٿو ته اهي Google Play سان تعلق رکن ٿا (ميزبان، پروٽوڪول، پورٽ):
private static class GooglePlayCorrectURL {
private static final String VALID_HOST = "play.google.com";
private static final String VALID_PROTOCOL = "https";
private static final int VALID_PORT = -1;
private static boolean isLinkValid(URI link) {
return (isHostExist(link) && isProtocolExist(link) && link.getPort() == VALID_PORT);
}
private static boolean isProtocolExist(URI link) {
if (link.getScheme() != null) {
return link.getScheme().equals(VALID_PROTOCOL);
}
else {
return false;
}
}
private static boolean isHostExist(URI link) {
if (link.getHost() != null) {
return link.getHost().equals(VALID_HOST);
}
else {
return false;
}
}
جيڪڏهن هر شي ترتيب ۾ آهي، ته پوء بوٽ هڪ لنڪ ذريعي ڳنڍيندو آهي Jsoup لائبريري استعمال ڪندي، جيڪو توهان کي صفحي جو HTML ڪوڊ حاصل ڪرڻ جي اجازت ڏئي ٿو، جيڪو وڌيڪ تجزيو ۽ تجزيو ڪرڻ جي تابع آهي. توهان غلط يا نقصانڪار لنڪ سان بوٽ کي بيوقوف نه بڻائي سگهندا.
if (GooglePlayCorrectURL.isLinkValid(link)){
if (!link.getPath().contains("apps")){
throw new InvalidGooglePlayLinkException("К сожалению, бот работает исключительно с играми. Введите другую ссылку.");
}
URL = forceToRusLocalization(URL);
document = Jsoup.connect(URL).get();
}
else {
throw new NotGooglePlayLinkException();
}
...
هتي اسان کي علائقائي سيٽنگن سان هڪ مسئلو حل ڪرڻو پيو. بوٽ يورپ ۾ واقع سرور کان گوگل پلي اسٽور سان ڳنڍي ٿو، تنهنڪري گوگل پلي اسٽور ۾ صفحو مناسب ٻولي ۾ کلي ٿو. مون کي هڪ ڪرچ لکڻو پيو جيڪو زبردستي صفحي جي روسي ورزن ڏانهن ”ريڊائريڪٽس“ ڪري ٿو (پراجيڪٽ، آخرڪار، اسان جي سامعين جو مقصد هو). هن کي ڪرڻ لاءِ، لنڪ جي آخر ۾ توهان کي احتياط سان شامل ڪرڻ جي ضرورت پوندي hl: &hl=ru GET درخواست ۾ Google Play سرور .
private String forceToRusLocalization(String URL) {
if (URL.endsWith("&hl=ru")){
return URL;
}
else {
if (URL.contains("&hl=")){
URL = URL.replace(
URL.substring(URL.length()-"&hl=ru".length()), "&hl=ru");
}
else {
URL += "&hl=ru";
}
}
return URL;
}
ڪامياب ڪنيڪشن کان پوءِ، اسان حاصل ڪندا آهيون هڪ HTML دستاويز تيار ڪيل تجزيو ۽ تجزيي لاءِ، پر اهو هن مضمون جي دائري کان ٻاهر آهي. پارسر ڪوڊ هتي آهي . parser پاڻ ضروري معلومات حاصل ڪري ٿو ۽ راند سان هڪ اعتراض ٺاهي ٿو، جيڪو بعد ۾ لائبريري ۾ شامل ڪيو ويو آهي جيڪڏهن ضروري هجي. <h2>اختصار ڪرڻ لاءِ</h2>بوٽ ڪيترن ئي حڪمن کي سپورٽ ڪري ٿو جيڪي خاص ڪارڪردگي تي مشتمل آهن. اهو صارف کان پيغام وصول ڪري ٿو ۽ انهن کي ان جي حڪمن سان ملائي ٿو. جيڪڏهن اهو هڪ لنڪ آهي يا /game + لنڪ ڪمانڊ، اهو انهي لنڪ کي چيڪ ڪري ٿو ته اهو ڏسڻ لاءِ ته اهو Google Play سان تعلق رکي ٿو. جيڪڏهن لنڪ صحيح آهي، اهو Jsoup ذريعي ڳنڍي ٿو ۽ HTML دستاويز وصول ڪري ٿو. هي دستاويز تحليل ڪيل تحرير جي بنياد تي تجزيو ڪيو ويو آهي. راند بابت ضروري معلومات دستاويز مان ڪڍيو ويو آهي، ۽ پوء راند سان اعتراض هن ڊيٽا سان ڀريو ويندو آهي. اڳيون، راند سان گڏ اعتراض مقامي اسٽوريج ۾ رکيل آهي (جيڪڏهن راند اڃا تائين نه آهي) ۽ فوري طور تي ڊيٽا جي نقصان کان بچڻ لاء هڪ فائل ڏانهن لکيو ويو آهي. لائبريري ۾ رڪارڊ ڪيل راند (راند جو نالو نقشي جي ڪنجي آھي، راند سان گڏ اعتراض نقشي لاءِ قدر آھي) ڪمانڊ /library Game_name استعمال ڪندي حاصل ڪري سگھجي ٿو. جيڪڏهن بيان ڪيل راند بوٽ جي لائبريري ۾ ملي ٿي، صارف کي هڪ ان لائن ڪيبورڊ واپس ڪيو ويندو، جنهن سان هو راند بابت معلومات حاصل ڪري سگهي ٿو. جيڪڏهن راند نه ملي، توهان کي يا ته پڪ ڪرڻ گهرجي ته نالو صحيح لکيو ويو آهي (اهو مڪمل طور تي Google Play Store ۾ راند جي نالي سان ملندو، سواء ڪيس جي)، يا بوٽ موڪلڻ سان راند کي لائبريري ۾ شامل ڪريو. راند جي لنڪ. مون بوٽ کي هيروڪو تي لڳايو ۽ انهن لاءِ جيڪي مستقبل ۾ پنهنجو بوٽ لکڻ ۽ هيروڪو تي مفت ۾ ميزباني ڪرڻ جو ارادو رکن ٿا، مان توهان کي پيش ايندڙ مشڪلاتن کي حل ڪرڻ لاءِ ڪجهه تجويزون ڏيندس (جڏهن ته مون پاڻ انهن سان منهن ڪيو). بدقسمتي سان، هيروڪو جي فطرت جي ڪري، بوٽ لائبريري مسلسل هر 24 ڪلاڪن ۾ هڪ ڀيرو "ري سيٽ" آهي. منهنجو منصوبو هيروڪو سرورز تي فائلن کي محفوظ ڪرڻ جي حمايت نٿو ڪري، تنهنڪري اهو صرف منهنجي گيم فائل کي Github کان ڇڪي ٿو. اتي ڪيترائي حل آھن: ھڪڙو ڊيٽابيس استعمال ڪريو، يا ٻيو سرور ڳوليو جيڪو ھن فائل کي راند سان گڏ ڪندو. مون فيصلو ڪيو ته في الحال ڪجھ به نه ڪيو، ڇو ته بنيادي طور تي بوٽ اهو مفيد نه آهي. مون کي ان جي ضرورت آهي بلڪه مڪمل تجربو حاصل ڪرڻ لاءِ، جيڪو بنيادي طور تي حاصل ڪيو آهي. تنهن ڪري، Heroku لاء سفارشون:
-
جيڪڏهن توهان روس ۾ رهندا آهيو ته توهان کي وي پي اين استعمال ڪندي هيروڪو تي رجسٽر ٿيڻو پوندو.
-
پروجيڪٽ جي روٽ تي توهان کي فائل رکڻ جي ضرورت آهي بغير ايڪسٽينشن جي Procfile. ان جو مواد هن طرح هجڻ گهرجي: https://github.com/miroha/Telegram-Bot/blob/master/Procfile
-
pom.xml ۾، مثال جي مطابق ھيٺيون لائينون شامل ڪريو ، جتي mainClass ٽيگ ۾ ڪلاس ڏانھن رستو ڏيکاريندو آھي جنھن ۾ مکيه طريقو آھي: bot.BotApplication (جيڪڏھن BotApplication ڪلاس بوٽ فولڊر ۾ آھي).
-
mvn پيڪيج ڪمانڊ وغيره استعمال ڪندي ڪو به پروجيڪٽ نه ٺاهيو، هيروڪو توهان جي لاءِ سڀ ڪجهه گڏ ڪندو.
-
اهو مشورو ڏنو ويو آهي ته هڪ gitignore منصوبي ۾ شامل ڪريو، مثال طور هي:
# Log file *.log # Compiled resources target # Tests test # IDEA files .idea *.iml
-
اصل ۾ پروجيڪٽ کي گيٿب تي اپلوڊ ڪريو، ۽ پوءِ مخزن کي هيروڪو سان ڳنڍيو (يا ٻيا طريقا استعمال ڪريو، انهن مان 3 آهن، جيڪڏهن مان غلط نه آهيان).
-
جيڪڏهن ڊائون لوڊ ڪامياب ٿي ويو ("تعمير ڪامياب")، پڪ ڪريو ته وڃو ڪنفيگر ڊائنوس:
۽ سلائيڊر کي مٽايو، ۽ پوء پڪ ڪريو ته اهو آن پوزيشن ۾ آهي (ان حقيقت جي ڪري ته مون اهو نه ڪيو، منهنجو بوٽ ڪم نه ڪيو ۽ مون پنهنجي دماغ کي ڪجهه ڏينهن تائين ريڪ ڪيو ۽ ڪيتريون ئي غير ضروري حرڪتون ڪيون. ).
-
Github تي بوٽ ٽوڪن کي لڪايو. هن کي ڪرڻ لاء، توهان کي ماحول جي متغير مان ٽوڪن حاصل ڪرڻ جي ضرورت آهي:
public class Bot extends TelegramLongPollingBot { private static final String BOT_TOKEN = System.getenv("TOKEN"); @Override public String getBotToken() { return BOT_TOKEN; } ... }
۽ پوءِ بوٽ کي ڊيپلائي ڪرڻ کان پوءِ هيروڪو ڊيش بورڊ ۾ سيٽنگون ٽئب ۾ هي ويريئبل سيٽ ڪريو (ٽوڪن جي ساڄي پاسي VALUE فيلڊ هوندي، اتي پنهنجي بوٽ جي ٽوڪن کي ڪاپي ڪريو):
- جاوا ۾ لکيل مڪمل طور تي ڪم ڪندڙ منصوبو حاصل ڪيو؛
- ٽئين پارٽي API (Telegram Bot API) سان ڪم ڪرڻ سکيو؛
- عملي طور تي، مون سيريلائيزيشن ۾ تمام گهڻي دلچسپي ورتي، JSON ۽ جيڪسن لائبريري سان تمام گهڻو ڪم ڪيو (شروع ۾ مون GSON استعمال ڪيو، پر ان سان گڏ مسئلا هئا)؛
- منهنجي صلاحيتن کي مضبوط ڪيو جڏهن فائلن سان ڪم ڪندي، جاوا NIO سان واقف ٿيو؛
- .xml فائلن جي ترتيب سان ڪم ڪرڻ سکيو ۽ پاڻ کي لاگنگ ڪرڻ جو عادي ڪيو؛
- ترقي جي ماحول ۾ بهتر مهارت (IDEA)؛
- git سان ڪم ڪرڻ سکيو ۽ gitignore جي قدر سکيو؛
- ويب پيج پارس ڪرڻ ۾ مهارت حاصل ڪئي (Jsoup لائبريري)؛
- سکيا ۽ ڪيترن ئي ڊيزائن جي نمونن کي استعمال ڪيو؛
- ڪوڊ کي بهتر ڪرڻ لاء هڪ احساس ۽ خواهش پيدا ڪيو (ريفڪٽرنگ)؛
- مون آن لائين حل ڳولڻ سکيو ۽ سوال پڇڻ ۾ شرم نه ٿيڻ جو مون کي جواب نه ملي سگهيو.
GO TO FULL VERSION