JavaRush /Java Blog /Random-TK /Bot bilen işlemek üçin buýruk nusgasyny durmuşa geçireliň...

Bot bilen işlemek üçin buýruk nusgasyny durmuşa geçireliň. (1-nji bölüm) - "A-dan Z-a çenli Java taslamasy"

Toparda çap edildi
Hemmelere salam, gadyrly dostlar. Bu gün zerurlyklarymyz üçin buýruk dizaýnynyň şablonyny (şablon bir nagyş, kontekstimizde şol bir zat) durmuşa geçireris. Bu şablony ulanyp, botumyzyň buýruklaryny gaýtadan işlemek bilen amatly we dogry işläris. "A-dan Z-a çenli Java taslamasy": Bot bilen işlemek üçin buýruk nusgasyny durmuşa geçirmek.  1-nji bölüm
Dostlar, “Javarush Telegram Bot” taslamasyny haladyňyzmy ? Yalta bolma: ýyldyz ber . Şeýlelik bilen, onuň gyzyklydygy aýdyň bolar we ony ösdürmek has ýakymly bolar!
Ilki bilen, munuň haýsy nagyşdygy barada buýruk bermek gowy bolardy - Buýruk. Thisöne muny etsem, makala gaty uly we kyn bolar. Şonuň üçin öz-özüňi öwrenmek üçin materiallary saýladym:
  1. Bu meniň 4 ýyl ozal ýazan makalam . Men muny kiçi wagtym ýazdym, şonuň üçin gaty berk baha bermäň.
  2. “YouTube” -da gaty duýgur we interaktiw şwesiýanyň wideosy. Men muny maslahat berýärin. Owadan gürleýär, iňlis dili düşnükli we düşnükli. Umuman aýdanyňda, beýleki dizaýn nagyşlary barada wideosy bar.
  3. Makalamdaky teswirlerde Nullptr35 kimdir biri bu wideony maslahat berdi .
Bu mowzuga çümmek we meniň bilen bir sahypada bolmak üçin ýeterlik bolmaly. Dogrusy, bu dizaýn nagşy bilen tanyşlar arkaýyn geçip, dowam edip bilerler.

JRTB-3 ýazýarys

Hemme zat öňküsi ýaly:
  1. Esasy şahany täzeleýäris.
  2. Täzelenen esasy şaha esaslanyp, täze JRTB-3 döredýäris .
  3. Geliň, nagşy durmuşa geçireliň.
  4. Edilen işleri suratlandyrýan täze borçnama döredýäris.
  5. Çekiş haýyşyny döredýäris, barlaýarys we hemme zat gowy bolsa, işimizi birleşdirýäris.
1-2 bal görkezmerin: Olary öňki makalalarda gaty üns bilen beýan etdim, geliň şablony durmuşa geçirmäge dowam edeliň. Bu şablon näme üçin bize laýyk gelýär? Hawa, sebäbi her gezek buýrugy ýerine ýetirenimizde, onUpdateReceived (Täzelenme täzelenmesi) usulyna geçeris we buýruga baglylykda dürli logikany ýerine ýetireris. Bu nagyş bolmasa, jümleler bar bolsa, tutuş bir toparymyz bolardy. Şuňa meňzeş bir zat:
if (message.startsWith("/start")) {
   doStartCommand();
} else if(message.startsWith("/stop")) {
   doStopCommand();
} else if(message.startsWith("/addUser")) {
   doAddUserCommand();
}
...
else if(message.startsWith("/makeMeHappy")) {
   doMakeMeHappyCommand();
}
Mundan başga-da, ellips bar ýerinde ýene-de onlarça topar bolup biler. Muny adaty nädip çözmeli? Nädip goldamaly? Kyn we kyn. Bu, bu wariantyň bize laýyk gelmeýändigini aňladýar. Munuň ýaly bir zat görünmeli:
if (message.startsWith(COMMAND_PREFIX)) {
   String commandIdentifier = message.split(" ")[0].toLowerCase();
   commandContainer.getCommand(commandIdentifier, userName).execute(update);
} else {
   commandContainer.getCommand(NO.getCommand(), userName).execute(update);
}
Bu hemmesi! Näçe buýruk goşsak-da, koduň bu bölümi üýtgemez. Ol näme edýär? Birinjisi, habaryň "/" buýruk prefiksi bilen başlanýandygyna göz ýetirseňiz. Eger şeýle bolsa, birinji giňişlige çenli setiri saýlaýarys we CommandContainer-de degişli buýrugy gözleýäris; tapanymyzdan soň buýrugy ýerine ýetirýäris. Bularyň hemmesi ...) Islegiňiz we wagtyňyz bar bolsa, toparlar bilen işlemegi, birbada bir synpda, bir topar şertler we beýleki zatlar bilen, soň bolsa şablon ulanyp bilersiňiz. Tapawudyny görersiňiz. Bu nähili gözellik bolar! Ilki bilen, buýruk diýilýän bot paketiniň gapdalynda bir paket döredeliň . "A-dan Z-a çenli Java taslamasy": Bot bilen işlemek üçin buýruk nusgasyny durmuşa geçirmek.  1-nji bölümBu paketde eýýäm buýrugyň ýerine ýetirilmegi bilen baglanyşykly ähli synplar bolar. Buýruklar bilen işlemek üçin bize bir interfeýs gerek. Bu ýagdaý üçin, geliň:
package com.github.javarushcommunity.jrtb.command;

import org.telegram.telegrambots.meta.api.objects.Update;

/**
* Command interface for handling telegram-bot commands.
*/
public interface Command {

   /**
    * Main method, which is executing command logic.
    *
    * @param update provided {@link Update} object with all the needed data for command.
    */
   void execute(Update update);
}
Bu pursatda buýrugyň ters amalyny amala aşyrmak hökman däl, şonuň üçin bu usuly geçeris (ýerine ýetirilmedik). Ecutionerine ýetirmek usulynda, Täzelenme obýekti argument hökmünde gelýär - edil botdaky esasy usulymyza gelýär. Bu obýekt buýrugy gaýtadan işlemek üçin zerur zatlary öz içine alar. Ondan soň, buýruk bahalaryny (başlamak, durmak we ş.m.) saklaýan san goşarys. Bu näme üçin bize gerek? Topar atlary üçin hakykatyň diňe bir çeşmesi bar. Şeýle hem buýruk bukjamyzda döredýäris . Oňa CommandName diýeliň :
package com.github.javarushcommunity.jrtb.command;

/**
* Enumeration for {@link Command}'s.
*/
public enum CommandName {

   START("/start"),
   STOP("/stop");

   private final String commandName;

   CommandName(String commandName) {
       this.commandName = commandName;
   }

   public String getCommandName() {
       return commandName;
   }

}
Bot arkaly habar iberjek hyzmat hem gerek. Munuň üçin buýruk bukjasynyň gapdalynda hyzmat bukjasyny dörederis , oňa ähli zerur hyzmatlary goşarys. Bu ýerde bu ýagdaýda hyzmat sözi diýjek bolýan zadymyza ünsi jemlemeli. Bir programmany göz öňünde tutsak, köplenç birnäçe gatlaklara bölünýär: ahyrky nokatlar - dolandyryjylar, iş logikasy - hyzmatlar we maglumatlar bazasy bilen işlemek üçin gatlak - ammar. Şonuň üçin biziň ýagdaýymyzda hyzmat haýsydyr bir iş logikasyny durmuşa geçirýän synpdyr. Hyzmaty nädip dogry döretmeli? Ilki bilen munuň üçin interfeýs dörediň we durmuşa geçiriň. “@ Service” düşündirişini ulanyp, “SpringBoot” programmamyzyň Programma mazmunyna goşuň we zerur bolsa, “@ Autowired” belligini ulanyp berkidiň. Şonuň üçin SendBotMessageService interfeýsini döredýäris (atlandyryş hyzmatlarynda adatça adyň soňunda Hyzmat goşýarlar):
package com.github.javarushcommunity.jrtb.service;

/**
* Service for sending messages via telegram-bot.
*/
public interface SendBotMessageService {

   /**
    * Send message via telegram bot.
    *
    * @param chatId provided chatId in which messages would be sent.
    * @param message provided message to be sent.
    */
   void sendMessage(String chatId, String message);
}
Indiki, biz onuň ýerine ýetirilişini döredýäris:
package com.github.javarushcommunity.jrtb.service;

import com.github.javarushcommunity.jrtb.bot.JavarushTelegramBot;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;

/**
* Implementation of {@link SendBotMessageService} interface.
*/
@Service
public class SendBotMessageServiceImpl implements SendBotMessageService {

   private final JavarushTelegramBot javarushBot;

   @Autowired
   public SendBotMessageServiceImpl(JavarushTelegramBot javarushBot) {
       this.javarushBot = javarushBot;
   }

   @Override
   public void sendMessage(String chatId, String message) {
       SendMessage sendMessage = new SendMessage();
       sendMessage.setChatId(chatId);
       sendMessage.enableHtml(true);
       sendMessage.setText(message);

       try {
           javarushBot.execute(sendMessage);
       } catch (TelegramApiException e) {
           //todo add logging to the project.
           e.printStackTrace();
       }
   }
}
Bu ýerine ýetirişiň görnüşi. Iň möhüm jady, dizaýneriň döredilen ýeri. Konstruktordaky @Autowired düşündirişini ulanyp, “SpringBoot” amaly kontekstinde bu synpyň obýektini gözlär. Ol eýýäm bar. Bu şeýle işleýär: programmamyzda islendik ýere bot girip, bir zatlar edip bileris. Bu hyzmat habar ibermek üçin jogapkärdir. Her gezek her ýerde şuňa meňzeş bir zat ýazmazlygymyz üçin:
SendMessage sendMessage = new SendMessage();
sendMessage.setChatId(chatId);
sendMessage.setText(message);

try {
   javarushBot.execute(sendMessage);
} catch (TelegramApiException e) {
   //todo add logging to the project.
   e.printStackTrace();
}
Bu logikany aýratyn klasa geçirdik we zerur bolsa ulanarys. Indi üç buýrugy durmuşa geçirmeli: StartCommand, StopCommand we UnknownCommand. Buýruklar üçin konteýnerimizi doldurjak bir zadymyz bolar ýaly, olara mätäç. Häzirlikçe tekstler gury we maglumat bermez; bu meseläniň maksatlary üçin bu gaty möhüm däl. Şeýlelikde, “StartCommand”:
package com.github.javarushcommunity.jrtb.command;

import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import org.telegram.telegrambots.meta.api.objects.Update;

/**
* Start {@link Command}.
*/
public class StartCommand implements Command {

   private final SendBotMessageService sendBotMessageService;

   public final static String START_MESSAGE = "Привет. Я Javarush Telegram Bot. Я помогу тебе быть в курсе последних " +
           "статей тех авторов, котрые тебе интересны. Я еще маленький и только учусь.";

   // Здесь не добавляем сервис через получение из Application Context.
   // Потому что если это сделать так, то будет циклическая зависимость, которая
   // ломает работу applications.
   public StartCommand(SendBotMessageService sendBotMessageService) {
       this.sendBotMessageService = sendBotMessageService;
   }

   @Override
   public void execute(Update update) {
       sendBotMessageService.sendMessage(update.getMessage().getChatId().toString(), START_MESSAGE);
   }
}
Dizaýneriň öňünde teswirleri üns bilen okaň. Tegelek garaşlylyk ( tegelek garaşlylyk ) arhitektura sebäpli gaty dogry däl bolup biler. Biziň ýagdaýymyzda, hemme zadyň işleýändigine we dogrudygyna göz ýetireris. Programma kontekstindäki hakyky obýekt CommandContainer-de eýýäm buýruk döredilende goşular. StopCommand:
package com.github.javarushcommunity.jrtb.command;

import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import org.telegram.telegrambots.meta.api.objects.Update;

/**
* Stop {@link Command}.
*/
public class StopCommand implements Command {

   private final SendBotMessageService sendBotMessageService;

   public static final String STOP_MESSAGE = "Деактивировал все ваши подписки \uD83D\uDE1F.";

   public StopCommand(SendBotMessageService sendBotMessageService) {
       this.sendBotMessageService = sendBotMessageService;
   }

   @Override
   public void execute(Update update) {
       sendBotMessageService.sendMessage(update.getMessage().getChatId().toString(), STOP_MESSAGE);
   }
}
We UnknownCommand. Näme üçin bize gerek? Biziň üçin bu bize berlen buýrugy tapyp bilmesek jogap berjek möhüm buýruk. Şeýle hem bize “NoCommand” we “HelpCommand” gerek bolar.
  • NoCommand - habar asla buýruk bilen başlamasa, ýagdaý üçin jogapkär bolar;
  • “HelpCommand” ulanyjy üçin resminamalaryň bir görnüşi bolar.
“HelpCommand” goşalyň:
package com.github.javarushcommunity.jrtb.command;

import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import org.telegram.telegrambots.meta.api.objects.Update;

import static com.github.javarushcommunity.jrtb.command.CommandName.*;

/**
* Help {@link Command}.
*/
public class HelpCommand implements Command {

   private final SendBotMessageService sendBotMessageService;

   public static final String HELP_MESSAGE = String.format("✨<b>Дотупные команды</b>✨\n\n"

                   + "<b>Начать\\закончить работу с ботом</b>\n"
                   + "%s - начать работу со мной\n"
                   + "%s - приостановить работу со мной\n\n"
                   + "%s - получить помощь в работе со мной\n",
           START.getCommandName(), STOP.getCommandName(), HELP.getCommandName());

   public HelpCommand(SendBotMessageService sendBotMessageService) {
       this.sendBotMessageService = sendBotMessageService;
   }

   @Override
   public void execute(Update update) {
       sendBotMessageService.sendMessage(update.getMessage().getChatId().toString(), HELP_MESSAGE);
   }
}
NoCommand:
package com.github.javarushcommunity.jrtb.command;

import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import org.telegram.telegrambots.meta.api.objects.Update;

/**
* No {@link Command}.
*/
public class NoCommand implements Command {

   private final SendBotMessageService sendBotMessageService;

   public static final String NO_MESSAGE = "Я поддерживаю команды, начинающиеся со слеша(/).\n"
           + "Whatбы посмотреть список команд введите /help";

   public NoCommand(SendBotMessageService sendBotMessageService) {
       this.sendBotMessageService = sendBotMessageService;
   }

   @Override
   public void execute(Update update) {
       sendBotMessageService.sendMessage(update.getMessage().getChatId().toString(), NO_MESSAGE);
   }
}
Bu mesele üçin henizem “UnknownCommand” bar:
package com.github.javarushcommunity.jrtb.command;

import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import org.telegram.telegrambots.meta.api.objects.Update;

/**
* Unknown {@link Command}.
*/
public class UnknownCommand implements Command {

   public static final String UNKNOWN_MESSAGE = "Не понимаю вас \uD83D\uDE1F, напишите /help чтобы узнать что я понимаю.";

   private final SendBotMessageService sendBotMessageService;

   public UnknownCommand(SendBotMessageService sendBotMessageService) {
       this.sendBotMessageService = sendBotMessageService;
   }

   @Override
   public void execute(Update update) {
       sendBotMessageService.sendMessage(update.getMessage().getChatId().toString(), UNKNOWN_MESSAGE);
   }
}
Soň bolsa, buýruklarymyz üçin konteýner goşalyň. Buýruk obýektlerimizi saklar we haýyş bilen talap edilýän buýrugy alarys. CommandContainer diýeliň :
package com.github.javarushcommunity.jrtb.command;

import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.google.common.collect.ImmutableMap;

import static com.github.javarushcommunity.jrtb.command.CommandName.*;

/**
* Container of the {@link Command}s, which are using for handling telegram commands.
*/
public class CommandContainer {

   private final ImmutableMap<String, Command> commandMap;
   private final Command unknownCommand;

   public CommandContainer(SendBotMessageService sendBotMessageService) {

       commandMap = ImmutableMap.<string, command="">builder()
               .put(START.getCommandName(), new StartCommand(sendBotMessageService))
               .put(STOP.getCommandName(), new StopCommand(sendBotMessageService))
               .put(HELP.getCommandName(), new HelpCommand(sendBotMessageService))
               .put(NO.getCommandName(), new NoCommand(sendBotMessageService))
               .build();

       unknownCommand = new UnknownCommand(sendBotMessageService);
   }

   public Command retrieveCommand(String commandIdentifier) {
       return commandMap.getOrDefault(commandIdentifier, unknownCommand);
   }

}
Görşüňiz ýaly, hemme zat ýönekeý edildi. Bizde buýruk bahasy görnüşindäki açar we buýruk görnüşindäki buýruk obýekti görnüşindäki üýtgewsiz karta bar. Konstruktorda üýtgewsiz kartany bir gezek doldurýarys we programmanyň işiniň dowamynda oňa girýäris. Konteýner bilen işlemegiň esasy we ýeke-täk usuly “RetrieCommand” (String commandIdentifier) . “UnknownCommand” atly buýruk bar, degişli buýrugy tapyp bilmeýän ýagdaýlarymyz üçin jogapkärdir. Indi konteýni bot synpymyza - JavaRushTelegramBot-da durmuşa geçirmäge taýyn: Bot synpymyz indi şeýle:
package com.github.javarushcommunity.jrtb.bot;

import com.github.javarushcommunity.jrtb.command.CommandContainer;
import com.github.javarushcommunity.jrtb.service.SendBotMessageServiceImpl;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.meta.api.objects.Update;

import static com.github.javarushcommunity.jrtb.command.CommandName.NO;

/**
* Telegram bot for Javarush Community from Javarush community.
*/
@Component
public class JavarushTelegramBot extends TelegramLongPollingBot {

   public static String COMMAND_PREFIX = "/";

   @Value("${bot.username}")
   private String username;

   @Value("${bot.token}")
   private String token;

   private final CommandContainer commandContainer;

   public JavarushTelegramBot() {
       this.commandContainer = new CommandContainer(new SendBotMessageServiceImpl(this));
   }

   @Override
   public void onUpdateReceived(Update update) {
       if (update.hasMessage() && update.getMessage().hasText()) {
           String message = update.getMessage().getText().trim();
           if (message.startsWith(COMMAND_PREFIX)) {
               String commandIdentifier = message.split(" ")[0].toLowerCase();

               commandContainer.retrieveCommand(commandIdentifier).execute(update);
           } else {
               commandContainer.retrieveCommand(NO.getCommandName()).execute(update);
           }
       }
   }

   @Override
   public String getBotUsername() {
       return username;
   }

   @Override
   public String getBotToken() {
       return token;
   }
}
Ine, koda üýtgetmeler girizildi. Muny nädip barlap bilerin? Boty işe girizip, hemme zadyň işleýändigini barlamaly. Munuň üçin programmany.properties-de belligi täzeleýärin, dogrysyny düzýärin we programmany JavarushTelegramBotApplication synpynda işe girizýärin: "A-dan Z-a çenli Java taslamasy": Bot bilen işlemek üçin buýruk nusgasyny durmuşa geçirmek.  1-nji bölümIndi buýruklaryň garaşylyşy ýaly işleýändigini barlamaly. Men ony ädimme-ädim barlaýaryn:
  • StopCommand;
  • StartCommand;
  • Kömek;
  • NoCommand;
  • Näbelli.
Ine, näme boldy: "A-dan Z-a çenli Java taslamasy": Bot bilen işlemek üçin buýruk nusgasyny durmuşa geçirmek.  1-nji bölümBot garaşyşymyz ýaly işledi. Baglanyşyk arkaly dowam etdirilýär .

Tapgyryň ähli materiallarynyň sanawy bu makalanyň başynda.

Teswirler
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION