JavaRush /Java Blogu /Random-AZ /Bahar Planlayıcısının əlavə edilməsi - "A-dan Z-yə Java l...
Roman Beekeeper
Səviyyə

Bahar Planlayıcısının əlavə edilməsi - "A-dan Z-yə Java layihəsi"

Qrupda dərc edilmişdir
Hər kəsə salam əziz dostlarım. Əvvəlki məqalədə məqalələr üçün JavaRush API ilə işləmək üçün müştəri hazırlamışdıq. İndi hər 15 dəqiqədən bir yerinə yetiriləcək işimiz üçün məntiq yaza bilərik. Məhz bu diaqramda göstərildiyi kimi: “A-dan Z-yə Java layihəsi”: Bahar Planlayıcısının əlavə edilməsi - 1Hər 15 dəqiqədən bir əsas tətbiqin fonunda yerinə yetirilən və aşağıdakıları yerinə yetirən bir iş (bizim fikrimizcə, yalnız müəyyən bir sinifdə bir üsul) işə salınacaq:
  1. Verilənlər bazamızda olan bütün qruplarda əvvəlki icradan sonra dərc edilmiş yeni məqalələri tapır.

    Bu sxem daha az sayda qrupları müəyyən edir - yalnız aktiv istifadəçiləri olanlar. O vaxt mənə məntiqli görünürdü, amma indi başa düşürəm ki, konkret qrupa abunə olan aktiv istifadəçilərin olub-olmamasından asılı olmayaraq, siz hələ də botun işlədiyi ən son məqaləni aktual saxlamalısınız. Yeni istifadəçi bu qrup ləğv edildikdən sonra dərc edilmiş məqalələrin bütün sayını dərhal aldıqda vəziyyət yarana bilər. Bu gözlənilən davranış deyil və bunun qarşısını almaq üçün hazırda aktiv istifadəçiləri olmayan qrupları bazamızda saxlamalıyıq.
  2. Yeni məqalələr varsa, bu qrupa aktiv şəkildə abunə olan bütün istifadəçilər üçün mesajlar yaradın. Yeni məqalələr yoxdursa, sadəcə işi tamamlayırıq.

Yeri gəlmişkən, artıq TG kanalımda qeyd etdim ki, bot artıq işləyir və abunələrə əsaslanan yeni məqalələr göndərir. FindNewArtcileService yazmağa başlayaq . Mesajların axtarışı və göndərilməsi ilə bağlı bütün işlər orada aparılacaq və iş yalnız bu xidmətin metodunu işə salacaq:

FindNewArticleService:

package com.github.javarushcommunity.jrtb.service;

/**
* Service for finding new articles.
*/
public interface FindNewArticleService {

   /**
    * Find new articles and notify subscribers about it.
    */
   void findNewArticles();
}
Çox sadə, elə deyilmi? Bu, onun mahiyyətidir və bütün çətinlik icrada olacaq:
package com.github.javarushcommunity.jrtb.service;

import com.github.javarushcommunity.jrtb.javarushclient.JavaRushPostClient;
import com.github.javarushcommunity.jrtb.javarushclient.dto.PostInfo;
import com.github.javarushcommunity.jrtb.repository.entity.GroupSub;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class FindNewArticleServiceImpl implements FindNewArticleService {

   public static final String JAVARUSH_WEB_POST_FORMAT = "https://javarush.com/groups/posts/%s";

   private final GroupSubService groupSubService;
   private final JavaRushPostClient javaRushPostClient;
   private final SendBotMessageService sendMessageService;

   @Autowired
   public FindNewArticleServiceImpl(GroupSubService groupSubService,
                                    JavaRushPostClient javaRushPostClient,
                                    SendBotMessageService sendMessageService) {
       this.groupSubService = groupSubService;
       this.javaRushPostClient = javaRushPostClient;
       this.sendMessageService = sendMessageService;
   }


   @Override
   public void findNewArticles() {
       groupSubService.findAll().forEach(gSub -> {
           List<PostInfo> newPosts = javaRushPostClient.findNewPosts(gSub.getId(), gSub.getLastArticleId());

           setNewLastArticleId(gSub, newPosts);

           notifySubscribersAboutNewArticles(gSub, newPosts);
       });
   }

   private void notifySubscribersAboutNewArticles(GroupSub gSub, List<PostInfo> newPosts) {
       Collections.reverse(newPosts);
       List<String> messagesWithNewArticles = newPosts.stream()
               .map(post -> String.format("✨Вышла новая статья <b>%s</b> в группе <b>%s</b>.✨\n\n" +
                               "<b>Описание:</b> %s\n\n" +
                               "<b>Ссылка:</b> %s\n",
                       post.getTitle(), gSub.getTitle(), post.getDescription(), getPostUrl(post.getKey())))
               .collect(Collectors.toList());

       gSub.getUsers().stream()
               .filter(TelegramUser::isActive)
               .forEach(it -> sendMessageService.sendMessage(it.getChatId(), messagesWithNewArticles));
   }

   private void setNewLastArticleId(GroupSub gSub, List<PostInfo> newPosts) {
       newPosts.stream().mapToInt(PostInfo::getId).max()
               .ifPresent(id -> {
                   gSub.setLastArticleId(id);
                   groupSubService.save(gSub);
               });
   }

   private String getPostUrl(String key) {
       return String.format(JAVARUSH_WEB_POST_FORMAT, key);
   }
}
Burada hər şeyi qaydasında həll edəcəyik:
  1. groupService istifadə edərək verilənlər bazasında olan bütün qrupları tapırıq.

  2. Sonra bütün qruplara dağılırıq və hər biri üçün son məqalədə yaradılmış müştəri çağırırıq - javaRushPostClient.findNewPosts .

  3. Sonra, setNewArticleId metodundan istifadə edərək , ən son yeni məqaləmizin məqalə identifikatorunu yeniləyirik ki, verilənlər bazamız artıq yenilərini emal etdiyimizi bilsin.

  4. Və GroupSub-un istifadəçilər toplusuna malik olması faktından istifadə edərək, biz aktiv olanlardan keçirik və yeni məqalələr haqqında bildirişlər göndəririk.

İndi mesajın nə olduğunu müzakirə etməyəcəyik, bu bizim üçün çox da vacib deyil. Əsas odur ki, metod işləyir. Yeni məqalələrin axtarışı və bildirişlərin göndərilməsi məntiqi hazırdır, ona görə də iş yaratmağa davam edə bilərsiniz.

FindNewArticleJob yaradın

SpringScheduler-in nə olduğu haqqında artıq danışdıq, lakin gəlin bunu tez bir zamanda təkrarlayaq: bu, bizim təyin etdiyimiz müəyyən vaxtda işləyəcək fon prosesi yaratmaq üçün Bahar çərçivəsindəki mexanizmdir. Bunun üçün sizə nə lazımdır? İlk addım yaz giriş sinifimizə @EnableScheduling annotasiyasını əlavə etməkdir :
package com.github.javarushcommunity.jrtb;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@EnableScheduling
@SpringBootApplication
public class JavarushTelegramBotApplication {

   public static void main(String[] args) {
       SpringApplication.run(JavarushTelegramBotApplication.class, args);
   }

}
İkinci addım sinif yaratmaq, onu ApplicationContext- ə əlavə etmək və orada vaxtaşırı işlədilən metod yaratmaqdır. Biz repozitoriya, xidmət və s. ilə eyni səviyyədə iş paketi yaradırıq və orada FindNewArticleJob sinfini yaradırıq :
package com.github.javarushcommunity.jrtb.job;

import com.github.javarushcommunity.jrtb.service.FindNewArticleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.ZoneOffset;

/**
* Job for finding new articles.
*/
@Slf4j
@Component
public class FindNewArticlesJob {

   private final FindNewArticleService findNewArticleService;

   @Autowired
   public FindNewArticlesJob(FindNewArticleService findNewArticleService) {
       this.findNewArticleService = findNewArticleService;
   }

   @Scheduled(fixedRateString = "${bot.recountNewArticleFixedRate}")
   public void findNewArticles() {
       LocalDateTime start = LocalDateTime.now();

       log.info("Find new article job started.");

       findNewArticleService.findNewArticles();

       LocalDateTime end = LocalDateTime.now();

       log.info("Find new articles job finished. Took seconds: {}",
               end.toEpochSecond(ZoneOffset.UTC) - start.toEpochSecond(ZoneOffset.UTC));
   }
}
Bu sinfi Tətbiq Kontekstinə əlavə etmək üçün @Component annotasiyasından istifadə etdim . Sinif daxilindəki metodun onun vaxtaşırı işə salınması lazım olduğunu bilməsi üçün metoda annotasiya əlavə etdim: @Scheduled(fixedRateString = "${bot.recountNewArticleFixedRate}") . Amma biz bunu application.properties faylında təyin etdik:
bot.recountNewArticleFixedRate = 900000
Burada dəyər millisaniyədədir. 15 dəqiqə olacaq. Bu üsulda hər şey sadədir: yeni məqalələrin axtarışını hesablamaq üçün qeydlərə özüm üçün super sadə bir metrik əlavə etdim ki, heç olmasa onun nə qədər sürətli işlədiyini başa düşsün.

Yeni funksionallığın sınaqdan keçirilməsi

İndi test botumuzda test edəcəyik. Bəs necə? Bildirişlərin gəldiyini göstərmək üçün hər dəfə məqalələri silməyəcəyəm? Əlbəttə yox. Biz sadəcə olaraq verilənlər bazasındakı məlumatları redaktə edəcəyik və proqramı işə salacağıq. Test serverimdə sınaqdan keçirəcəyəm. Bunun üçün gəlin hansısa qrupa abunə olaq. Abunəlik başa çatdıqdan sonra qrupa son məqalənin cari ID-si veriləcək. Gəlin verilənlər bazasına gedək və dəyəri iki məqalə geri dəyişək. Nəticədə, biz lastArticleId-i daha əvvəl təyin etdiyimiz qədər məqalə olacağını gözləyirik . "A-dan Z-yə Java layihəsi": Bahar Planlayıcısının əlavə edilməsi - 2Sonra, sayta daxil oluruq, Java layihələri qrupundakı məqalələri çeşidləyirik - əvvəlcə yeniləri - və siyahıdan üçüncü məqaləyə keçək: "Java-проект от А до Я": Добавляем Spring Scheduler - 3Aşağıdakı məqaləyə keçək və ünvan çubuğundan Id - 3313 məqaləsini alırıq: "Java-проект от А до Я": Добавляем Spring Scheduler - 4Sonrakı , MySQL Workbench-ə keçin və lastArticleId dəyərini 3313-ə dəyişin. Gəlin görək belə bir qrup verilənlər bazasındadır: "Java-проект от А до Я": Добавляем Spring Scheduler - 5Və bunun üçün əmri yerinə yetirəcəyik: "Java-проект от А до Я": Добавляем Spring Scheduler - 6Və budur, indi işin növbəti işə salınmasını gözləmək lazımdır. yeni məqalələr axtarın. Java layihələri qrupundan yeni məqalə haqqında iki mesaj alacağımızı gözləyirik. Necə deyərlər, nəticə özünü çox gözlətməyib: "Java-проект от А до Я": Добавляем Spring Scheduler - 7Belə çıxır ki, bot gözlədiyimiz kimi işləyir.

Son

Həmişə olduğu kimi, biz pom.xml-dəki versiyanı yeniləyirik və RELEASE_NOTES-ə giriş əlavə edirik ki, iş tarixçəsi yadda saxlanılsın və siz həmişə geri qayıdıb nəyin dəyişdiyini başa düşə biləsiniz. Beləliklə, versiyanı bir vahid artırırıq:
<version>0.7.0-SNAPSHOT</version>
Və RELEASE_NOTES-i yeniləyin:
## 0.7.0-SNAPSHOT * JRTB-4: yeni məqalələr haqqında bildiriş göndərmək imkanı əlavə edilib * JRTB-8: qeyri-aktiv teleqram istifadəçisini təyin etmək üçün əlavə imkan * JRTB-9: aktiv istifadəçi qurmaq və/və ya ondan istifadə etməyə başlamaq imkanı əlavə edilib.
İndi siz çəkmə sorğusu yarada və yeni dəyişikliklər yükləyə bilərsiniz. Budur, iki hissədən ibarət bütün dəyişikliklərlə çəkilmə sorğusu: STEP_8 . Sonra nə var? Deyəsən, hər şey hazırdır və dediyimiz kimi, istehsala keçə bilər, amma hələ də etmək istədiyim bəzi şeylər var. Məsələn, bot üçün adminlərin işini konfiqurasiya edin, onları əlavə edin və qurmaq imkanı əlavə edin. Bitirməmişdən əvvəl koddan keçmək və yenidən düzəldilə bilən şeylərin olub olmadığını yoxlamaq da yaxşı fikirdir. Artıq məqalənin/yazının adlandırılmasında sinxronizasiyanı görə bilirəm. Sonda biz nə planlaşdırdığımızın və nə aldığımızın retrospektivini edəcəyik. Və gələcəkdə nə etmək istərdiniz? İndi mən sizinlə günün işığını görə biləcək və görəcək kifayət qədər kobud bir fikri paylaşacağam: teleqram botu ilə işləmək və məqalələr axtarmaq üçün bütün funksiyaları özündə cəmləşdirəcək bir yay başlanğıcı hazırlamaq. Bu, yanaşmanı birləşdirməyə və ondan digər teleqram botları üçün istifadə etməyə imkan verəcək. Bu, bu layihəni başqaları üçün daha əlçatan edəcək və daha çox insana fayda verə bilər. Bu fikirlərdən biridir. Başqa bir fikir bildirişin inkişafına daha dərindən getməkdir. Ancaq bu barədə bir az sonra danışacağıq. Diqqətiniz üçün hamınıza təşəkkür edirəm, həmişəki kimi: bəyənin - abunə olun - zəng edin , layihəmiz üçün ulduz verin , məqaləni şərh edin və qiymətləndirin! Oxuduğunuz üçün hər kəsə təşəkkür edirəm.

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