JavaRush /Java Blog /Random-IT /Aggiunta di un cliente agli articoli - "Progetto Java dal...
Roman Beekeeper
Livello 35

Aggiunta di un cliente agli articoli - "Progetto Java dalla A alla Z"

Pubblicato nel gruppo Random-IT
Ciao a tutti, miei cari amici. Passo dopo passo ci stiamo avvicinando al nostro obiettivo: diventare l'MVP del nostro progetto: JavaRush Telegram Bot. Come ho detto nell'ultimo articolo, mancano solo 5 attività. Oggi ne copriremo due. "Progetto Java dalla A alla Z": Aggiunta di un client agli articoli - 1Voglio ribadire che il progetto non finirà qui. Ho ancora un sacco di idee e visioni su come dovrebbe svilupparsi questo progetto, quali cose nuove possono essere aggiunte ad esso, cosa si può fare meglio. Prima di MVP, creeremo un articolo separato sull'argomento del refactoring, ovvero sul miglioramento della qualità del codice senza modificarne la funzionalità. A quel punto l’intero progetto sarà visibile e sarà chiaro cosa e dove può essere migliorato. Nel nostro caso, saremo protetti al massimo dall'interruzione della funzionalità, poiché sono stati scritti molti test. Scriveremo anche una retrospettiva su ciò che volevamo e su ciò che abbiamo ottenuto alla fine. Questa è una cosa molto utile: vediamo come è stato visto correttamente il tutto sei mesi fa. Almeno questo è molto interessante per me. Se qualcuno volesse cimentarsi come tester manuale, ci scriva e collaboreremo. Miglioriamo insieme questo progetto! Quindi, eccoli qui: due compiti descritti sei mesi fa: JRTB-8 e JRTB-9 . Ho iniziato a guardare cosa doveva essere implementato per queste attività e mi sono reso conto che in termini di lancio dei comandi tutto era già pronto. Succede...) Qui puoi guardare StartCommand , il metodo di esecuzione :
@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);
}
La logica funziona qui: se il nostro database ha già un utente di questo tipo per chatId, impostiamo semplicemente il campo active = true per lui. E se non esiste un utente simile, ne creiamo uno nuovo. Lo stesso per il comando /stop 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);
}
Si può vedere che quando si richiama questo comando, per l'utente viene impostato solo il campo active = false. E questo è tutto: i suoi abbonamenti vivranno e aspetteranno dietro le quinte quando l'utente deciderà nuovamente di attivare la chat con il bot. E sembrerebbe che l'attività sia già stata completata e possa essere chiusa. Ma non c'era. Il compito più importante è creare un avviso sui nuovi articoli nell'abbonamento. È qui che queste attività verranno completamente aggiornate e completate. Cioè, finché non avremo implementato la notifica di nuovi articoli, non potrà essere chiuso. Pertanto, occupiamoci del compito JRTB-4: creazione di un controllo ogni 20 minuti e notifiche sui nuovi articoli. Amici! Vuoi sapere subito quando verrà rilasciato il nuovo codice per il progetto? Quando esce un nuovo articolo? Unisciti al mio canale tg . Lì raccolgo insieme i miei articoli, i miei pensieri, il mio sviluppo open source.

Implementiamo JRTB-4

Cosa dobbiamo fare come parte di questo compito:
  1. Crea un lavoro che verrà periodicamente inviato a tutti i gruppi per i quali abbiamo abbonamenti nel database, ordina gli articoli per data di pubblicazione e controlla se l'ID dell'ultima pubblicazione corrisponde al valore in GroupSub. Se non corrisponde, allora devi capire esattamente quanti articoli sono stati pubblicati dall’ultima volta. Aggiorniamo last_article_id in GroupSub7 allo stato corrente.

  2. Quando troviamo un elenco di articoli pubblicati, troviamo tutti gli utenti ATTIVI per questi gruppi e inviamo loro notifiche sui nuovi articoli.

Per fare ciò, utilizzeremo qualcosa come Spring Scheduler. Questo è un meccanismo di Spring Framework, con esso puoi creare attività che verranno eseguite in un momento specifico. O ogni 15-20-40 minuti, oppure ogni giovedì alle 15:30 o qualche altra opzione. Sono anche chiamati carta da lucido dall'inglese - joba. Mentre svolgiamo questo compito, lascerò deliberatamente un difetto nella ricerca di nuovi articoli. È piuttosto raro ed è apparso solo in una situazione in cui ho testato manualmente il funzionamento di questa attività. Per fare ciò è necessario scrivere un client per la ricerca di articoli. Per fare ciò, utilizzeremo l'API Swagger che ci è già familiare . C'è un post-controller. Siamo interessati solo a cercare una raccolta di articoli utilizzando determinati filtri:
/api/1.0/rest/posts Ottieni post tramite filtri
Lavoreremo con questa richiesta. Di cosa abbiamo bisogno? Ottieni un elenco di articoli che appartengono a un gruppo specifico e dovrebbero essere ordinati per data di pubblicazione. In questo modo possiamo prendere gli ultimi 15 articoli e verificare se sono state pubblicate nuove pubblicazioni in base a lastArticleId dal nostro database. Se ce ne sono, li inoltreremo per l'elaborazione e l'invio all'utente. Quindi dobbiamo scrivere JavaRushPostClient .

Scriviamo JavaRushPostClient

Qui non cercheremo di coprire tutte le richieste che ci sono state passate nell'API e creeremo solo quella di cui abbiamo bisogno. In questo modo raggiungiamo due obiettivi contemporaneamente:
  1. Acceleriamo il processo di scrittura della nostra candidatura.

  2. Lasciamo questo lavoro a chi vuole aiutare la nostra comunità e decide di cimentarsi come sviluppatore. Realizzerò attività per questo che possono essere completate dopo l'MVP.

Facciamolo. Per interrogare la sezione Modelli nell'interfaccia utente di Swagger, creeremo i seguenti DTO:"Progetto Java dalla A alla Z": Aggiunta di un client agli articoli - 2

Informazioni utentebase:

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

Lingua:

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
}

Mi piaceInformazioni:

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

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

   private Integer count;
   private LikeStatus status;
}

Mi piaceStato:

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
}

Tipo di messaggio:

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

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

Stato pubblico utente:

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
}
Sulla base di tutti questi DTO, scriviamo una classe principale per ricevere articoli:

Informazioni sul messaggio:

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;

}
Ora creiamo un'interfaccia con cui lavorare e la sua implementazione. Avremo bisogno di un solo metodo per lavorare con gli articoli:

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 accetta due argomenti: l'ID del gruppo e l'ultimo ID dell'articolo che il bot ha già pubblicato. Verranno quindi trasmessi tutti quegli articoli che sono stati pubblicati successivamente all'articolo con lastPostId . E la sua implementazione:
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;
   }
}
Aggiungiamo diversi filtri alla richiesta:
  • order = NEW - in modo che l'elenco contenga prima quelli nuovi;
  • groupKid = groupId: cerca solo determinati gruppi;
  • limite = 15: limitiamo il numero di articoli per richiesta. La nostra frequenza è di 15-20 minuti e prevediamo che durante questo periodo non ne verranno scritti PIÙ di 15 (!).
Successivamente, quando abbiamo trovato gli articoli, scorriamo l'elenco e ne cerchiamo di nuovi. L'algoritmo è semplice ed intuitivo. Se vuoi migliorarlo scrivi). Scriviamo un semplice test per questo 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());
   }
}
Questo è un test molto semplice che verifica se c'è o meno comunicazione con il cliente. Trova 15 nuovi articoli nel gruppo Progetti Java, perché gli do l'ID del primo articolo di questo gruppo, e ce ne sono già più di 15... Ce ne sono già 22! Non pensavo nemmeno che ce ne sarebbero stati così tanti. Come ho fatto a scoprirlo velocemente? Pensi che sia andato a contarli? No) Ho usato uno spavalderia e ho guardato il numero di articoli per un determinato gruppo. A proposito, puoi guardare così anche negli altri... E quanti articoli ci sono nel gruppo RANDOM?... Te lo dico subito: sono 1062! Importo serio.

Fine della prima parte

Qui abbiamo aggiunto il lavoro con il cliente per articolo. Abbiamo già fatto tutto, questa volta penso che tutto debba essere semplice e veloce. Nel prossimo articolo aggiungeremo Spring Scheduler e scriveremo FindNewArticleService . Bene, come al solito, metti mi piace - iscriviti - suona il campanello , dai una stella al nostro progetto , scrivi commenti e valuta l'articolo! Grazie a tutti per aver letto: a presto!

Un elenco di tutti i materiali della serie si trova all'inizio di questo articolo.

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