@Override
public void onUpdateReceived(Update update) {
UpdatesReceiver.handleUpdates(update);
}
işleýjä geçirýärin (“UpdatesReceiver” synpy):
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” täzelenmäniň görnüşine baglylykda dolandyryşy başga bir ýöriteleşdirilen işleýjä geçirýän merkezi işleýjidir: TextMessageHandler ýa-da CallbackQueryHandler, konstruktorlaryna zynjyry hasam täzeleýärin. Täzelenme bot bilen işlän wagtyňyz iň möhüm zat we ýitirilmeli däldir, sebäbi täzelenmede saklanýan maglumatlaryň kömegi bilen haýsy ulanyja we haýsy söhbetdeşlige jogap iberilmelidigini bilýäris. Ulanyja jogap döretmek üçin aýratyn synp ýazdym. Ol yzygiderli tekst habary, içerki klawiatura bilen habar, suratly habar we jogap klawiaturasy bilen habar iberip biler. Içerki klawiatura şuňa meňzeýär: Düwmeleri kesgitleýär, basmak bilen ulanyjy adaty habarlar bilen birmeňzeş işlenip bilinýän serwere jaň iberýär. “Saklamak” üçin öz işleýjiňiz gerek. Her düwme üçin hereket edýäris, soň bolsa täzelenme obýektine ýazylýar. Bular. "Çykdajy" düwmesi üçin, täzelenmeden soň alyp boljak yzyna çagyryş üçin düşündiriş "/ baha" belläris. Ondan soň, aýratyn synpda, bu jaňy eýýäm işläp bilerin:
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;
...
Jogap bermek klawiaturasy şuňa meňzeýär: Aslynda ulanyjynyň ýazuwynyň ýerini alýar. "Kitaphana" düwmesine basylanda bot "Kitaphana" habaryny çalt iberer. Klawiaturanyň her görnüşi üçin, Gurluşyk nagyşyny durmuşa geçirip, öz synpymy ýazdym: setir we jogap . Netijede, talaplaryňyza baglylykda islenýän klawiaturany “çyzyp” bilersiňiz. Bu gaty amatly, sebäbi klawiaturalar başgaça bolup biler, ýöne ýörelge şol bir bolmagynda galýar. Ine, içerki klawiatura bilen habar ibermegiň içgin usuly:
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());
}
}
Botyň berk işlemegi üçin, çyzgy belgisini ulanýan ýörite buýruklar oýlanyp tapyldy: / kitaphana, / kömek, / oýun we ş.m. Otherwiseogsam, ulanyjynyň ýazyp biljek islendik zibilini gaýtadan işlemeli bolarys. Aslynda, MessageHandler üçin ýazylan zat:
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());
}
...
Şeýlelik bilen, bota haýsy buýrugy iberýändigiňize baglylykda işe ýörite işleýji goşular. Geliň, derňewçiniň we kitaphananyň işine seredeliň. Boty Google Play dükanyndaky bir oýna baglanyşyk iberseňiz, ýörite işleýän awtomatiki usulda işlär . Muňa jogap hökmünde ulanyjy oýun hakda aşakdaky görnüşde maglumat alar: Şol bir wagtyň özünde, oýny botyň kitaphanasyna (ilki ýerli kartada, soňra -> json faýlyna) goşjak bir usul çagyrylar. ). Oýun eýýäm kitaphanada bolsa, onda barlag geçiriler (adaty hashmapdaky ýaly) we meýdan maglumatlary (mysal üçin, wersiýa belgisi üýtgedi), kitaphanadaky oýun gaýtadan ýazylar. Hiç hili üýtgeşme tapylmasa, hiç hili ýazgy edilmez. Kitaphanada asla oýun bolmadyk bolsa, ilki ýerli karta ( tyk ýaly bir obýekt ) ýazylýar, soň bolsa json faýlyna ýazylýar, sebäbi serwerdäki programma garaşylmadyk ýagdaýda ýapylsa, maglumatlar bolar ýitdi, ýöne faýly ulanyp hemişe okap bolýar. Aslynda, programma başlanda kitaphana hemişe ilkinji gezek statik blokdan bir faýldan ýüklenýär:
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());
}
}
Mundan başga-da, faýlda oýun gözläniňizde hadysanyň duýgurlygyny saklamak üçin faýldan maglumatlary wagtlaýyn kartada okamaly bolarsyňyz (TITan QuEST ýazyp, bot henizem tapylar) kitaphanadaky “Titan Quest” oýny). Başga bir çözgüt tapmak mümkin däldi, bular Jeksonyň kömegi bilen deserializasiýa aýratynlyklary. Şeýlelik bilen, baglanyşyk üçin her haýyş bilen, mümkin boldugyça oýun kitaphana goşulýar we kitaphana giňelýär. Belli bir oýun hakda has giňişleýin maglumat / LibraryGame_Name buýrugy arkaly alyp bilersiňiz . Belli bir parametri (mysal üçin, häzirki wersiýa) we ähli parametrleri birbada tapyp bilersiňiz. Bu, ozal ara alnyp maslahatlaşylan içerki klawiaturanyň kömegi bilen amala aşyrylýar. Iş wagtynda, bu ýerde gazanylan endikleri meseleleri çözmek bilen ulandym. Mysal üçin, kitaphanada ýerleşýän tötänleýin oýunlaryň atlarynyň sanawy (opsiýa / kitaphananyň buýrugy bilen elýeterlidir):
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);
}
Bot prosesi nähili baglanyşýar? Google Play-e degişlidigini ýa-da ýokdugyny barlaýar (host, protokol, port):
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;
}
}
Everythinghli zat tertipli bolsa, bot Jsoup kitaphanasyny ulanyp, sahypanyň HTML koduny almaga mümkinçilik berýän baglanyşyk arkaly birigýär, bu bolsa has giňişleýin derňelip we derňelip bilner. Nädogry ýa-da zyýanly baglanyşyk bilen boty aldap bilmersiňiz.
if (GooglePlayCorrectURL.isLinkValid(link)){
if (!link.getPath().contains("apps")){
throw new InvalidGooglePlayLinkException("К сожалению, бот работает исключительно с играми. Введите другую ссылку.");
}
URL = forceToRusLocalization(URL);
document = Jsoup.connect(URL).get();
}
else {
throw new NotGooglePlayLinkException();
}
...
Bu ýerde sebit sazlamalary bilen bir meseläni çözmeli bolduk. Bot, Google Play dükanyna Europeewropada ýerleşýän serwerden birigýär, şonuň üçin Google Play dükanyndaky sahypa degişli dilde açylýar. Sahypanyň rus görnüşine zor bilen “gönükdirýän” taýak ýazmaly boldum (taslama ahyrsoňy diňleýjilerimize gönükdirilipdi). Munuň üçin baglanyşygyň soňunda Google Play serwerine GET haýyşynda hl: & hl = ru parametrini üns bilen goşmaly .
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;
}
Üstünlikli baglanyşykdan soň, derňew we derňew üçin taýýar HTML resminamasyny alýarys, ýöne bu makalanyň çäginden çykmaýar. Derňew kody şu ýerde . Derňewçiniň özi zerur maglumatlary alýar we oýun bilen bir obýekt döredýär, zerur bolsa soň kitaphana goşulýar. <h2> Jemlemek üçin </h2> Bot belli bir funksiýany öz içine alýan birnäçe buýrugy goldaýar. Ulanyjydan habar alýar we buýruklary bilen gabat gelýär. Eger baglanyşyk ýa-da / oýun + baglanyşyk buýrugy bolsa, bu baglanyşygy Google Play-e degişlidigini barlaýar. Baglanyşyk dogry bolsa, Jsoup arkaly birleşýär we HTML resminamasyny alýar. Bu resminama ýazylan derňewçiniň esasynda seljerilýär. Oýun hakda zerur maglumatlar resminamadan alynýar, soň bolsa oýun bilen obýekt bu maglumatlar bilen doldurylýar. Ondan soň, oýun bilen obýekt ýerli ammarda ýerleşdirilýär (eger oýun entek ýok bolsa) we maglumatlaryň ýitmezligi üçin derrew faýla ýazylýar. Kitaphanada ýazylan oýun (oýnuň ady kartanyň açary, oýun bilen obýekt kartanyň gymmaty) Game_name buýrugy / kitaphanasy arkaly alnyp bilner. Görkezilen oýun botyň kitaphanasynda tapylsa, ulanyja oýun hakda maglumat alyp boljak içerki klawiatura yzyna berler. Oýun tapylmasa, ýa-da adyň dogry ýazylandygyna göz ýetirmeli (bu ýagdaýdan başga Google Play dükanyndaky oýnuň adyna doly laýyk bolmaly) ýa-da bot iberip, kitaphana goşmaly. oýna baglanyşyk. Boty herokuda ýerleşdirdim we geljekde öz botyny ýazmagy we ony herokuda mugt ýerleşdirmegi meýilleşdirýänler üçin, ýüze çykyp biljek kynçylyklary çözmek üçin birnäçe maslahat bererin (sebäbi men özüme duş geldim). Gynansagam, Herokunyň tebigaty sebäpli bot kitaphanasy her 24 sagatda bir gezek "täzeden" düzülýär. Meýilnamam Heroku serwerlerinde faýllary saklamagy goldamaýar, şonuň üçin oýun faýlymy Github-dan çykarýar. Birnäçe çözgüt bardy: maglumat bazasyny ulanyň ýa-da bu faýly oýun bilen saklajak başga bir serwer gözläň. Häzirlikçe hiç zat etmezlik kararyna geldim, sebäbi bot beýle peýdaly däl. Maňa doly tejribe toplamak gerekdi, bu esasan ýeten zadym. Şeýlelikde, Heroku üçin teklipler:
-
Russiýada ýaşaýan bolsaňyz, VPN ulanyp, herokuda hasaba alynmaly bolarsyňyz.
-
Taslamanyň düýbünde “Procfile” atly giňeltmesiz bir faýl goýmaly. Mazmuny şeýle bolmaly: https://github.com/miroha/Telegram-Bot/blob/master/Procfile
-
Pom.xml-de, mysal boýunça aşakdaky setirleri goşuň , esasyClass belliginde esasy usuly öz içine alýan synpa barýan ýoly görkezýär: bot.BotApplication (BotApplication synpy bot bukjasynda bolsa).
-
Mvn paket buýruklaryny we ş.m. ulanyp, haýsydyr bir taslama gurmaň, Heroku siziň üçin hemme zady ýygnaýar.
-
Taslama gitignore goşmak maslahat berilýär, mysal üçin:
# Log file *.log # Compiled resources target # Tests test # IDEA files .idea *.iml
-
Aslynda taslamany github-a ýükläň, soňra ammary Heroku bilen birikdiriň (ýa-da başga usullary ulanyň, ýalňyşmasam 3 sanysy bar).
-
Göçürip almak üstünlikli bolsa ("Gurmak üstünlik gazandy"), Dynos-y sazlamak üçin hökman giriň:
süýşürijini çalşyň, soňra bolsa ON ýagdaýynda bolandygyna göz ýetiriň (muny etmedigim sebäpli botym işlemedi we bir-iki gün beýnimi döwdüm we köp gereksiz hereketler etdim ).
-
Bot belligini Github-da gizläň. Munuň üçin daşky gurşaw üýtgeýjisinden belgi almaly:
public class Bot extends TelegramLongPollingBot { private static final String BOT_TOKEN = System.getenv("TOKEN"); @Override public String getBotToken() { return BOT_TOKEN; } ... }
Soňra bot ýerleşdirilenden soň, bu üýtgeýjini Sazlamalar goýmasyndaky Heroku dolandyryş panelinde goýuň (TOKEN-iň sag tarapynda GYMMAT meýdançasy bolar, botyňyzyň belligini şol ýere göçüriň):
- Java-da ýazylan doly iş taslamasyny aldy;
- üçünji tarap API (Telegram Bot API) bilen işlemegi öwrendi;
- iş ýüzünde serializasiýa has çuňňur göz aýladym, JSON we Jekson kitaphanasy bilen köp işledim (başda GSON ulanýardym, ýöne bu ýerde kynçylyklar bardy);
- faýllar bilen işleýän wagtym başarnygymy berkitdim, Java NIO bilen tanyşdym;
- konfigurasiýa .xml faýllary bilen işlemegi öwrendim we hasaba girmäge öwrenişdim;
- ösüş gurşawynda hünär derejesini ýokarlandyrmak (IDEA);
- git bilen işlemegi öwrendi we gitignore-nyň bahasyny öwrendi;
- web sahypasyny derňemek endiklerini gazandy (Jsoup kitaphanasy);
- birnäçe dizaýn nagyşlaryny öwrendi we ulandy;
- kody gowulaşdyrmak duýgusyny we islegini ösdürdi;
- Onlaýn çözgüt tapmagy we jogap tapyp bilmeýän soraglary bermäge utanmazlygy öwrendim.
GO TO FULL VERSION