JavaRush /مدونة جافا /Random-AR /إضافة عميل إلى المقالات - "مشروع جافا من الألف إلى الياء"...
Roman Beekeeper
مستوى

إضافة عميل إلى المقالات - "مشروع جافا من الألف إلى الياء"

نشرت في المجموعة
مرحبا بالجميع، أصدقائي الأعزاء. خطوة بخطوة نقترب من هدفنا - أن نصبح أفضل لاعب في مشروعنا - JavaRush Telegram Bot. كما قلت في المقال الأخير، لم يتبق سوى 5 مهام. اليوم سوف نغطي اثنين منهم. "مشروع جافا من الألف إلى الياء": إضافة عميل إلى المقالات - 1أريد أن أكرر أن المشروع لن ينتهي هنا. لا يزال لدي الكثير من الأفكار والرؤى حول كيفية تطوير هذا المشروع، وما هي الأشياء الجديدة التي يمكن إضافتها إليه، وما الذي يمكن القيام به بشكل أفضل. قبل MVP، سنقوم بعمل مقالة منفصلة حول موضوع إعادة البناء - أي تحسين جودة التعليمات البرمجية دون تغيير وظائفها. بحلول ذلك الوقت، سيكون المشروع بأكمله مرئيًا وسيكون من الواضح ما وأين يمكن تحسينه. في حالتنا، سنكون محميين إلى أقصى حد من كسر الوظيفة، لأنه تمت كتابة العديد من الاختبارات. سنكتب أيضًا نظرة استعادية عما أردناه وما حصلنا عليه في النهاية. هذا شيء مفيد للغاية: دعونا نرى مدى صحة رؤية كل شيء قبل ستة أشهر. على الأقل هذا مثير للاهتمام للغاية بالنسبة لي. إذا كان أي شخص يرغب في تجربة نفسه كمختبر يدوي، فاكتب إلينا وسنتعاون. دعونا نجعل هذا المشروع أفضل معًا! إذن، ها هما: مهمتان تم وصفهما منذ ستة أشهر: JRTB-8 و JRTB-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);
}
يعمل المنطق هنا: إذا كانت قاعدة بياناتنا تحتوي بالفعل على مثل هذا المستخدم من خلال معرف الدردشة، فإننا ببساطة نقوم بتعيين الحقل active = true له. وإذا لم يكن هناك مثل هذا المستخدم، فإننا نقوم بإنشاء مستخدم جديد. نفس الشيء بالنسبة للأمر /stop في 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);
}
يمكن ملاحظة أنه عند استدعاء هذا الأمر، يتم تعيين الحقل active = false فقط للمستخدم. وهذا كل شيء: ستظل اشتراكاته حية وتنتظر عندما يقرر المستخدم مرة أخرى تنشيط الدردشة مع الروبوت. ويبدو أن المهمة قد اكتملت بالفعل ويمكن إغلاقها. ولكن لم يكن هناك. المهمة الأكثر أهمية هي إنشاء تنبيه حول المقالات الجديدة في الاشتراك. هذا هو المكان الذي سيتم فيه تحديث هذه المهام وإكمالها بالكامل. أي أنه حتى ننفذ الإخطار بالمقالات الجديدة، لا يمكن إغلاقه. لذلك، دعونا نتولى المهمة JRTB-4 - إنشاء شيك كل 20 دقيقة وإشعارات حول المقالات الجديدة. أصدقاء! هل تريد أن تعرف على الفور متى سيتم إصدار الكود الجديد للمشروع؟ متى يخرج مقال جديد؟ انضم إلى قناتي tg . هناك أجمع مقالاتي وأفكاري وتطويري مفتوح المصدر معًا.

نحن ننفذ JRTB-4

ما يتعين علينا القيام به كجزء من هذه المهمة:
  1. قم بإنشاء مهمة ستنتقل بشكل دوري إلى جميع المجموعات التي لدينا اشتراكات بها في قاعدة البيانات، وقم بفرز المقالات حسب تاريخ النشر وتحقق مما إذا كان معرف آخر منشور يطابق القيمة الموجودة في GroupSub. إذا لم يكن متطابقًا، فأنت بحاجة إلى فهم عدد المقالات التي تم نشرها منذ آخر مرة. نقوم بتحديث last_article_id في GroupSub7 إلى الحالة الحالية.

  2. عندما نعثر على قائمة بالمقالات المنشورة، نجد جميع المستخدمين النشطين لهذه المجموعات ونرسل إليهم إشعارات حول المقالات الجديدة.

للقيام بذلك، سوف نستخدم شيئًا مثل Spring Scholer. هذه آلية في Spring Framework، حيث يمكنك من خلالها إنشاء المهام التي سيتم تنفيذها في وقت محدد. إما كل 15-20-40 دقيقة، أو كل يوم خميس الساعة 15:30 أو أي خيار آخر. ويطلق عليهم أيضًا اسم ورق البحث عن المفقودين من اللغة الإنجليزية - جوبا. وبينما نقوم بهذه المهمة، سأترك عمدًا عيبًا واحدًا في البحث عن مقالات جديدة. إنه نادر جدًا ولم يظهر إلا في موقف قمت فيه باختبار تشغيل هذه المهمة يدويًا. للقيام بذلك تحتاج إلى كتابة عميل للبحث عن المقالات. للقيام بذلك، سوف نستخدم Swagger API المألوف لنا بالفعل . هناك وحدة تحكم بعد. نحن مهتمون فقط بالبحث عن مجموعة من المقالات باستخدام مرشحات معينة:
/api/1.0/rest/posts احصل على المشاركات حسب المرشحات
سوف نعمل مع هذا الطلب. ماذا نحتاج فيه؟ الحصول على قائمة بالمقالات التي تنتمي إلى مجموعة معينة، ويجب ترتيبها حسب تاريخ النشر. بهذه الطريقة يمكننا أخذ آخر 15 مقالة والتحقق من نشر منشورات جديدة بناءً على معرف المقالة الأخير من قاعدة البيانات الخاصة بنا. إذا كان هناك أي منها، فسنقوم بتمريرها للمعالجة وإرسالها إلى المستخدم. لذلك نحن بحاجة إلى كتابة JavaRushPostClient .

نكتب JavaRushPostClient

لن نحاول هنا تغطية جميع الطلبات التي تم إرسالها إلينا في واجهة برمجة التطبيقات وسنقوم بإنشاء الطلب الذي نحتاجه فقط. ومن خلال ذلك نحقق هدفين في وقت واحد:
  1. نحن نسرع ​​عملية كتابة طلبنا.

  2. نترك هذا العمل لأولئك الذين يريدون مساعدة مجتمعنا ويقررون تجربة أنفسهم كمطورين. سأقوم بإنشاء مهام يمكن إكمالها بعد الحصول على جائزة MVP.

لنفعلها اذا. للاستعلام عن قسم النماذج في Swagger UI، سنقوم بإنشاء DTOs التالية:"مشروع جافا من الألف إلى الياء": إضافة عميل إلى المقالات - 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
}
بناءً على كل هذه DTOs، دعنا نكتب فئة رئيسية لتلقي المقالات:

معلومات المشاركة:

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 وسيطتين: معرف المجموعة والمعرف الأخير للمقالة التي نشرها الروبوت بالفعل. لذلك، سيتم إرسال جميع المقالات التي تم نشرها بعد المقالة التي تحتوي على 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 - البحث فقط عن مجموعات معينة؛
  • الحد = 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());
   }
}
هذا اختبار بسيط للغاية يتحقق مما إذا كان هناك أي اتصال مع العميل على الإطلاق أم لا. لقد وجد 15 مقالة جديدة في مجموعة مشاريع Java، لأنني أعطيته معرف المقالة الأولى في هذه المجموعة، ويوجد بالفعل أكثر من 15 منها... يوجد بالفعل 22 منها! لم أكن أعتقد حتى أنه سيكون هناك الكثير منهم. كيف عرفت بسرعة؟ هل تظن أنه ذهب ليحصيهم؟ لا) لقد استخدمت تبجحًا ونظرت إلى عدد المقالات لمجموعة معينة. بالمناسبة، يمكنك أن تنظر بهذه الطريقة في الآخرين... وكم عدد المقالات الموجودة في مجموعة RANDOM؟... سأخبرك الآن: هناك 1062 مقالة! مبلغ خطير.

نهاية الجزء الأول

لقد أضفنا هنا العمل مع العميل حسب المقالة. لقد فعلنا كل شيء بالفعل، وهذه المرة أعتقد أن كل شيء يجب أن يكون بسيطًا وسريعًا. في المقالة التالية سنضيف Spring Scholer ونكتب FindNewArticleService . حسنًا، كالعادة، قم بإعجاب - اشتراك - دق الجرس ، ومنح مشروعنا نجمة ، وكتابة التعليقات وتقييم المقالة! شكرا لكم جميعا على القراءة – نراكم قريبا!

توجد قائمة بجميع المواد الموجودة في السلسلة في بداية هذه المقالة.

تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION