JavaRush/Java блог/Random UA/Telegram bot - нагадування через webHook на Java або скаж...
Vladimir Popov
41 рівень

Telegram bot - нагадування через webHook на Java або скажи ні Google-календарю! Частина 1

Стаття з групи Random UA
учасників
Мене звати Владимир. Мені 43 роки. І якщо тобі, читачу за 40, то так, після 40 можна стати програмістом, якщо тобі це подобається. Моя робота взагалі ніяк не пов'язана з програмуванням, я керівник проекту в галузі автоматизації та всього такого. Але планую змінити рід діяльності. Ох вже ці нові віяння... змінювати сферу діяльності раз на 5-7 років. Так ось : Проект вийшов не маленький так що деякі моменти доведеться опускати або говорити про них коротко, сподіваючись, що читач вміє гуглити. На просторах інтернетів повно публікацій telegram-ботів, що працюють за принципом Long polling. І дуже мало, що працюють за принципом Webhook. Що це таке? Long polling- означає ваш додаток сам опитуватиме сервер telegram на предмет наявності повідомлень з певною періодичністю, повільно. Webhook - означає сервер telegram миттєво перенаправлятиме повідомлення на вказаний вами сервер. У нашому випадку, люб'язно наданий сервіс Heroku. Докладніше про все це і взагалі про бот можна звичайно ж почитати на сайті Telegram - https://tlgrm.ru/docs/bots/api Інтерфейс бот виглядає ось так: Telegram bot - нагадування через webHook на Java або скажи ні Google-календарю!  - 1 Цей додаток я розглядаю саме як навчальний проект з тієї причини, що при написанні цього бота я засвоїв більше інформації, ніж при навчанні. Бажаєте навчитися програмувати? Почніть писати код! Але! Тут не буде докладних інструкцій, як залити додаток на github, як створити базу даних. Цього всього повно в інтернетах і розписано докладним чином, крім того, це і так вийде дуже довге читання. Додаток буде працювати наступним чином: Вводьте опис події, вводите дату та час події, вибираєте періодичність (можна на один раз, можна нагадування щодня у певний час, можна раз на місяць у певний час, або раз на рік). Варіації сповіщень можна допилювати нескінченно, у самих ідей багато. Далі введені дані зберігаються до бази даних (теж розгорнуто безкоштовно на heroku, безкоштовними є 10 000 рядків) Далі один раз на початку дня о 0:00 за серверним часом Spring витягує з бази всі події за критеріями, які повинні спрацювати в цей день і направляє їх на виконання у встановлений час. УВАГА!!! ЦЯ ЧАСТИНА ПРОГРАМИ ЕКСПЕРЕМЕНТАЛЬНА! ІСНУЄ РЕАЛІЗАЦІЯ БІЛЬШ ПРОСТІЙ І ВІРНА! ТАК ЗРОБЛЕНО СПЕЦІАЛЬНО, ЩОБ ПОДИВИТИСЯ ЯК ПРАЦЮЄ КЛАС Time! Доторкнутися своїми руками працюючого бота можна набравши в возі @calendar_event_bot але не розраховуйте на нього, бо я з нього все ще знущаюся. код - ТАК ЗРОБЛЕНО СПЕЦІАЛЬНО, ЩОБ ПОДИВИТИСЯ ЯК ПРАЦЮЄ КЛАС Time! Доторкнутися своїми руками працюючого бота можна набравши в возі @calendar_event_bot але не розраховуйте на нього, бо я з нього все ще знущаюся. код - ТАК ЗРОБЛЕНО СПЕЦІАЛЬНО, ЩОБ ПОДИВИТИСЯ ЯК ПРАЦЮЄ КЛАС Time! Доторкнутися своїми руками працюючого бота можна набравши в возі @calendar_event_bot але не розраховуйте на нього, бо я з нього все ще знущаюся. код -https://github.com/papoff8295/webHookBotForHabr В принципі, щоб запустити власного вам необхідно зробити наступні кроки: • Пройти реєстрацію в @BotFather , це не складно, отримати токен та ім'я • Зробити fork проекту на github • Зареєструватися на Heroku , створити додаток(покроково розбиратимемо), зробити deploy з вашого репозиторію. • Створити на Heroku базу даних • Замінити в репозиторії відповідні поля на свої (токен, назва таблиць по суті, webHookPath, user name, пароль та шлях до бази, це все буде розбирати) • Змусити heroku працювати 24/7 за допомогою https: / /uptimerobot.com/ Підсумкова структура проекту у мене вийшла така: Telegram bot - нагадування через webHook на Java або скажи ні Google-календарю!  - 2 Почнемо зі створення проекту https://start.spring.ioВибираємо потрібні нам залежності як показано на малюнку: Telegram bot - нагадування через webHook на Java або скажи ні Google-календарю!  - 3Вибираємо власну назву для проекту та натискаємо Generate . Далі вам запропонують зберегти проект на диск. Залишається відкрити файл pom.xm l зі свого середовища розробки. Перед Вами готовий проект. Тепер нам лишилося додати нашу основну бібліотеку. Я використовував бібліотеку з https://github.com/rubenlagus/TelegramBots Загалом можна заморочитися і обійтися без неї. Адже весь зміст роботи полягає в конкатенації URL на кшталт такого: https://api.telegram.org/bot1866835969:AAE6gJG6ptUyqhV2XX0MxyUak4QbAGGnz10/setWebhook?url=https://e9c658b548aa.ngro - Сервер telegram. bot1866835969:AAE6gJG6ptUyqhV2XX0MxyUak4QbAGGnz10/ - після слова bot- секретний токен, який отримуєте при реєстрації бота. setWebhook?url=https://e9c658b548aa.ngrok.io – назва методу та його параметри. В даному випадку ми встановлюємо Ваш webhook сервер, на нього будуть надходити всі повідомлення. Загалом, я вирішив, що проект і так не маленький для публікації, а з ручною реалізацією взагалі буде нечитабельним. Отже, кінцевий вид файлу pom :
<!--?xml version="1.0" encoding="UTF-8"?-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelversion>4.0.0</modelversion>
   <parent>
      <groupid>org.springframework.boot</groupid>
      <artifactid>spring-boot-starter-parent</artifactid>
      <version>2.5.0</version>
      <relativepath> <!-- lookup parent from repository -->
   </relativepath></parent>
   <groupid>ru.popov</groupid>
   <artifactid>telegrambot</artifactid>
   <version>0.0.1-SNAPSHOT</version>
   <name>telegrambot</name>
   <description>Demo project for Spring Boot</description>
   <properties>
      <java.version>1.8</java.version>
   </properties>
   <dependencies>
      <dependency>
         <groupid>org.springframework.boot</groupid>
         <artifactid>spring-boot-starter-web</artifactid>
      </dependency>

      <dependency>
         <groupid>org.springframework.boot</groupid>
         <artifactid>spring-boot-starter-data-jpa</artifactid>
      </dependency>

      <dependency>
         <groupid>org.springframework.boot</groupid>
         <artifactid>spring-boot-starter-test</artifactid>
         <scope>test</scope>
      </dependency>

      <!-- https://mvnrepository.com/artifact/org.telegram/telegrambots-spring-boot-starter -->
      <dependency>
         <groupid>org.telegram</groupid>
         <artifactid>telegrambots-spring-boot-starter</artifactid>
         <version>5.2.0</version>
      </dependency>

      <dependency>
         <groupid>org.projectlombok</groupid>
         <artifactid>lombok</artifactid>
         <version>1.18.16</version>
      </dependency>

      <dependency>
         <groupid>org.postgresql</groupid>
         <artifactid>postgresql</artifactid>
         <scope>runtime</scope>
      </dependency>

   </dependencies>

   <build>
      <plugins>
         <plugin>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-maven-plugin</artifactid>
         </plugin>
      </plugins>
   </build>

</project>
Все готове до написання нашого бота. Створимо клас TelegramBot . Назва папок я писати не буду, можете подивитися у структурі проекту вище.
@Getter
@Setter
@FieldDefaults(level = AccessLevel.PRIVATE)
public class TelegramBot extends SpringWebhookBot {
    String botPath;
    String botUsername;
    String botToken;

    private TelegramFacade telegramFacade;

    public TelegramBot(TelegramFacade telegramFacade, DefaultBotOptions options, SetWebhook setWebhook) {
        super(options, setWebhook);
        this.telegramFacade = telegramFacade;
    }
    public TelegramBot(TelegramFacade telegramFacade, SetWebhook setWebhook) {
        super(setWebhook);
        this.telegramFacade = telegramFacade;
    }

    @Override
    public BotApiMethod<!--?--> onWebhookUpdateReceived(Update update) {
        return telegramFacade.handleUpdate(update);
    }
}
Клас розширюється від SpringWebhookBot з нашої біліотеки telegram, і нам необхідно реалізувати всього один метод onWebhookUpdateReceived . Він приймає рапарсенний JSON як об'єкт Update і повертає те, що хоче від нас «почути» сервер telegram. Тут у нас зустрічаються інструкції з бібліотеки Lombok . Lombok – робимо життя програміста легшим!! Ну, тобто. нам не треба перевизначати гетери та сеттери, це робить за нас Lombok, а також не треба писати ідентифікатор рівня доступу. Вже й не варто писати, що цим займаються анотації @ Getter, @ Setter, @ FieldDefaults Поле botPath – означає нашу адресау webhook, яку ми отримаємо на Heroku пізніше. ПолеbotUsername – це назва нашого бота, яку ми отримаємо при реєстрації нашого бота в Telegram. Поле botToken це наш токен, який ми отримаємо при реєстрації нашого бота в Telegram. Поле telegramFacade - це наш клас, де відбуватиметься обробка повідомлень, до нього ми повернемося трохи пізніше, нехай він поки буде червоним. Тепер нам час звернутися до @BotFather і отримати заповітний botToken і botUsername. Telegram bot - нагадування через webHook на Java або скажи ні Google-календарю!  - 4Просто напишіть йому в telegram і він вам все підкаже. Записуємо дані в наш application.properties, повністю зрештою він виглядатиме ось так:
server#server.port=5000

telegrambot.userName=@calendar_event_bot
telegrambot.botToken=1731265488:AAFDjUSk3vu5SFfgdfh556gOOFmuml7SqEjwrmnEF5Ak
#telegrambot.webHookPath=https://telegrambotsimpl.herokuapp.com/
telegrambot.webHookPath=https://f5d6beeb7b93.ngrok.io


telegrambot.adminId=39376213

eventservice.period =600000

spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/telegramUsers
spring.datasource.username=postgres
spring.datasource.password=password

#spring.datasource.url=jdbc:postgresql:ec2-54-247-158-179.eu-west-1.compute.amazonaws.com:5432/d2um126le5notq?ssl=true&sslmode=require&sslfactory=org.postgresql.ssl.NonValidatingFactory
#spring.datasource.username=ulmbeywyhvsxa
#spring.datasource.password=4c7646c69dbbgeacb98fa96e8daa6d9b1bl4894e67f3f3ddd6a27fe7b0537fd
Ця конфігурація налаштована для роботи з локальною базою даних, згодом ми зробимо необхідні зміни. Замініть botToken та username на свої. Не можна використовувати дані з application.properties безпосередньо в програмі. Створимо з цих даних bean або клас обгортку.
@Component
@Getter
@FieldDefaults(level = AccessLevel.PRIVATE)

public class TelegramBotConfig {
    @Value("${telegrambot.webHookPath}")
    String webHookPath;
    @Value("${telegrambot.userName}")
    String userName;
    @Value("${telegrambot.botToken}")
    String botToken;
Тут інструкція @Value ініціалізує відповідні рядки з файлу application.properties, про цю папку Spring знає за замовчуванням. А анотація @Component створює нам Bean під час запуску програми. Займемося тепер файлом конфігурації Spring:
@Configuration
public class AppConfig {
    private final TelegramBotConfig botConfig;

    public AppConfig(TelegramBotConfig botConfig) {
        this.botConfig = botConfig;
    }

    @Bean
    public SetWebhook setWebhookInstance() {
        return SetWebhook.builder().url(botConfig.getWebHookPath()).build();
    }

    @Bean
    public TelegramBot springWebhookBot(SetWebhook setWebhook, TelegramFacade telegramFacade) {
        TelegramBot bot = new TelegramBot(telegramFacade, setWebhook);
        bot.setBotToken(botConfig.getBotToken());
        bot.setBotUsername(botConfig.getUserName());
        bot.setBotPath(botConfig.getWebHookPath());

        return bot;
    }
}
Жодної магії тут немає, при старті Spring створює нам об'єкти SetWebhook і TelegramBot. Створимо тепер точки входу наших повідомлень:
@RestController
public class WebhookController {

    private final TelegramBot telegramBot;

    public WebhookController(TelegramBot telegramBot) {
        this.telegramBot = telegramBot;
    }

// point for message
    @PostMapping("/")
    public BotApiMethod<!--?--> onUpdateReceived(@RequestBody Update update) {
        return telegramBot.onWebhookUpdateReceived(update);
    }

    @GetMapping
    public ResponseEntity get() {
        return ResponseEntity.ok().build();
    }
}
Telegram сервер відправляє на зареєстровану адресау webhook повідомлення у форматі JSON методом POST, наш контролер їх приймає та передає бібліотеці telegram у вигляді об'єкта Update. Метод get я зробив просто так ) Тепер нам залишилося реалізувати якусь логіку обробки повідомлень та відповіді у класі TelegramFacade , я наведу його короткий код, щоб уже можна було запускати програму і далі йти своїм шляхом або перейти вже у deploy на Heroku, потім буде повна версія:
@Component
@FieldDefaults(level = AccessLevel.PRIVATE)
public class TelegramFacade {

    public BotApiMethod<!--?--> handleUpdate(Update update) {

        if (update.hasCallbackQuery()) {
            CallbackQuery callbackQuery = update.getCallbackQuery();
            return null;
        } else {

            Message message = update.getMessage();
            SendMessage sendMessage = new SendMessage();
            sendMessage.setChatId(String.valueOf(message.getChatId()));
            if (message.hasText()) {
                sendMessage.setText("Hello world");
                return sendMessage;
            }
        }
        return null;
    }

}
Цей метод відповідатиме на будь-яке повідомлення Hello world! Для того, щоб запустити наш додаток нам залишилося зробити так, щоб ми могли тестувати нашу програму прямо з IDEA. Для цього нам необхідно завантажити утиліту ngrok. https://ngrok.com/download Ця утиліта є командним рядком, який дає нам тимчасову адресау на 2 години і перенаправляє всі повідомлення на вказаний порт локального сервера. Запускаємо та пишемо у рядку ngrok http 5000 (або можете вказати свій порт): Telegram bot - нагадування через webHook на Java або скажи ні Google-календарю!  - 5Отримуємо результат: Telegram bot - нагадування через webHook на Java або скажи ні Google-календарю!  - 6https://23b1a54ccbbd.ngrok.io – це і є наша webhook адресаа. Як ви могли помітити у файлі properties ми написали server.port=5000 при старті сервера tomcat, він буде займати порт 5000, стежте, щоб ці поля були однакові. Також не забуваємо, що адресаа дається на дві години. У командному рядку за цим слідкує поле Session Expires. Коли час скінчиться потрібно буде знову отримати адресау і пройти процедуру його реєстрації на telegram. Тепер беремо рядок . отриманий рядок та натискаємо enter. Повинен вийде такий результат: Telegram bot - нагадування через webHook на Java або скажи ні Google-календарю!  - 7Все, тепер можна запускати додаток: Telegram bot - нагадування через webHook на Java або скажи ні Google-календарю!  - 8Перевірте, що Ваш клас з методомmain , був такий:
@SpringBootApplication
public class TelegramBotApplication {

   public static void main(String[] args) {
      SpringApplication.run(TelegramBotApplication.class, args);
   }
}
Якщо Ви все зробабо правильно, то тепер Ваш бот буде відгукуватися на будь-яке повідомлення фразою - Hello world . Далі можете йти своїм шляхом. Якщо ж Ви зі мною і Вам цікаво піти всі кроки, то приступимо до написання сутностей бази даних і створимо саму базу даних. Почнемо з бази: Як я вже казав, вважаю, що Ви вже маєте мінімальні навички роботи з базою, і у вас встановлена ​​локальна база postgreSQL , якщо ні пройдіть цей шлях. https://www.postgresql.org/download/ У файлі application.properties замініть логін та пароль до бази даних на свої. У IDEA справа є вкладка database, у ній потрібно натиснути на +/Data source/PostgreSQL . В результаті при натисканні на Test Connectionповинні отримати задовільний результат: Telegram bot - нагадування через webHook на Java або скажи ні Google-календарю!  - 9Тепер ви можете створити базу з таблицями прямо із середовища розробки, а можете скористатися web-інтерфейсом pgadmin , який знаходиться в меню пуск. Нам знадобляться 3 таблиці:
CREATE TABLE users
(
    id               INTEGER PRIMARY KEY UNIQUE NOT NULL,
    name             VARCHAR,
    time_zone        INTEGER DEFAULT 0,
    on_off           BOOLEAN DEFAULT true
);

CREATE TABLE user_events
(
    user_id INTEGER ,
    time timestamp ,
    description varchar ,
    event_id serial,
    event_freq varchar default 'TIME',
    FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
);

CREATE TABLE event_cash
(
    time timestamp ,
    description varchar ,
    user_id INTEGER ,
    id serial
);
Рекомендую створити окремо цей скрипт, він нам знадобиться для створення бази на Heroku, щоб не писати двічі. Пройдемося трохи. Відразу скажу таблиця event_cash нам знадобиться тільки для роботи з Heroku у зв'язку з його специфікою та моїм невгамовним бажанням попрацювати з класом Time , в локальній версії він не знадобиться. У таблицю users ми будемо записувати id облікового запису користувача telegram, його ім'я, якого може і не бути, буде розрахований часовий пояс користувача, для коректної відправки повідомлень, а також стан on/off розсилки повідомлень. У таблицю user_events у нас записуватиметься idкористувача, час повідомлення, опис, буде автоматично генеруватися id для події, та встановлюватиметься частота повідомлень. У таблиці event_cash буде записуватися повідомлення перед відправкою, і, якщо воно надіслано, видалятися з таблиці. Таблиці готові, давайте тепер додамо сутності.
@Entity
@Table(name = "user_events")
@Getter
@Setter
public class Event {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column( name = "event_id", columnDefinition = "serial")
    private int eventId;

    @Column(name = "time")
    @NotNull(message = "Need date!")
    private Date date;

    @Column(name = "description")
    @Size(min = 4, max = 200, message = "Description must be between 0 and 200 chars!")
    private String description;

    @Column(name = "event_freq", columnDefinition = "TIME")
    @Enumerated(EnumType.STRING)
    private EventFreq freq;

    @ManyToOne(fetch=FetchType.EAGER)
    @JoinColumn(name="user_id")
    @OnDelete(action = OnDeleteAction.CASCADE)
    private User user;

    public Event() {
    }

    public Event(int eventId,
                 @NotNull(message = "Need date!") Date date,
                 @Size(min = 4, max = 200, message = "Description must be between 0 and 200 chars!")
                         String description,
                 EventFreq freq, User user) {
        this.eventId = eventId;
        this.date = date;
        this.description = description;
        this.freq = freq;
        this.user = user;
    }
}
@Entity
@Table(name = "users")
@Getter
@Setter
public class User {

    @Id
    @Column(name = "id")
    private long id;

    @Column(name = "name")
    private String name;

    @Column(name = "time_zone", columnDefinition = "default 0")
    //sets the broadcast time of events for your time zone
    private int timeZone;

    @OneToMany(mappedBy="user")
    private List<event> events;

    @Column(name = "on_off")
    // on/off send event
    private boolean on;

    public User() {
    }
}

</event>
@Entity
@Table(name = "event_cash")
@Getter
@Setter
//serves to save unhandled events after rebooting heroku
public class EventCashEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column( name = "id", columnDefinition = "serial")
    private long id;

    @Column(name = "time")
    private Date date;

    @Column(name = "description")
    private String description;

    @Column(name = "user_id")
    private long userId;

    public EventCashEntity() {
    }

    public static EventCashEntity eventTo(Date date, String description, long userId) {
        EventCashEntity eventCashEntity = new EventCashEntity();
        eventCashEntity.setDate(date);
        eventCashEntity.setDescription(description);
        eventCashEntity.setUserId(userId);
        return eventCashEntity;
    }
}
Трохи пробіжимося основними моментами. @Entity – позначає клас нашого dada jpa, що це клас є сутністю для бази даних, тобто. при наданні даних з бази вони будуть представлені нам у вигляді об'єкта Event, User і EventCashEntity. @Table - кажемо як називається наша таблиця в базі даних. Для того, щоб назва таблиці не підкреслювалася червоною, нам потрібно в IDEA погодитися із запропонованим варіантом виправлення помилки і натиснути Assign data sources. І вибрати там нашу основу. @id і @GeneratedValue – використовується Spring для створення бази даних, якщо її ще немає. @Column – використовується для позначення назви полів у таблиці, якщо вони збігаються, але правила хорошого коду рекомендують це писати. СтавленняOneToMany - рекомендую витратити час і розібратися що це таке тут https://en.wikibooks.org/wiki/Java_Persistence Я не зможу викласти більш зрозуміло, просто повірте. Скажу лише, що в даному випадку анотація @OneToMany каже, що в одного користувача може бути багато подій, і вони будуть надані нам у вигляді списку. Тепер нам треба діставати дані із таблиць. У бібліотеці SRING DATA JPA вже все за нас написано, нам треба просто створити інтерфейс для кожної таблиці та розширити його від JpaRepository.
public interface EventRepository extends JpaRepository<event, long=""> {
    Event findByEventId(long id);
}
public interface UserRepository extends JpaRepository<user, long=""> {

    User findById(long id);
}
public interface EventCashRepository extends JpaRepository<eventcashentity, long=""> {
    EventCashEntity findById(long id);
}

</eventcashentity,></user,></event,>
Основну логіку роботи з базою даних винесено на сервіс, так званий Data Access Object(DAO):
@Service
public class UserDAO {

    private final UserRepository userRepository;

    @Autowired
    public UserDAO(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public User findByUserId(long id) {
        return userRepository.findById(id);
    }

    public List<user> findAllUsers() {
        return userRepository.findAll();
    }

    public void removeUser(User user) {
        userRepository.delete(user);
    }


    public void save(User user) {
        userRepository.save(user);
    }

    public boolean isExist(long id) {
        User user = findByUserId(id);
        return user != null;
    }
}
@Service
public class EventDAO {

    private final UserRepository userRepository;
    private final EventRepository eventRepository;

    @Autowired
    public EventDAO(UserRepository userRepository, EventRepository eventRepository) {
        this.userRepository = userRepository;
        this.eventRepository = eventRepository;
    }

    public List<event> findByUserId(long userId) {
        User user = userRepository.findById(userId);
        return user.getEvents();
    }
    public List<event> findAllEvent() {
       return eventRepository.findAll();
    }

    public Event findByEventId(long eventId) {
        return eventRepository.findByEventId(eventId);
    }

    public void remove(Event event) {
        eventRepository.delete(event);
    }

    public void save(Event event) {
        eventRepository.save(event);
    }
}

</event></event></user>
@Service
//handles events not dispatched after reboot heroku
public class EventCashDAO {

    private EventCashRepository eventCashRepository;

    @Autowired
    public void setEventCashRepository(EventCashRepository eventCashRepository) {
        this.eventCashRepository = eventCashRepository;
    }

    public List<eventcashentity> findAllEventCash() {
        return eventCashRepository.findAll();
    }

    public void save(EventCashEntity eventCashEntity) {
        eventCashRepository.save(eventCashEntity);
    }

    public void delete(long id) {
        eventCashRepository.deleteById(id);
    }
}

</eventcashentity>
В даному випадку ми не маємо ніякої обробки даних, ми просто дістаємо дані з таблиць. У нас все готово, щоб привести повний код класу T elegramFacade і почати розбирати логіку.
@Component
@FieldDefaults(level = AccessLevel.PRIVATE)
public class TelegramFacade {

    final MessageHandler messageHandler;
    final CallbackQueryHandler callbackQueryHandler;
    final BotStateCash botStateCash;

    @Value("${telegrambot.adminId}")
    int adminId;


    public TelegramFacade(MessageHandler messageHandler, CallbackQueryHandler callbackQueryHandler, BotStateCash botStateCash) {
        this.messageHandler = messageHandler;
        this.callbackQueryHandler = callbackQueryHandler;
        this.botStateCash = botStateCash;
    }

    public BotApiMethod<!--?--> handleUpdate(Update update) {

        if (update.hasCallbackQuery()) {
            CallbackQuery callbackQuery = update.getCallbackQuery();
            return callbackQueryHandler.processCallbackQuery(callbackQuery);
        } else {

            Message message = update.getMessage();
            if (message != null && message.hasText()) {
                return handleInputMessage(message);
            }
        }
        return null;
    }

    private BotApiMethod<!--?--> handleInputMessage(Message message) {
        BotState botState;
        String inputMsg = message.getText();
        //we process messages of the main menu and any other messages
        //set state
        switch (inputMsg) {
            case "/start":
                botState = BotState.START;
                break;
            case "Мои напоминания":
                botState = BotState.MYEVENTS;
                break;
            case "Создать напоминание":
                botState = BotState.CREATE;
                break;
            case "Отключить напоминания":
            case "Включить напоминания":
                botState = BotState.ONEVENT;
                break;
            case "All users":
                if (message.getFrom().getId() == adminId)
                botState = BotState.ALLUSERS;
                else botState = BotState.START;
                break;
            case "All events":
                if (message.getFrom().getId() == adminId)
                botState = BotState.ALLEVENTS;
                else botState = BotState.START;
                break;
            default:
                botState = botStateCash.getBotStateMap().get(message.getFrom().getId()) == null?
                        BotState.START: botStateCash.getBotStateMap().get(message.getFrom().getId());
        }
        //we pass the corresponding state to the handler
        //the corresponding method will be called
        return messageHandler.handle(message, botState);

    }
}
Розберемо для чого потрібні поля
final MessageHandler messageHandler;
    final CallbackQueryHandler callbackQueryHandler;
    final BotStateCash botStateCash;
Якщо ми всі кодуватимемо в одному класі, то в нас вийде онуча до місяця, у зв'язку з цим ми відносимо логіку роботи з текстовими повідомленнями в клас MessageHandler, логіку роботи з повідомленнями callbackquery в клас СallbackQueryHandler . Настав час розібрати, що таке c allbackquery і які види меню бувають. Для цього наведу ще раз картинку з інтерфейсом робота: Telegram bot - нагадування через webHook на Java або скажи ні Google-календарю!  - 10Бувають два типи меню. Ті, що закріплені знизу вікна - основне меню, і ті, що закріплені за повідомленням, наприклад, кнопки видалити, редагувати, змінити пояс. При натисканні на кнопку основного меню надсилається однойменне повідомлення, наприклад, при натисканні «Мої нагадування» , буде просто надіслано текст «Мої нагадування». А при встановленні клавіатури callbackquery, для кожної кнопки встановлюється певне значення і буде спрямоване значення без виведення на екран. Далі у нас є поле BotStateCash . Це спеціально створений клас, який стежитиме за станом бота, і увага, це складний елемент, треба напружитися. Було перевищено кількість символів, про що, до речі ніде не нписано )). Так що ось посилання на другу частину
Коментарі
  • популярні
  • нові
  • старі
Щоб залишити коментар, потрібно ввійти в систему
Для цієї сторінки немає коментарів.