JavaRush /Java-Blog /Random-DE /Hinzufügen eines Clients zu den Artikeln - „Java-Projekt ...

Hinzufügen eines Clients zu den Artikeln - „Java-Projekt von A bis Z“

Veröffentlicht in der Gruppe Random-DE
Hallo zusammen, meine lieben Freunde. Schritt für Schritt kommen wir unserem Ziel näher – der MVP unseres Projekts – JavaRush Telegram Bot – zu werden. Wie ich im letzten Artikel sagte, sind nur noch 5 Aufgaben übrig. Heute werden wir zwei davon behandeln. „Java-Projekt von A bis Z“: Hinzufügen eines Clients zu Artikeln – 1Ich möchte wiederholen, dass das Projekt hier nicht enden wird. Ich habe noch jede Menge Ideen und Visionen, wie sich dieses Projekt entwickeln soll, welche neuen Dinge dazu hinzugefügt werden können, was besser gemacht werden kann. Vor MVP werden wir einen separaten Artikel zum Thema Refactoring verfassen – also zur Verbesserung der Qualität von Code, ohne seine Funktionalität zu ändern. Zu diesem Zeitpunkt wird das gesamte Projekt sichtbar sein und klar sein, was und wo verbessert werden kann. In unserem Fall sind wir maximal vor Funktionsstörungen geschützt, da viele Tests geschrieben wurden. Wir werden auch einen Rückblick darüber schreiben, was wir wollten und was wir am Ende bekommen haben. Das ist eine sehr nützliche Sache: Mal sehen, wie richtig alles vor sechs Monaten gesehen wurde. Zumindest ist das für mich sehr interessant. Wenn sich jemand als manueller Tester versuchen möchte, schreiben Sie uns und wir werden zusammenarbeiten. Lasst uns dieses Projekt gemeinsam besser machen! Hier sind sie also: zwei Aufgaben, die vor sechs Monaten beschrieben wurden: JRTB-8 und JRTB-9 . Ich begann zu prüfen, was für diese Aufgaben implementiert werden musste, und stellte fest, dass in Bezug auf die Startbefehle bereits alles bereit war. Es passiert...) Hier können Sie sich StartCommand , die Ausführungsmethode , ansehen :
@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);
}
Die Logik funktioniert hier: Wenn unsere Datenbank bereits einen solchen Benutzer per ChatId hat, setzen wir einfach das Feld active = true für ihn. Und wenn es keinen solchen Benutzer gibt, erstellen wir einen neuen. Das Gleiche gilt für den /stop- Befehl in 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);
}
Es ist ersichtlich, dass beim Aufruf dieses Befehls nur das Feld active = false für den Benutzer gesetzt wird. Und das ist alles: Seine Abonnements bleiben bestehen und warten in den Startlöchern, wenn der Benutzer sich erneut dazu entschließt, den Chat mit dem Bot zu aktivieren. Und es scheint, dass die Aufgabe bereits abgeschlossen ist und geschlossen werden kann. Aber es war nicht da. Die wichtigste Aufgabe besteht darin, eine Benachrichtigung über neue Artikel im Abonnement zu erstellen. Hier werden diese Aufgaben komplett aktualisiert und erledigt. Das heißt, bis wir die Benachrichtigung über neue Artikel implementiert haben, kann sie nicht geschlossen werden. Kümmern wir uns daher um die Aufgabe JRTB-4 – alle 20 Minuten einen Scheck und Benachrichtigungen über neue Artikel erstellen. Freunde! Möchten Sie sofort wissen, wann neuer Code für das Projekt veröffentlicht wird? Wann erscheint ein neuer Artikel? Treten Sie meinem TG-Kanal bei . Dort sammle ich meine Artikel, meine Gedanken, meine Open-Source-Entwicklung zusammen.

Wir implementieren JRTB-4

Was wir im Rahmen dieser Aufgabe tun müssen:
  1. Erstellen Sie einen Job, der regelmäßig alle Gruppen besucht, für die wir Abonnements in der Datenbank haben, Artikel nach Veröffentlichungsdatum sortieren und prüfen, ob die ID der letzten Veröffentlichung mit dem Wert in GroupSub übereinstimmt. Wenn es nicht übereinstimmt, müssen Sie genau wissen, wie viele Artikel seit dem letzten Mal veröffentlicht wurden. Wir aktualisieren last_article_id in GroupSub7 auf den aktuellen Stand.

  2. Wenn wir eine Liste veröffentlichter Artikel gefunden haben, finden wir alle AKTIVEN Benutzer für diese Gruppen und senden ihnen Benachrichtigungen über neue Artikel.

Dazu verwenden wir so etwas wie den Spring Scheduler. Dies ist ein Mechanismus im Spring Framework, mit dem Sie Aufgaben erstellen können, die zu einem bestimmten Zeitpunkt ausgeführt werden. Entweder alle 15-20-40 Minuten oder jeden Donnerstag um 15:30 Uhr oder eine andere Option. Sie werden auch Pauspapier aus dem Englischen genannt – joba. Während wir diese Aufgabe erledigen, werde ich bei der Suche nach neuen Artikeln bewusst einen Fehler belassen. Es kommt recht selten vor und trat nur dann auf, wenn ich die Funktion dieser Aufgabe manuell getestet habe. Dazu müssen Sie einen Client zum Suchen von Artikeln schreiben. Dazu nutzen wir die uns bereits bekannte Swagger-API . Es gibt einen Nachregler. Wir sind nur daran interessiert, mithilfe bestimmter Filter nach einer Sammlung von Artikeln zu suchen:
/api/1.0/rest/posts Beiträge nach Filtern abrufen
Wir werden dieser Anfrage nachkommen. Was brauchen wir darin? Erhalten Sie eine Liste der Artikel, die zu einer bestimmten Gruppe gehören, und sie sollten nach Veröffentlichungsdatum sortiert sein. Auf diese Weise können wir anhand der letzten 15 Artikel anhand der lastArticleId aus unserer Datenbank prüfen, ob neue Veröffentlichungen veröffentlicht wurden . Sofern vorhanden, geben wir diese zur Bearbeitung und Versendung an den Nutzer weiter. Also müssen wir JavaRushPostClient schreiben .

Wir schreiben JavaRushPostClient

Hier werden wir nicht versuchen, alle Anfragen abzudecken, die uns in der API übergeben wurden, sondern nur diejenige erstellen, die wir benötigen. Damit erreichen wir gleich zwei Ziele:
  1. Wir beschleunigen den Prozess des Verfassens unserer Bewerbung.

  2. Diese Arbeit überlassen wir denen, die unserer Community helfen wollen und sich dazu entschließen, sich als Entwickler zu versuchen. Ich werde dafür Aufgaben erstellen, die nach dem MVP erledigt werden können.

Also machen wir's. Um den Abschnitt „Modelle“ in der Swagger-Benutzeroberfläche abzufragen , erstellen wir die folgenden DTOs:„Java-Projekt von A bis Z“: Hinzufügen eines Clients zu Artikeln – 2

BaseUserInfo:

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;
}

Sprache:

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
}

LikesInfo:

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

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

   private Integer count;
   private LikeStatus status;
}

LikeStatus:

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
}

Post-Typ:

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

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

UserPublicStatus:

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
}
Basierend auf all diesen DTOs schreiben wir eine Hauptklasse zum Empfangen von Artikeln:

Beitragsinfo:

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;

}
Lassen Sie uns nun eine Schnittstelle zum Arbeiten und deren Implementierung erstellen. Wir benötigen nur eine Methode, um mit Artikeln zu arbeiten:

JavaRushPostClient:

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 benötigt zwei Argumente: die Gruppen-ID und die letzte ID des Artikels, den der Bot bereits gepostet hat. Daher werden alle Artikel übertragen, die später als der Artikel mit lastPostId veröffentlicht wurden . Und seine Umsetzung:
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;
   }
}
Wir fügen der Anfrage mehrere Filter hinzu:
  • order = NEW – damit die Liste zuerst neue enthält;
  • groupKid = groupId – nur nach bestimmten Gruppen suchen;
  • limit = 15 – wir begrenzen die Anzahl der Artikel pro Anfrage. Unsere Frequenz beträgt 15-20 Minuten und wir gehen davon aus, dass in dieser Zeit nicht MEHR als 15 (!) geschrieben werden.
Als nächstes gehen wir, wenn wir Artikel gefunden haben, die Liste durch und suchen nach neuen. Der Algorithmus ist einfach und intuitiv. Wenn Sie es verbessern möchten, schreiben Sie). Schreiben wir einen einfachen Test für diesen Client:
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());
   }
}
Hierbei handelt es sich um einen sehr einfachen Test, der überprüft, ob überhaupt eine Kommunikation mit dem Client stattfindet oder nicht. Er findet 15 neue Artikel in der Gruppe „Java-Projekte“, weil ich ihm die ID des ersten Artikels in dieser Gruppe gebe, und es sind bereits mehr als 15 davon … Es sind bereits 22 davon! Ich hätte nicht einmal gedacht, dass es so viele davon geben würden. Wie habe ich es schnell herausgefunden? Glaubst du, er ging, um sie zu zählen? Nein) Ich habe einen Swager verwendet und mir die Anzahl der Artikel für eine bestimmte Gruppe angesehen. So kann man übrigens auch bei anderen aussehen... Und wie viele Artikel gibt es in der RANDOM-Gruppe?... Ich verrate es euch jetzt: Es sind 1062 davon! Ernsthafte Menge.

Ende des ersten Teils

Hier haben wir die Arbeit mit dem Kunden artikelweise hinzugefügt. Wir haben bereits alles erledigt, dieses Mal sollte meiner Meinung nach alles einfach und schnell gehen. Im nächsten Artikel werden wir Spring Scheduler hinzufügen und FindNewArticleService schreiben . Nun, wie immer, liken – abonnieren – klingeln , unserem Projekt einen Stern geben , Kommentare schreiben und den Artikel bewerten! Vielen Dank fürs Lesen – bis bald!

Eine Liste aller Materialien der Serie finden Sie am Anfang dieses Artikels.

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