JavaRush /Blog Java /Random-PL /Bot telegramowy - przypomnienie przez webHook w Javie lub...
Vladimir Popov
Poziom 41

Bot telegramowy - przypomnienie przez webHook w Javie lub powiedz nie kalendarzowi Google! Część 1

Opublikowano w grupie Random-PL
Nazywam się Włodzimierz. Mam 43 lata. A jeśli Ty, czytelniku, masz ponad 40 lat, to tak, po 40-tce możesz zostać programistą, jeśli lubisz. Moja praca nie ma nic wspólnego z programowaniem, jestem kierownikiem projektu z zakresu automatyki i tak dalej. Planuję jednak zmienić zawód. Ach te nowe trendy... zmieniaj pole działania co 5-7 lat. A więc : Projekt okazał się dość duży, więc niektóre punkty trzeba będzie pominąć lub krótko omówić, w nadziei, że czytelnik wie, jak korzystać z Google. W Internecie pełno jest publikacji na temat botów telegramowych działających na zasadzie Long poll. Niewiele jest takich, które działają na zasadzie Webhook. Co to jest? Długie odpytywanie — oznacza to, że Twoja aplikacja będzie powoli odpytywać serwer telegramów w poszukiwaniu wiadomości z określoną częstotliwością. Webhook — oznacza, że ​​serwer telegramów będzie natychmiast przekierowywał wiadomości na wskazany przez Ciebie serwer. W naszym przypadku dzięki uprzejmości serwisu Heroku. Możesz oczywiście przeczytać więcej o tym wszystkim i ogólnie o bocie na stronie Telegramu - https://tlgrm.ru/docs/bots/api Interfejs bota wygląda tak: Bot telegramowy - przypomnienie przez webHook w Javie lub powiedz nie kalendarzowi Google!  - 1 Uważam tę aplikację właśnie za szkolenie projekt z tego powodu, że pisząc, dowiedziałem się od tego bota więcej informacji niż na szkoleniu. Chcesz nauczyć się programować? Zacznij pisać kod!!! Ale! Nie będzie szczegółowej instrukcji jak wgrać aplikację na github czy jak stworzyć bazę danych. Jest tego mnóstwo w Internecie i jest to szczegółowo opisane, a poza tym będzie to bardzo długa lektura. Aplikacja będzie działać w następujący sposób: Wprowadź opis wydarzenia, wprowadź datę i godzinę wydarzenia, wybierz częstotliwość (możesz to zrobić raz, możesz mieć przypomnienie codziennie o określonej godzinie, możesz mieć to raz co miesiąc o określonej porze lub raz w roku). Warianty powiadomień można dodawać w nieskończoność, pomysłów mam mnóstwo. Następnie wprowadzone dane są zapisywane w bazie danych (również wdrożone bezpłatnie na Heroku, 10 000 wierszy jest bezpłatnych) Następnie raz na początku dnia o godzinie 0:00 czasu serwera Spring pobiera z bazy danych wszystkie zdarzenia w oparciu o kryteria który powinien odpalić tego dnia i wysłać je do wykonania o określonej godzinie. UWAGA!!! TA CZĘŚĆ PROGRAMU JEST EKSPERYMENTALNA! ISTNIEJE REALIZACJA, KTÓRA JEST BARDZIEJ PROSTA I PRAWDZIWA! ZROBIONO TO SPECJALNIE ABY ZOBACZYĆ, JAK DZIAŁAJĄ KLASY CZASOWE! Możesz dotknąć działającego bota własnymi rękami, wpisując w koszyku @calendar_event_bot, ale nie licz na to, bo wciąż się z tego śmieję. kod - https://github.com/papoff8295/webHookBotForHabr Zasadniczo, aby uruchomić własny, musisz wykonać następujące kroki: • Zarejestruj się w @BotFather , to nie jest trudne, zdobądź token i nazwę • Forkuj projekt na githubie • Zarejestruj się na Heroku, utwórz aplikację (przejdziemy przez to krok po kroku), wdróż ze swojego repozytorium. • Utwórz bazę danych na Heroku • Zamień odpowiednie pola w repozytorium na własne (token, nazwa tabel w encjach, webHookPath, nazwa użytkownika, hasło i ścieżka do bazy danych, wszystko zostanie przeanalizowane) • Spraw, aby Heroku działało 24/ 7 za pomocą https:// /uptimerobot.com/ Ostateczna struktura projektu wygląda następująco: Bot telegramowy - przypomnienie przez webHook w Javie lub powiedz nie kalendarzowi Google!  - 2 Zacznijmy od stworzenia projektu w https://start.spring.io Wybierz potrzebne nam zależności jak pokazano na rysunku: Bot telegramowy - przypomnienie przez webHook w Javie lub powiedz nie kalendarzowi Google!  - 3Wybierz własne nazwę projektu i kliknij opcję Generuj . Następnie zostaniesz poproszony o zapisanie projektu na dysku. Pozostaje tylko otworzyć plik pom.xml l ze środowiska programistycznego. Przed Tobą gotowy projekt. Teraz musimy tylko dodać naszą główną bibliotekę. Korzystałem z biblioteki z https://github.com/rubenlagus/TelegramBots Ogólnie rzecz biorąc, można się pomylić i obejść się bez niej. Przecież cały sens tej pracy polega na połączeniu adresu URL w następujący sposób: https://api.telegram.org/bot1866835969:AAE6gJG6ptUyqhV2XX0MxyUak4QbAGGnz10/setWebhook?url=https://e9c658b548aa.ngrok.io Przyjrzyjmy się temu trochę : https://api.telegram.org – serwer telegramów. bot1866835969:AAE6gJG6ptUyqhV2XX0MxyUak4QbAGGnz10/ - po słowie bot znajduje się tajny token, który otrzymujesz podczas rejestracji bota. setWebhook?url=https://e9c658b548aa.ngrok.io – nazwa metody i jej parametry. W takim przypadku instalujemy Twój serwer webhook, wszystkie wiadomości będą do niego wysyłane. Generalnie stwierdziłem, że projekt nie jest za mały na publikację, ale przy ręcznym wdrożeniu byłby w ogóle nieczytelny. Ostateczny wygląd pliku pom wygląda następująco:
<!--?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>
Wszystko jest gotowe do napisania naszego bota. Stwórzmy klasę TelegramBot . Nazw folderów nie będę pisać, możesz je obejrzeć w strukturze projektu powyżej.
@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);
    }
}
Klasa stanowi rozszerzenie SpringWebhookBot z naszej biblioteki telegramów i wystarczy zaimplementować tylko jedną metodę onWebhookUpdateReceived . Akceptuje przeanalizowany JSON jako obiekt Update i zwraca to, co serwer telegramów chce od nas „usłyszeć”. Tutaj mamy adnotacje z biblioteki Lombok . Lombok – ułatwienie życia programisty!! Cóż, to znaczy. nie musimy na nowo definiować metod pobierających i ustawiających, robi to za nas Lombok i nie musimy też pisać identyfikatora poziomu dostępu. Nie warto już pisać, że robią to adnotacje @Getter, @Setter, @FieldDefaults Pole botPath oznacza adres naszego webhooka, który otrzymamy później na Heroku. Pole botUsername oznacza nazwę naszego bota, którą otrzymamy podczas rejestracji naszego bota w Telegramie. Pole botToken to nasz token, który otrzymamy podczas rejestracji naszego bota w Telegramie. Pole telegramFacade to nasza klasa, w której będzie odbywać się przetwarzanie wiadomości, wrócimy do niego nieco później, niech na razie będzie czerwone. Teraz nadszedł czas, abyśmy skontaktowali się z @BotFather i zdobyli pożądany botToken i botUsername. Bot telegramowy - przypomnienie przez webHook w Javie lub powiedz nie kalendarzowi Google!  - 4Napisz do niego na telegramie, a on ci wszystko powie. Zapisujemy dane do naszej aplikacji.properties, finalnie będzie to wyglądało tak:
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
Konfiguracja ta jest skonfigurowana do pracy z lokalną bazą danych, później dokonamy niezbędnych zmian. Zamień botToken i nazwę użytkownika na własną. Niedobrze jest wykorzystywać dane z application.properties bezpośrednio w aplikacji. Utwórzmy komponent bean lub klasę opakowania na podstawie tych danych.
@Component
@Getter
@FieldDefaults(level = AccessLevel.PRIVATE)

public class TelegramBotConfig {
    @Value("${telegrambot.webHookPath}")
    String webHookPath;
    @Value("${telegrambot.userName}")
    String userName;
    @Value("${telegrambot.botToken}")
    String botToken;
Tutaj adnotacja @Value inicjuje odpowiednie linie z pliku application.properties, o którym Spring domyślnie wie. Adnotacja @Component tworzy dla nas komponent Bean po uruchomieniu aplikacji. Przejdźmy teraz do pliku konfiguracyjnego Springa:
@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;
    }
}
Nie ma tu żadnej magii, Spring przy starcie tworzy za nas obiekty SetWebhook i TelegramBot. Stwórzmy teraz punkty wejścia dla naszych wiadomości:
@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();
    }
}
Serwer Telegramu wysyła wiadomości w formacie JSON na zarejestrowany adres webhooka przy użyciu metody POST, nasz kontroler odbiera je i przesyła do biblioteki telegramów w postaci obiektu Update. Zrobiłem metodę get w ten sposób) Teraz musimy tylko zaimplementować logikę przetwarzania wiadomości i odpowiedzi w klasie TelegramFacade , podam jej krótki kod, abyś mógł uruchomić aplikację, a następnie pójść własną drogą lub przejść do wdrożenia na Heroku, wtedy będzie pełna wersja:
@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;
    }

}
Ta metoda zareaguje na dowolne Hello world! Aby uruchomić naszą aplikację, musimy się jedynie upewnić, że możemy przetestować naszą aplikację bezpośrednio z IDEA. Aby to zrobić, musimy pobrać narzędzie ngrok. https://ngrok.com/download To narzędzie jest wierszem poleceń, które daje nam tymczasowy adres na 2 godziny i przekierowuje wszystkie wiadomości na określony port lokalnego serwera. Uruchamiamy i w linii wpisujemy ngrok http 5000 (lub możesz podać swój port): Bot telegramowy - przypomnienie przez webHook w Javie lub powiedz nie kalendarzowi Google!  - 5Otrzymujemy wynik: Bot telegramowy - przypomnienie przez webHook w Javie lub powiedz nie kalendarzowi Google!  - 6https://23b1a54ccbbd.ngrok.io - to jest adres naszego webhooka. Jak być może zauważyłeś w pliku właściwości, który podczas uruchamiania serwera Tomcat zapisaliśmy server.port=5000, zajmie on port 5000, upewnij się, że te pola są takie same. Nie zapominaj również, że adres jest podawany na dwie godziny. W wierszu poleceń jest to monitorowane za pomocą pola Session Expires. Kiedy skończy się czas, konieczne będzie ponowne uzyskanie adresu i przejście procedury rejestracji go w telegramie. Teraz przyjmujemy linię https://api.telegram.org/bot1866835969:AAE6gJG6ptUyqhV2XX0MxyUak4QbAGGnz10/setWebhook?url=https://e9c658b548aa.ngrok.io I zręcznymi ruchami dłoni zastępujemy token naszym, adres URL naszym, wklejamy wynikowy wiersz do przeglądarki i kliknij Enter. Powinieneś otrzymać następujący wynik: Bot telegramowy - przypomnienie przez webHook w Javie lub powiedz nie kalendarzowi Google!  - 7To wszystko, teraz możesz uruchomić aplikację: Bot telegramowy - przypomnienie przez webHook w Javie lub powiedz nie kalendarzowi Google!  - 8Sprawdź, czy Twoja klasa z metodą główną wyglądała następująco:
@SpringBootApplication
public class TelegramBotApplication {

   public static void main(String[] args) {
      SpringApplication.run(TelegramBotApplication.class, args);
   }
}
Jeśli wszystko zrobiłeś poprawnie, teraz Twój bot odpowie na każdą wiadomość z frazą „ Witaj, świecie” . Wtedy możesz iść swoją drogą. Jeśli jesteś ze mną i jesteś zainteresowany przejściem przez wszystkie kroki, to zacznijmy pisać encje do bazy danych i stwórzmy samą bazę danych. Zacznijmy od bazy danych: Jak już mówiłem, zakładam, że masz już minimalne umiejętności pracy z bazą danych i masz zainstalowaną lokalną bazę danych PostgreSQL , jeśli nie, podążaj tą ścieżką. https://www.postgresql.org/download/ W pliku application.properties zamień login i hasło do bazy danych na własne. W IDEA po prawej stronie znajduje się zakładka baza danych, w której należy kliknąć +/Data source/PostgreSQL . W rezultacie po kliknięciu Testuj połączenie powinieneś uzyskać zadowalający wynik: Bot telegramowy - przypomnienie przez webHook w Javie lub powiedz nie kalendarzowi Google!  - 9Teraz możesz utworzyć bazę danych z tabelami bezpośrednio ze środowiska programistycznego lub możesz skorzystać z interfejsu sieciowego pgadmin , który znajduje się w menu Start. Będziemy potrzebować 3 tabel:
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
);
Polecam stworzyć ten skrypt osobno, będzie nam potrzebny do stworzenia bazy danych na Heroku, żeby nie pisać go dwa razy. Przejdźmy się trochę. Od razu powiem, że do pracy z Heroku potrzebujemy jedynie tabeli event_cash ze względu na jej specyfikę i moją nienasyconą chęć pracy z klasą Time ; w wersji lokalnej nie będzie ona przydatna. W tabeli użytkowników zapiszemy identyfikator konta użytkownika telegramu, jego nazwę, która może nie istnieć, wyliczona zostanie strefa czasowa użytkownika pod kątem prawidłowego wysyłania powiadomień oraz status włączenia/wyłączenia wysyłania powiadomień. Zapiszemy identyfikator użytkownika, czas powiadomienia, opis w tabeli user_events , automatycznie wygenerujemy identyfikator zdarzenia i ustalimy częstotliwość powiadomień. Tabela event_cash zarejestruje powiadomienie przed jego wysłaniem i jeśli zostanie wysłane, usunie je z tabeli. Tabele są gotowe, teraz dodajmy encje.
@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;
    }
}
Omówmy trochę główne punkty. @Entity – zaznacza klasę dla naszego Dada jpa, że ​​ta klasa jest bytem dla bazy danych, tj. podczas pobierania danych z bazy zostaną nam one zaprezentowane w postaci obiektu Event, User oraz EventCashEntity. @Table – podajemy nazwę naszej tabeli w bazie danych. Aby mieć pewność, że nazwa tabeli nie zostanie podkreślona na czerwono, musimy zgodzić się w IDEA z proponowaną opcją korekcji błędów i kliknąć Przypisz źródła danych. I wybierz tam naszą bazę. @id i @GeneratedValue - używane przez Springa do tworzenia bazy danych, jeśli jeszcze nie istnieje. @Kolumna służy do wskazania nazw pól w tabeli, jeśli nie pasują, ale zasady dobrego kodu zalecają, aby zawsze to pisać. Postawa OneToMany - polecam spędzić czas i dowiedzieć się, co to jest tutaj https://en.wikibooks.org/wiki/Java_Persistence Nie potrafię tego jaśniej wytłumaczyć, po prostu mi uwierz. Powiem tylko, że w tym przypadku adnotacja @OneToMany mówi, że jeden użytkownik może mieć wiele zdarzeń i zostaną one nam przekazane w formie listy. Teraz musimy pobrać dane z tabel. W bibliotece SRING DATA JPA wszystko jest już za nas napisane, pozostaje nam tylko stworzyć interfejs dla każdej tabeli i rozszerzyć go z 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,>
Główna logika pracy z bazą danych przeniesiona jest do usługi tzw. 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>
W tym przypadku nie mamy do czynienia z żadnym przetwarzaniem danych, po prostu pobieramy dane z tabel. Wszyscy jesteśmy gotowi dostarczyć pełny kod klasy TelegramFacade i zacząć analizować logikę.
@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);

    }
}
Przyjrzyjmy się, do jakich pól są potrzebne
final MessageHandler messageHandler;
    final CallbackQueryHandler callbackQueryHandler;
    final BotStateCash botStateCash;
Jeżeli wszyscy będziemy kodować w jednej klasie, to wylądujemy z nogą na księżycu, dlatego logikę pracy z wiadomościami tekstowymi przypisujemy klasie MessageHandler , a logikę pracy z wiadomościami callbackquery – klasie CallbackQueryHandler . Czas dowiedzieć się, czym jest allbackquery i jakie są rodzaje menu. Aby to zrobić, pokażę inny obraz interfejsu bota: Bot telegramowy - przypomnienie przez webHook w Javie lub powiedz nie kalendarzowi Google!  - 10Istnieją dwa typy menu. Te, które są dołączone na dole okna - menu główne, oraz te, które są przypisane do wiadomości, np. przyciski usuwania, edycji, zmiany paska. Po kliknięciu przycisku menu głównego zostanie wysłana wiadomość o tej samej nazwie, na przykład po kliknięciu „Moje przypomnienia” zostanie po prostu wysłany tekst „Moje przypomnienia” . A podczas instalowania klawiatury callbackquery dla każdego przycisku ustawiana jest konkretna wartość, a jej wartość zostanie wysłana bez wyświetlania jej na ekranie. Następnie mamy pole BotStateCash . Jest to specjalnie utworzona klasa, która będzie monitorować stan bota, a uwaga, to skomplikowany element, trzeba się namęczyć. Przekroczono liczbę znaków, która, nawiasem mówiąc, nie jest nigdzie zapisana)). Oto link do części drugiej
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION