JavaRush /Java Blogu /Random-AZ /Məqalələrə müştəri əlavə etmək - "A-dan Z-yə Java layihəs...
Roman Beekeeper
Səviyyə

Məqalələrə müştəri əlavə etmək - "A-dan Z-yə Java layihəsi"

Qrupda dərc edilmişdir
Hər kəsə salam əziz dostlarım. Addım-addım hədəfimizə - layihəmizin MVP-si olmaq - JavaRush Telegram Botuna yaxınlaşırıq. Keçən yazıda dediyim kimi, cəmi 5 vəzifə qalıb. Bu gün onlardan ikisini əhatə edəcəyik. "A-dan Z-yə Java layihəsi": Məqalələrə müştəri əlavə etmək - 1Bir daha demək istəyirəm ki, layihə burada bitməyəcək. Bu layihənin necə inkişaf etdirilməsi, ona hansı yeni şeylərin əlavə oluna biləcəyi, nəyi daha yaxşı etmək barədə hələ də çoxlu fikirlərim və baxışlarım var. MVP-dən əvvəl biz refaktorinq mövzusunda ayrıca məqalə hazırlayacağıq - yəni kodun funksionallığını dəyişmədən keyfiyyətini artırmaq haqqında. O vaxta qədər bütün layihə görünəcək və nəyi və harada təkmilləşdirmək olar aydın olacaq. Bizim vəziyyətimizdə funksionallığı pozmaqdan maksimum dərəcədə qorunacağıq, çünki bir çox testlər yazılmışdır. İstədiyimiz və sonda nə əldə etdiyimizlə bağlı retrospektiv də yazacağıq. Bu çox faydalı bir şeydir: gəlin altı ay əvvəl hər şeyin necə düzgün göründüyünü görək. Ən azından bu mənim üçün çox maraqlıdır. Hər kəs özünü əl testçisi kimi sınamaq istəyirsə, bizə yazın və biz əməkdaşlıq edək. Gəlin birlikdə bu layihəni daha da yaxşılaşdıraq! Beləliklə, bunlardır: altı ay əvvəl təsvir olunan iki tapşırıq: JRTB-8JRTB-9 . Bu tapşırıqlar üçün nəyin həyata keçirilməsinə baxmağa başladım və başa düşdüm ki, əmrləri işə salmaq baxımından hər şey artıq hazırdır. Bu olur...) Burada StartCommand-a , icra metoduna baxa bilərsiniz :
@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);
}
Məntiq burada işləyir: əgər verilənlər bazamızda artıq chatId tərəfindən belə bir istifadəçi varsa, biz onun üçün sadəcə olaraq aktiv = doğru sahəsini təyin edirik. Əgər belə bir istifadəçi yoxdursa, biz yenisini yaradırıq. StopCommand -da /stop əmri üçün eynidir :
@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);
}
Görünür ki, bu əmri çağırarkən istifadəçi üçün yalnız aktiv = false sahəsi təyin olunur. Hamısı budur: istifadəçi yenidən botla söhbəti aktivləşdirməyə qərar verəndə onun abunələri yaşayacaq və qanadlarda gözləyəcək. Və belə görünür ki, tapşırıq artıq tamamlanıb və bağlana bilər. Amma orda yoxdu. Ən vacib vəzifə abunədə yeni məqalələr haqqında xəbərdarlıq yaratmaqdır. Burada bu tapşırıqlar tamamilə yenilənəcək və tamamlanacaq. Yəni biz yeni məqalələrin bildirişini həyata keçirməmişik, onu bağlamaq olmaz. Buna görə də, gəlin JRTB-4 tapşırığına diqqət yetirək - hər 20 dəqiqədən bir çek yaratmaq və yeni məqalələr haqqında bildirişlər. Dostlar! Layihə üçün yeni kodun nə vaxt buraxılacağını dərhal bilmək istəyirsiniz? Yeni məqalə nə vaxt çıxır? tg kanalıma qoşulun . Orada məqalələrimi, fikirlərimi, açıq mənbə inkişafımı bir yerdə toplayıram.

Biz JRTB-4 tətbiq edirik

Bu tapşırığın bir hissəsi olaraq nə etməliyik:
  1. Verilənlər bazasında abunəliyimiz olan bütün qruplara vaxtaşırı gedəcək bir iş yaradın, məqalələri nəşr tarixinə görə çeşidləyin və son nəşrin ID-sinin GroupSub-dakı dəyərə uyğun olub olmadığını yoxlayın. Əgər uyğun gəlmirsə, son dəfədən bu yana neçə məqalənin dərc olunduğunu dəqiq başa düşməlisiniz. GroupSub7-də last_article_id-i cari vəziyyətə yeniləyirik.

  2. Dərc edilmiş məqalələrin siyahısını tapdıqda, biz bu qruplar üçün bütün AKTİV istifadəçiləri tapırıq və onlara yeni məqalələr haqqında bildirişlər göndəririk.

Bunun üçün Spring Scheduler kimi bir şeydən istifadə edəcəyik. Bu, Bahar Çərçivəsindəki bir mexanizmdir, onunla müəyyən bir zamanda yerinə yetiriləcək tapşırıqlar yarada bilərsiniz. Ya hər 15-20-40 dəqiqədən bir, ya da hər cümə axşamı saat 15:30 və ya başqa variant. Onlara ingilis dilindən izləmə kağızı da deyilir - joba. Biz bu tapşırığı yerinə yetirərkən mən qəsdən yeni məqalə axtarışında bir qüsur buraxacağam. Bu olduqca nadirdir və yalnız bu tapşırığın işini əl ilə sınaqdan keçirdiyim bir vəziyyətdə ortaya çıxdı. Bunu etmək üçün məqalələri axtarmaq üçün müştəri yazmalısınız. Bunun üçün artıq bizə tanış olan Swagger API-dən istifadə edəcəyik . Post nəzarətçi var. Biz yalnız müəyyən filtrlərdən istifadə edərək məqalələr toplusunu axtarmaqda maraqlıyıq:
/api/1.0/rest/posts Filtrlər vasitəsilə yazıları əldə edin
Biz bu tələblə işləyəcəyik. Bunun içində bizə nə lazımdır? Müəyyən bir qrupa aid olan məqalələrin siyahısını əldə edin və onlar nəşr tarixinə görə sıralanmalıdır. Bu yolla biz son 15 məqaləni götürə və verilənlər bazamızdan lastArticleId əsasında yeni nəşrlərin dərc edilib-edilmədiyini yoxlaya bilərik . Əgər varsa, biz onları emal etmək və istifadəçiyə göndərmək üçün ötürəcəyik. Beləliklə, JavaRushPostClient yazmalıyıq .

JavaRushPostClient yazırıq

Burada API-də bizə göndərilən bütün sorğuları əhatə etməyə çalışmayacağıq və yalnız bizə lazım olanı yaradacağıq. Bununla biz eyni anda iki məqsədə nail oluruq:
  1. Ərizəmizi yazma prosesini sürətləndiririk.

  2. Bu işi cəmiyyətimizə kömək etmək istəyənlərin öhdəsinə buraxırıq və özlərini inkişaf etdirici kimi sınamağa qərar veririk. Bunun üçün MVP-dən sonra tamamlana biləcək tapşırıqlar verəcəyəm.

Beləliklə, edək. Swagger UI -də Modellər bölməsini sorğulamaq üçün biz aşağıdakı DTO-ları yaradacağıq:"A-dan Z-yə Java layihəsi": Məqalələrə müştəri əlavə etmək - 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;
}

Dil:

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
}

Bəyənmə məlumatı:

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 Növü:

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
}
Bütün bu DTO-lara əsaslanaraq, məqalələri qəbul etmək üçün əsas sinif yazaq:

PostInfo:

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;

}
İndi işləmək üçün interfeys və onun həyata keçirilməsini yaradaq. Məqalələrlə işləmək üçün bizə yalnız bir üsul lazımdır:

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 iki arqument götürür: qrup ID-si və botun artıq yerləşdirdiyi məqalənin sonuncu ID-si. Buna görə də, lastPostId ilə məqalədən gec dərc edilmiş bütün məqalələr ötürüləcək . Və onun həyata keçirilməsi:
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;
   }
}
Sorğuya bir neçə filtr əlavə edirik:
  • sifariş = YENİ - siyahıda ilk növbədə yeniləri olması üçün;
  • groupKid = groupId - yalnız müəyyən qruplar üçün axtarış;
  • limit = 15 — hər sorğu üçün məqalələrin sayını məhdudlaşdırırıq. Tezliyimiz 15-20 dəqiqədir və gözləyirik ki, bu müddət ərzində 15-dən (!) ARTIQ yazılmayacaq.
Sonra, məqalələr tapdıqda, siyahıya göz gəzdiririk və yenilərini axtarırıq. Alqoritm sadə və intuitivdir. Təkmilləşdirmək istəyirsinizsə, yazın). Bu müştəri üçün sadə bir test yazaq:
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());
   }
}
Bu, müştəri ilə hər hansı əlaqənin olub-olmadığını yoxlayan çox sadə bir testdir. Java layihələri qrupunda 15 yeni məqalə tapır, çünki mən ona bu qrupdakı ilk məqalənin şəxsiyyət vəsiqəsini verirəm və onların sayı artıq 15-dən çoxdur... Artıq 22-si var! Onların bu qədər çox olacağını ağlıma belə gətirməzdim. Necə tez tapdım? Sizcə o, onları saymağa getdi? Xeyr) Swager istifadə etdim və müəyyən bir qrup üçün məqalələrin sayına baxdım. Yeri gəlmişkən, başqalarında belə baxa bilərsiniz... Bəs RANDOM qrupunda nə qədər məqalə var?... İndi sizə deyəcəm: onlardan 1062-si var! Ciddi məbləğ.

Birinci hissənin sonu

Burada müştəri ilə işi məqalə ilə əlavə etdik. Artıq hər şeyi etdik, bu dəfə düşünürəm ki, hər şey sadə və sürətli olmalıdır. Növbəti məqalədə Spring Scheduler əlavə edəcəyik və FindNewArticleService yazacağıq . Yaxşı, həmişəki kimi, bəyənin - abunə olun - zəngi vurun , layihəmizə ulduz verin , şərh yazın və məqaləni qiymətləndirin! Oxuduğunuz üçün hamınıza təşəkkür edirəm - tezliklə görüşərik!

Serialdakı bütün materialların siyahısı bu məqalənin əvvəlindədir.

Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION