JavaRush /Java Blog /Random-TW /在文章中加入客戶端 - “Java 專案從 A 到 Z”
Roman Beekeeper
等級 35

在文章中加入客戶端 - “Java 專案從 A 到 Z”

在 Random-TW 群組發布
大家好,我親愛的朋友們。我們正在一步步接近我們的目標——成為我們專案——JavaRush Telegram Bot 的 MVP。正如我在上一篇文章中所說,只剩下 5 個任務了。今天我們將介紹其中兩個。 「Java 專案從頭到尾」:在文章中新增客戶端 - 1我想重申,這個計畫不會到此結束。對於這個專案應該如何發展、可以增加哪些新東西、哪些可以做得更好,我仍然有很多想法和願景。在 MVP 之前,我們將單獨撰寫一篇關於重構主題的文章——即在不改變程式碼功能的情況下提高程式碼品質。到那時,整個專案將是可見的,並且可以清楚哪些地方可以改進。在我們的例子中,我們將最大限度地防止破壞功能,因為已經編寫了許多測試。我們還將寫一份關於我們想要什麼以及最終得到什麼的回顧。這是一件非常有用的事情:讓我們看看六個月前所看到的一切是否正確。至少這對我來說很有趣。如果有人想嘗試自己擔任手動測試員,請寫信給我們,我們將予以合作。讓我們一起把這個專案做得更好!因此,它們是:六個月前描述的兩項任務:JRTB-8JRTB-9。我開始研究這些任務需要實現什麼,並意識到在啟動命令方面,一切都已經準備好了。它發生了...)在這裡,您可以查看StartCommand,即執行方法:
@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);
}
這裡的邏輯是這樣的:如果我們的資料庫已經有這樣一個使用者的 chatId,我們只需為他設定 active = true 欄位。如果沒有這樣的用戶,我們將建立一個新用戶。StopCommand中的/stop指令相同:
@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);
}
可以看到,呼叫該指令時,只為使用者設定了active = false欄位。僅此而已:當用戶再次決定啟動與機器人的聊天時,他的訂閱將立即生效並等待。而且看起來任務已經完成了,可以關閉了。但它不在那裡。最重要的任務是建立有關訂閱中新文章的警報。這是這些任務將被完全更新和完成的地方。也就是說,在我們實施新文章通知之前,它無法關閉。因此,讓我們處理任務 JRTB-4 - 每 20 分鐘建立一次檢查以及有關新文章的通知。 朋友們!您想立即知道該專案的新程式碼何時發布嗎?新文章什麼時候出來?加入我的tg頻道。我在那裡收集我的文章、我的想法、我的開源開發。

我們實作 JRTB-4

作為此任務的一部分,我們需要做什麼:
  1. 建立一個作業,該作業將定期存取我們在資料庫中訂閱的所有群組,按發布日期對文章進行排序,並檢查最後發布的 ID 是否與 GroupSub 中的值相符。如果不匹配,那麼您需要準確了解自上次以來已發布了多少篇文章。我們將 GroupSub7 中的last_article_id 更新為目前狀態。

  2. 當我們找到已發表文章的清單時,我們會找到這些群組的所有活躍用戶並向他們發送有關新文章的通知。

為此,我們將使用 Spring Scheduler 之類的東西。這是Spring框架中的一種機制,用它你可以創建將在特定時間執行的任務。每 15-20-40 分鐘一班,或每週四 15:30 或其他選項。它們也被稱為英語「描圖紙」—joba。當我們做這個任務的時候,我會故意在尋找新文章時留下一個缺陷。這種情況相當罕見,只出現在我手動測試該任務運行情況的情況下。為此,您需要編寫一個用於搜尋文章的客戶端。為此,我們將使用我們已經熟悉的Swagger API。有一個後控制器。我們只對使用某些過濾器搜尋文章集合感興趣:
/api/1.0/rest/posts 透過過濾器取得帖子
我們將處理此請求。我們需要什麼?取得屬於特定群組的文章列表,它們應按發布日期排序。這樣我們就可以取得最後 15 篇文章,並根據資料庫中的lastArticleId檢查是否已發布新出版品。如果有,我們會將其轉交處理並發送給用戶。所以我們需要寫JavaRushPostClient

我們編寫JavaRushPostClient

在這裡,我們不會嘗試涵蓋 API 中發送給我們的所有請求,而只會建立我們需要的請求。透過這樣做,我們可以同時實現兩個目標:
  1. 我們加快了撰寫申請的過程。

  2. 我們將這項工作留給那些想要幫助我們社區並決定嘗試自己作為開發人員的人。我會為此制定一些任務,這些任務可以在 MVP 之後完成。

那麼就讓我們開始吧。為了查詢Swagger UI中的模型部分,我們將建立以下 DTO:「Java 專案從頭到尾」:在文章中新增客戶端 - 2

基本使用者資訊:

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

語言:

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
}

喜歡資訊:

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

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

   private Integer count;
   private LikeStatus status;
}

喜歡狀態:

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
}

貼文類型:

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

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

使用者公共狀態:

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
}
基於所有這些DTO,讓我們寫一個主類別來接收文章:

貼文資訊:

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;

}
現在讓我們建立一個要使用的介面及其實作。我們只需要一個方法來處理文章:

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採用兩個參數:群組 ID 和機器人已發布的文章的最後一個 ID。因此,所有晚於lastPostId的文章發布的文章都會被傳輸。及其實作:
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;
   }
}
我們向請求添加幾個過濾器:
  • order = NEW - 以便清單首先包含新的;
  • groupKid = groupId - 僅搜尋某些群組;
  • limit = 15 — 我們限制每個請求的文章數量。我們的頻率是 15-20 分鐘,我們預計在此期間寫入的內容不會超過 15 (!)。
接下來,當我們找到文章時,我們會瀏覽清單並尋找新的文章。該演算法簡單直觀。如果你想改進它,請寫)。讓我們為這個客戶端寫一個簡單的測試:
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());
   }
}
這是一個非常簡單的測試,用於檢查是否與客戶端有任何通訊。他在Java專案群組裡找到了15篇新文章,因為我給了他這個群組裡第一篇文章的ID,已經超過15篇了…已經有22篇了!我甚至沒有想到會有這麼多人。我怎麼很快就知道了?你認為他去數數了嗎?不)我使用了壓印器並查看了某個組的文章數量。對了,你可以在別人身上這樣看…那麼 RANDOM 組裡有多少篇文章?…我現在告訴你:有 1062 篇!數額嚴重。

第一部分結束

這裡我們透過文章加入了與客戶的合作。我們已經完成了所有工作,這次我認為一切都應該簡單又快速。在下一篇文章中,我們將新增 Spring Scheduler 並編寫FindNewArticleService好吧,像往常一樣,按讚 - 訂閱 - 敲響小鈴,給我們的專案一顆星,寫評論並評論文章! 感謝大家的閱讀 - 很快再見!

此系列所有資料的清單位於本文開頭。

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