JavaRush /Blog Java /Random-MS /Menambah Penjadual Spring - "Projek Java dari A hingga Z"...

Menambah Penjadual Spring - "Projek Java dari A hingga Z"

Diterbitkan dalam kumpulan
Hello semua, kawan-kawan yang dikasihi. Dalam artikel sebelumnya , kami menyediakan pelanggan untuk bekerja dengan JavaRush API untuk artikel. Sekarang kita boleh menulis logik untuk kerja kita, yang akan dilaksanakan setiap 15 minit. Tepat seperti yang ditunjukkan dalam rajah ini: “Projek Java dari A hingga Z”: Menambah Penjadual Spring - 1Setiap 15 minit kerja akan dilancarkan (pada pendapat kami, hanya kaedah dalam kelas tertentu), yang dilaksanakan di latar belakang aplikasi utama dan melakukan perkara berikut:
  1. Cari dalam semua kumpulan yang berada dalam pangkalan data kami artikel baharu yang diterbitkan selepas pelaksanaan sebelumnya.

    Skim ini menentukan bilangan kumpulan yang lebih kecil - hanya kumpulan yang mempunyai pengguna aktif. Pada masa itu ia kelihatan logik kepada saya, tetapi kini saya faham bahawa tidak kira sama ada terdapat pengguna aktif yang melanggan kumpulan tertentu atau tidak, anda masih perlu memastikan artikel terbaharu yang diproses bot itu dikemas kini. Situasi mungkin timbul apabila pengguna baharu segera menerima keseluruhan jumlah artikel yang diterbitkan sejak penyahaktifan kumpulan ini. Ini bukan tingkah laku yang dijangka, dan untuk mengelakkannya, kami perlu memastikan kumpulan tersebut daripada pangkalan data kami yang pada masa ini tidak mempunyai pengguna aktif yang terkini.
  2. Jika terdapat artikel baharu, jana mesej untuk semua pengguna yang aktif melanggan kumpulan ini. Jika tiada artikel baharu, kami siapkan sahaja kerja tersebut.

Dengan cara ini, saya telah menyebut dalam saluran TG saya bahawa bot sudah berfungsi dan menghantar artikel baharu berdasarkan langganan. Mari mulakan menulis FindNewArtcileService . Semua kerja mencari dan menghantar mesej akan berlaku di sana, dan kerja itu hanya akan melancarkan kaedah perkhidmatan ini:

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();
}
Sangat mudah, bukan? Inilah intipatinya, dan semua kesukaran akan berlaku dalam pelaksanaan:
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);
   }
}
Di sini kita akan berurusan dengan segala-galanya mengikut urutan:
  1. Menggunakan groupService kami mencari semua kumpulan yang ada dalam pangkalan data.

  2. Kemudian kami bersurai ke semua kumpulan dan untuk setiap kumpulan kami memanggil klien yang dibuat dalam artikel terakhir - javaRushPostClient.findNewPosts .

  3. Seterusnya, menggunakan kaedah setNewArticleId , kami mengemas kini ID artikel artikel baharu kami yang terkini supaya pangkalan data kami mengetahui bahawa kami telah memproses yang baharu.

  4. Dan menggunakan fakta bahawa GroupSub mempunyai koleksi pengguna, kami menyemak yang aktif dan menghantar pemberitahuan tentang artikel baharu.

Kami tidak akan membincangkan apa mesej itu sekarang, ia tidak begitu penting untuk kami. Perkara utama ialah kaedah itu berfungsi. Logik untuk mencari artikel baharu dan menghantar pemberitahuan sudah sedia, jadi anda boleh meneruskan untuk mencipta pekerjaan.

Buat FindNewArticleJob

Kami telah pun bercakap tentang apa itu SpringScheduler, tetapi mari kita ulangi dengan cepat: ini adalah mekanisme dalam rangka kerja Spring untuk mencipta proses latar belakang yang akan berjalan pada masa tertentu yang kami tetapkan. Apa yang anda perlukan untuk ini? Langkah pertama ialah menambah anotasi @EnableScheduling ke kelas input musim bunga kami:
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);
   }

}
Langkah kedua ialah mencipta kelas, tambahkannya pada ApplicationContext dan buat kaedah di dalamnya yang akan dijalankan secara berkala. Kami mencipta pakej kerja pada tahap yang sama seperti repositori, perkhidmatan dan sebagainya, dan di sana kami mencipta kelas FindNewArticleJob :
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));
   }
}
Untuk menambah kelas ini pada Konteks Aplikasi, saya menggunakan anotasi @Component . Dan supaya kaedah di dalam kelas mengetahui bahawa ia perlu dijalankan secara berkala, saya menambah anotasi kepada kaedah: @Scheduled(fixedRateString = "${bot.recountNewArticleFixedRate}") . Tetapi kami menetapkannya dalam fail application.properties:
bot.recountNewArticleFixedRate = 900000
Di sini nilainya adalah dalam milisaat. Ia akan menjadi 15 minit. Dalam kaedah ini, segala-galanya adalah mudah: Saya menambah metrik yang sangat mudah untuk diri saya sendiri dalam log untuk mengira carian untuk artikel baharu, untuk sekurang-kurangnya memahami secara kasar betapa pantas ia berfungsi.

Menguji fungsi baharu

Sekarang kami akan menguji bot ujian kami. Tetapi bagaimana? Saya tidak akan memadamkan artikel setiap kali untuk menunjukkan bahawa pemberitahuan telah tiba? Sudah tentu tidak. Kami hanya akan mengedit data dalam pangkalan data dan melancarkan aplikasi. Saya akan mengujinya pada pelayan ujian saya. Untuk melakukan ini, mari melanggan beberapa kumpulan. Apabila langganan selesai, kumpulan akan diberikan ID semasa artikel terkini. Mari pergi ke pangkalan data dan tukar nilai dua artikel kembali. Akibatnya, kami menjangkakan bahawa akan terdapat banyak artikel seperti yang kami tetapkan lastArticleId sebelum ini . "Projek Java dari A hingga Z": Menambah Penjadual Spring - 2Seterusnya, kami pergi ke tapak, mengisih artikel dalam kumpulan projek Java - yang baharu dahulu - dan pergi ke artikel ketiga dari senarai: "Java-проект от А до Я": Добавляем Spring Scheduler - 3Mari pergi ke artikel bawah dan dari bar alamat kami mendapat Id artikel - 3313: "Java-проект от А до Я": Добавляем Spring Scheduler - 4Seterusnya , pergi ke MySQL Workbench dan tukar nilai lastArticleId kepada 3313. Mari kita lihat bahawa kumpulan sedemikian ada dalam pangkalan data: "Java-проект от А до Я": Добавляем Spring Scheduler - 5Dan untuk itu kita akan melaksanakan arahan: "Java-проект от А до Я": Добавляем Spring Scheduler - 6Dan itu sahaja, kini anda perlu menunggu sehingga pelancaran kerja seterusnya untuk mencari artikel baru. Kami menjangkakan untuk menerima dua mesej tentang artikel baharu daripada kumpulan projek Java. Seperti yang mereka katakan, hasilnya tidak lama lagi: "Java-проект от А до Я": Добавляем Spring Scheduler - 7Ternyata bot itu berfungsi seperti yang kami jangkakan.

Berakhir

Seperti biasa, kami mengemas kini versi dalam pom.xml dan menambah entri pada RELEASE_NOTES supaya sejarah kerja disimpan dan anda sentiasa boleh kembali dan memahami perkara yang telah berubah. Oleh itu, kami menambah versi dengan satu unit:
<version>0.7.0-SNAPSHOT</version>
Dan kemas kini RELEASE_NOTES:
## 0.7.0-SNAPSHOT * JRTB-4: menambah keupayaan untuk menghantar pemberitahuan tentang artikel baharu * JRTB-8: menambah keupayaan untuk menetapkan pengguna telegram tidak aktif * JRTB-9: menambah keupayaan untuk menetapkan pengguna aktif dan/atau mula menggunakannya.
Kini anda boleh membuat permintaan tarik dan memuat naik perubahan baharu. Berikut ialah permintaan tarik dengan semua perubahan dalam dua bahagian: STEP_8 . Apa yang akan datang? Nampaknya semuanya sudah siap dan, seperti yang kita katakan, ia boleh masuk ke dalam pengeluaran, tetapi masih ada beberapa perkara yang saya mahu lakukan. Sebagai contoh, konfigurasikan kerja pentadbir untuk bot, tambahkan mereka dan tambahkan keupayaan untuk menetapkannya. Ia juga merupakan idea yang baik untuk menyemak kod sebelum menyelesaikan dan melihat sama ada terdapat perkara yang boleh difaktorkan semula. Saya sudah dapat melihat penyahsegerakan dalam penamaan artikel/siaran. Pada akhirnya, kami akan melakukan retrospektif terhadap apa yang kami rancang dan apa yang kami terima. Dan apakah yang anda ingin lakukan pada masa hadapan? Sekarang saya akan berkongsi dengan anda idea yang agak kasar yang boleh dan akan melihat cahaya hari: untuk membuat pemula springboot yang akan mempunyai semua fungsi untuk bekerja dengan bot telegram dan mencari artikel. Ini akan memungkinkan untuk menyatukan pendekatan dan menggunakannya untuk bot telegram lain. Ini akan menjadikan projek ini lebih mudah diakses oleh orang lain dan boleh memberi manfaat kepada lebih ramai orang. Ini adalah salah satu idea. Idea lain adalah untuk pergi lebih mendalam ke dalam pembangunan pemberitahuan. Tetapi kita akan bercakap tentang ini sedikit kemudian. Terima kasih semua atas perhatian anda, seperti biasa: suka - langgan - loceng , bintang untuk projek kami , komen dan nilai artikel! Terima kasih semua kerana membaca.

Senarai semua bahan dalam siri ini adalah pada permulaan artikel ini.

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