-
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. -
Jika terdapat artikel baharu, jana mesej untuk semua pengguna yang aktif melanggan kumpulan ini. Jika tiada artikel baharu, kami siapkan sahaja kerja tersebut.
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:
-
Menggunakan groupService kami mencari semua kumpulan yang ada dalam pangkalan data.
-
Kemudian kami bersurai ke semua kumpulan dan untuk setiap kumpulan kami memanggil klien yang dibuat dalam artikel terakhir - javaRushPostClient.findNewPosts .
-
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.
-
Dan menggunakan fakta bahawa GroupSub mempunyai koleksi pengguna, kami menyemak yang aktif dan menghantar pemberitahuan tentang artikel baharu.
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 . Seterusnya, kami pergi ke tapak, mengisih artikel dalam kumpulan projek Java - yang baharu dahulu - dan pergi ke artikel ketiga dari senarai: Mari pergi ke artikel bawah dan dari bar alamat kami mendapat Id artikel - 3313: Seterusnya , pergi ke MySQL Workbench dan tukar nilai lastArticleId kepada 3313. Mari kita lihat bahawa kumpulan sedemikian ada dalam pangkalan data: Dan untuk itu kita akan melaksanakan arahan: Dan 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: Ternyata 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:
GO TO FULL VERSION