JavaRush /Blog Java /Random-PL /Dodanie klienta do artykułów - "Projekt Java od A do Z"
Roman Beekeeper
Poziom 35

Dodanie klienta do artykułów - "Projekt Java od A do Z"

Opublikowano w grupie Random-PL
Witam wszystkich, moi drodzy przyjaciele. Krok po kroku jesteśmy coraz bliżej naszego celu - zostania MVP naszego projektu - JavaRush Telegram Bot. Jak wspomniałem w ostatnim artykule, pozostało już tylko 5 zadań. Dziś omówimy dwa z nich. „Projekt Java od A do Z”: Dodawanie klienta do artykułów - 1Chcę powtórzyć, że projekt na tym się nie zakończy. Mam jeszcze mnóstwo pomysłów i wizji, jak ten projekt powinien się rozwijać, co nowego można do niego dodać, co można zrobić lepiej. Przed MVP zrobimy osobny artykuł na temat refaktoryzacji – czyli poprawy jakości kodu bez zmiany jego funkcjonalności. Do tego czasu cały projekt będzie widoczny i będzie jasne, co i gdzie można poprawić. W naszym przypadku będziemy maksymalnie zabezpieczeni przed złamaniem funkcjonalności, ponieważ napisano wiele testów. Napiszemy też retrospektywę o tym, czego chcieliśmy i co ostatecznie otrzymaliśmy. To bardzo przydatna rzecz: zobaczmy, jak poprawnie wszystko było widziane sześć miesięcy temu. Przynajmniej dla mnie jest to bardzo interesujące. Jeśli ktoś chciałby spróbować swoich sił w roli testera manualnego, napisz do nas, a nawiążemy współpracę. Razem ulepszymy ten projekt! A więc oto one: dwa zadania opisane sześć miesięcy temu: JRTB-8 i JRTB-9 . Zacząłem się zastanawiać, co należy wdrożyć w przypadku tych zadań i zdałem sobie sprawę, że jeśli chodzi o uruchamianie poleceń, wszystko było już gotowe. To się zdarza...) Tutaj możesz przyjrzeć się StartCommand , metodzie wykonania :
@Override
public void execute(Update update) {
   String chatId = update.getMessage().getChatId().toString();

   telegramUserService.findByChatId(chatId).ifPresentOrElse(
           user -> {
               user.setActive(true);
               telegramUserService.save(user);
           },
           () -> {
               TelegramUser telegramUser = new TelegramUser();
               telegramUser.setActive(true);
               telegramUser.setChatId(chatId);
               telegramUserService.save(telegramUser);
           });

   sendBotMessageService.sendMessage(chatId, START_MESSAGE);
}
Tutaj działa logika: jeśli w naszej bazie danych jest już taki użytkownik o chatId, to po prostu ustawiamy dla niego pole active=true. A jeśli nie ma takiego użytkownika, tworzymy nowego. To samo dotyczy polecenia /stop w StopCommand :
@Override
public void execute(Update update) {
   telegramUserService.findByChatId(update.getMessage().getChatId().toString())
           .ifPresent(it -> {
               it.setActive(false);
               telegramUserService.save(it);
           });
   sendBotMessageService.sendMessage(update.getMessage().getChatId().toString(), STOP_MESSAGE);
}
Można zauważyć, że przy wywołaniu tego polecenia dla użytkownika ustawiane jest tylko pole active = false. I tyle: jego subskrypcje przetrwają i poczekają, gdy użytkownik ponownie zdecyduje się aktywować czat z botem. I wydawałoby się, że zadanie zostało już wykonane i można je zamknąć. Ale tego tam nie było. Najważniejszym zadaniem jest utworzenie alertu o nowych artykułach w prenumeracie. Tutaj te zadania zostaną całkowicie zaktualizowane i zakończone. Oznacza to, że dopóki nie wdrożymy powiadamiania o nowych artykułach, nie można go zamknąć. Dlatego zajmijmy się zadaniem JRTB-4 - tworzeniem czeku co 20 minut i powiadomień o nowych artykułach. Przyjaciele! Chcesz wiedzieć od razu, kiedy zostanie wydany nowy kod projektu? Kiedy pojawi się nowy artykuł? Dołącz do mojego kanału tg . Gromadzę tam moje artykuły, przemyślenia i rozwój open source.

Wdrażamy JRTB-4

Co musimy zrobić w ramach tego zadania:
  1. Utwórz zadanie, które będzie okresowo odwiedzać wszystkie grupy, dla których mamy subskrypcje w bazie, sortować artykuły według daty publikacji i sprawdzać, czy identyfikator ostatniej publikacji odpowiada wartości w GroupSub. Jeśli się nie zgadza, musisz dokładnie zrozumieć, ile artykułów zostało opublikowanych od ostatniego razu. Aktualizujemy last_article_id w GroupSub7 do bieżącego stanu.

  2. Kiedy znajdziemy listę opublikowanych artykułów, wyszukujemy wszystkich AKTYWNYCH użytkowników tych grup i wysyłamy im powiadomienia o nowych artykułach.

W tym celu użyjemy czegoś takiego jak Spring Scheduler. Jest to mechanizm w Spring Framework, za jego pomocą można tworzyć zadania, które będą wykonywane w określonym czasie. Albo co 15-20-40 minut, albo w każdy czwartek o 15:30 lub w innej opcji. Nazywa się je również kalką z języka angielskiego - joba. Wykonując to zadanie, celowo pozostawię jeden mankament w poszukiwaniu nowych artykułów. Jest to dość rzadkie i pojawiło się tylko w sytuacji gdy ręcznie testowałem działanie tego zadania. Aby to zrobić musisz napisać klienta do wyszukiwania artykułów. W tym celu wykorzystamy znane nam już Swagger API . Jest post-kontroler. Nas interesuje tylko wyszukiwanie zbioru artykułów przy użyciu określonych filtrów:
/api/1.0/rest/posts Pobieraj posty według filtrów
Będziemy pracować nad tą prośbą. Czego w nim potrzebujemy? Uzyskaj listę artykułów należących do określonej grupy i należy je posortować według daty publikacji. W ten sposób możemy pobrać ostatnie 15 artykułów i sprawdzić, czy pojawiły się nowe publikacje na podstawie lastArticleId z naszej bazy. Jeżeli takowe wystąpią, przekażemy je do przetworzenia i przesłania użytkownikowi. Musimy więc napisać JavaRushPostClient .

Piszemy JavaRushPostClient

Tutaj nie będziemy się starali opisywać wszystkich żądań, które zostały do ​​nas przesłane w API i utworzymy tylko to, które będzie nam potrzebne. W ten sposób osiągamy dwa cele jednocześnie:
  1. Przyspieszamy proces pisania naszej aplikacji.

  2. Tę pracę pozostawiamy tym, którzy chcą pomóc naszej społeczności i decydują się spróbować swoich sił jako programista. Zrobię do tego zadania, które będzie można wykonać po MVP.

Więc zróbmy to. Aby wysłać zapytanie do sekcji Modele w interfejsie Swagger, utworzymy następujące DTO:„Projekt Java od A do Z”: Dodawanie klienta do artykułów - 2

Podstawowe informacje o użytkowniku:

package com.github.javarushcommunity.jrtb.javarushclient.dto;

import lombok.Data;

/**
* DTO, which represents base user information.
*/
@Data
public class BaseUserInfo {
   private String city;
   private String country;
   private String displayName;
   private Integer id;
   private String job;
   private String key;
   private Integer level;
   private String pictureUrl;
   private String position;
   private UserPublicStatus publicStatus;
   private String publicStatusMessage;
   private Integer rating;
   private Integer userId;
}

Język:

package com.github.javarushcommunity.jrtb.javarushclient.dto;

/**
* DTO, which represents languages.
*/
public enum Language {
   UNKNOWN,
   ENGLISH,
   GERMAN,
   SPANISH,
   HINDI,
   FRENCH,
   PORTUGUESE,
   POLISH,
   BENGALI,
   PUNJABI,
   CHINESE,
   ITALIAN,
   INDONESIAN,
   MARATHI,
   TAMIL,
   TELUGU,
   JAPANESE,
   KOREAN,
   URDU,
   TAIWANESE,
   NETHERLANDS,
   RUSSIAN,
   UKRAINIAN
}

Informacje o polubieniach:

package com.github.javarushcommunity.jrtb.javarushclient.dto;

/**
* DTO, which represents like's information.
*/
public class LikesInfo {

   private Integer count;
   private LikeStatus status;
}

LubięStan:

package com.github.javarushcommunity.jrtb.javarushclient.dto;

/**
* DTO, which represents like's status.
*/
public enum LikeStatus {

   UNKNOWN,
   LIKE,
   HOT,
   FOLLOW,
   FAVORITE,
   SOLUTION,
   HELPFUL,
   ARTICLE,
   OSCAR,
   DISLIKE,
   WRONG,
   SPAM,
   ABUSE,
   FOUL,
   TROLLING,
   OFFTOPIC,
   DUPLICATE,
   DIRTY,
   OUTDATED,
   BORING,
   UNCLEAR,
   HARD,
   EASY,
   FAKE,
   SHAM,
   AWFUL
}

Typ postu:

package com.github.javarushcommunity.jrtb.javarushclient.dto;

/**
* DTO, which represents post types.
*/
public enum PostType {
   UNKNOWN, USUAL, INNER_LINK, OUTER_LINK
}

Stan użytkownika publicznego:

package com.github.javarushcommunity.jrtb.javarushclient.dto;

/**
* DTO, which represents user public status.
*/
public enum UserPublicStatus {
   UNKNOWN,
   BEGINNER,
   ACTIVE,
   STRONG,
   GRADUATED,
   INTERNSHIP_IN_PROGRESS,
   INTERNSHIP_COMPLETED,
   RESUME_COMPLETED,
   LOOKING_FOR_JOB,
   HAVE_JOB;
}

VisibilityStatus:
package com.github.javarushcommunity.jrtb.javarushclient.dto;

/**
* DTO, which represents visibility status.
*/
public enum VisibilityStatus {
   UNKNOWN,
   RESTRICTED,
   PUBLIC,
   PROTECTED,
   PRIVATE,
   DISABLED,
   DELETED
}
W oparciu o wszystkie te DTO napiszmy główną klasę, aby otrzymywać artykuły:

Informacje o wpisie:

package com.github.javarushcommunity.jrtb.javarushclient.dto;

import lombok.Data;

/**
* DTO, which represents post information.
*/
@Data
public class PostInfo {

   private BaseUserInfo authorInfo;
   private Integer commentsCount;
   private String content;
   private Long createdTime;
   private String description;
   private GroupInfo groupInfo;
   private Integer id;
   private String key;
   private Language language;
   private LikesInfo likesInfo;
   private GroupInfo originalGroupInfo;
   private String pictureUrl;
   private Double rating;
   private Integer ratingCount;
   private String title;
   private PostType type;
   private Long updatedTime;
   private UserDiscussionInfo userDiscussionInfo;
   private Integer views;
   private VisibilityStatus visibilityStatus;

}
Stwórzmy teraz interfejs do pracy i jego implementację. Do pracy z artykułami będziemy potrzebować tylko jednej metody:

Klient JavaRushPost:

package com.github.javarushcommunity.jrtb.javarushclient;

import com.github.javarushcommunity.jrtb.javarushclient.dto.PostInfo;

import java.util.List;

/**
* Client for Javarush Open API corresponds to Posts.
*/
public interface JavaRushPostClient {

   /**
    * Find new posts since lastPostId in provided group.
    *
    * @param groupId provided group ID.
    * @param lastPostId provided last post ID.
    * @return the collection of the new {@link PostInfo}.
    */
   List<PostInfo> findNewPosts(Integer groupId, Integer lastPostId);
}
findNewPosts przyjmuje dwa argumenty: identyfikator grupy i ostatni identyfikator artykułu, który bot już opublikował. Dlatego wszystkie artykuły, które zostały opublikowane później niż artykuł z lastPostId, zostaną przesłane . I jego realizacja:
package com.github.javarushcommunity.jrtb.javarushclient;

import com.github.javarushcommunity.jrtb.javarushclient.dto.PostInfo;
import kong.unirest.GenericType;
import kong.unirest.Unirest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
public class JavaRushPostClientImpl implements JavaRushPostClient {

   private final String javarushApiPostPath;

   public JavaRushPostClientImpl(@Value("${javarush.api.path}") String javarushApi) {
       this.javarushApiPostPath = javarushApi + "/posts";
   }

   @Override
   public List<PostInfo> findNewPosts(Integer groupId, Integer lastPostId) {
       List<PostInfo> lastPostsByGroup = Unirest.get(javarushApiPostPath)
               .queryString("order", "NEW")
               .queryString("groupKid", groupId)
               .queryString("limit", 15)
               .asObject(new GenericType<List<PostInfo>>() {
               }).getBody();
       List<PostInfo> newPosts = new ArrayList<>();
       for (PostInfo post : lastPostsByGroup) {
           if (lastPostId.equals(post.getId())) {
               return newPosts;
           }
           newPosts.add(post);
       }
       return newPosts;
   }
}
Do żądania dodajemy kilka filtrów:
  • Order = NEW - tak, aby lista zawierała najpierw nowe;
  • groupKid = groupId - wyszukaj tylko określone grupy;
  • limit = 15 — ograniczamy liczbę artykułów na żądanie. Nasza częstotliwość wynosi 15-20 minut i spodziewamy się, że w tym czasie nie zostanie napisanych WIĘCEJ niż 15 (!).
Następnie, gdy już znajdziemy artykuły, przeglądamy listę i szukamy nowych. Algorytm jest prosty i intuicyjny. Jeśli chcesz to poprawić, napisz). Napiszmy prosty test dla tego klienta:
package com.github.javarushcommunity.jrtb.javarushclient;

import com.github.javarushcommunity.jrtb.javarushclient.dto.PostInfo;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.List;

import static com.github.javarushcommunity.jrtb.javarushclient.JavaRushGroupClientTest.JAVARUSH_API_PATH;

@DisplayName("Integration-level testing for JavaRushPostClient")
class JavaRushPostClientTest {

   private final JavaRushPostClient postClient = new JavaRushPostClientImpl(JAVARUSH_API_PATH);

   @Test
   public void shouldProperlyGetNew15Posts() {
       //when
       List<PostInfo> newPosts = postClient.findNewPosts(30, 2935);

       //then
       Assertions.assertEquals(15, newPosts.size());
   }
}
To bardzo prosty test, który sprawdza, czy w ogóle jest komunikacja z klientem, czy też nie. Znajduje 15 nowych artykułów w grupie Projekty Java, bo podaję mu ID pierwszego artykułu w tej grupie, a jest ich już ponad 15... Jest ich już 22! Nawet nie przypuszczałam, że będzie ich tak dużo. Jak się tego szybko dowiedziałem? Myślisz, że poszedł je policzyć? Nie) Użyłem przechwałki i sprawdziłem liczbę artykułów dla określonej grupy. Swoją drogą, w innych też możesz tak wyglądać... A ile artykułów jest w grupie RANDOM?... Już Ci powiem: jest ich 1062! Poważna kwota.

Koniec pierwszej części

Tutaj dodaliśmy pracę z klientem według artykułu. Wszystko już zrobiliśmy, tym razem myślę, że wszystko powinno być proste i szybkie. W następnym artykule dodamy Spring Scheduler i napiszemy FindNewArticleService . No cóż, jak zwykle lajkuj - subskrybuj - zadzwoń , daj gwiazdkę naszemu projektowi , napisz komentarz i oceń artykuł! Dziękuję wszystkim za przeczytanie – do zobaczenia wkrótce!

Lista wszystkich materiałów wchodzących w skład serii znajduje się na początku artykułu.

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