-
Tìm trong tất cả các nhóm có trong cơ sở dữ liệu của chúng tôi các bài viết mới được xuất bản sau lần thực hiện trước đó.
Lược đồ này chỉ định số lượng nhóm nhỏ hơn - chỉ những nhóm có người dùng đang hoạt động. Vào thời điểm đó, điều đó đối với tôi có vẻ hợp lý, nhưng bây giờ tôi hiểu rằng bất kể có người dùng đang hoạt động nào đăng ký vào một nhóm cụ thể hay không, bạn vẫn cần cập nhật bài viết mới nhất mà bot xử lý. Một tình huống có thể phát sinh khi người dùng mới nhận được ngay toàn bộ số bài viết đã xuất bản kể từ khi nhóm này ngừng hoạt động. Đây không phải là hành vi được mong đợi và để tránh nó, chúng tôi cần loại bỏ những nhóm hiện không có người dùng hoạt động khỏi cơ sở dữ liệu của chúng tôi. -
Nếu có bài viết mới, hãy tạo tin nhắn cho tất cả người dùng đã đăng ký tích cực vào nhóm này. Nếu không có bài viết mới, chúng tôi chỉ đơn giản là hoàn thành công việc.
Dịch vụ FindNewArticle:
package com.github.javarushcommunity.jrtb.service;
/**
* Service for finding new articles.
*/
public interface FindNewArticleService {
/**
* Find new articles and notify subscribers about it.
*/
void findNewArticles();
}
Rất đơn giản phải không? Đây là bản chất của nó và tất cả khó khăn sẽ nằm ở việc thực hiện:
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);
}
}
Ở đây chúng tôi sẽ giải quyết mọi thứ theo thứ tự:
-
Sử dụng groupService chúng tôi tìm thấy tất cả các nhóm có trong cơ sở dữ liệu.
-
Sau đó, chúng tôi phân tán đến tất cả các nhóm và với mỗi nhóm, chúng tôi gọi ứng dụng khách được tạo trong bài viết trước - javaRushPostClient.findNewPosts .
-
Tiếp theo, bằng cách sử dụng phương thức setNewArticleId , chúng ta cập nhật ID bài viết của bài viết mới nhất để cơ sở dữ liệu biết rằng chúng tôi đã xử lý bài viết mới.
-
Và dựa trên thực tế là GroupSub có một tập hợp người dùng, chúng tôi xem xét những người dùng đang hoạt động và gửi thông báo về các bài viết mới.
Tạo FindNewArticleJob
Chúng ta đã nói về SpringScheduler là gì, nhưng hãy nhắc lại nhanh: đó là một cơ chế trong Spring framework để tạo một quy trình nền sẽ chạy vào một thời điểm cụ thể mà chúng ta đã đặt. Bạn cần gì cho việc này? Bước đầu tiên là thêm chú thích @EnableScheduling vào lớp đầu vào mùa xuân của chúng ta: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);
}
}
Bước thứ hai là tạo một lớp, thêm nó vào ApplicationContext và tạo một phương thức trong đó sẽ được chạy định kỳ. Chúng tôi tạo một gói công việc ở cùng cấp độ với kho lưu trữ, dịch vụ, v.v. và ở đó chúng tôi tạo lớp 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));
}
}
Để thêm lớp này vào Bối cảnh ứng dụng , tôi đã sử dụng chú thích @Component . Và để phương thức bên trong lớp biết rằng nó cần được chạy định kỳ, tôi đã thêm chú thích vào phương thức: @Scheduled(fixedRateString = "${bot.recountNewArticleFixedRate}") . Nhưng chúng tôi đặt nó trong tệp application.properties:
bot.recountNewArticleFixedRate = 900000
Ở đây giá trị tính bằng mili giây. Sẽ là 15 phút. Trong phương pháp này, mọi thứ đều đơn giản: Tôi đã thêm một số liệu siêu đơn giản cho chính mình vào nhật ký để tính toán tìm kiếm các bài viết mới, nhằm ít nhất là hiểu đại khái tốc độ hoạt động của nó.
Thử nghiệm chức năng mới
Bây giờ chúng ta sẽ thử nghiệm trên bot thử nghiệm của mình. Nhưng bằng cách nào? Tôi sẽ không xóa bài viết mỗi lần để hiển thị rằng thông báo đã đến? Dĩ nhiên là không. Chúng tôi chỉ cần chỉnh sửa dữ liệu trong cơ sở dữ liệu và khởi chạy ứng dụng. Tôi sẽ thử nghiệm nó trên máy chủ thử nghiệm của tôi. Để làm điều này, hãy đăng ký vào một số nhóm. Khi đăng ký hoàn tất, nhóm sẽ được cấp ID hiện tại của bài viết mới nhất. Hãy vào cơ sở dữ liệu và thay đổi giá trị của hai bài viết. Do đó, chúng tôi mong đợi rằng sẽ có nhiều bài viết như chúng tôi đã đặt LastArticleId thành trước đó . Tiếp theo, chúng ta vào trang web, sắp xếp các bài viết trong nhóm dự án Java - những bài mới trước - và đi đến bài viết thứ ba từ danh sách: Chúng ta hãy đi đến bài viết dưới cùng và từ thanh địa chỉ, chúng ta nhận được Id bài viết - 3313: Next , hãy truy cập MySQL Workbench và thay đổi giá trị LastArticleId thành 3313. Hãy xem một nhóm như vậy có trong cơ sở dữ liệu hay không: Và đối với nó, chúng ta sẽ thực thi lệnh: Và thế là xong, bây giờ bạn cần đợi cho đến lần khởi chạy công việc tiếp theo để tìm kiếm bài viết mới. Chúng tôi mong đợi nhận được hai thông báo về một bài viết mới từ nhóm dự án Java. Như họ nói, không lâu nữa sẽ có kết quả: Hóa ra bot đã hoạt động như chúng tôi mong đợi.Kết thúc
Như mọi khi, chúng tôi cập nhật phiên bản trong pom.xml và thêm mục nhập vào RELEASE_NOTES để lịch sử công việc được lưu và bạn luôn có thể quay lại và hiểu những gì đã thay đổi. Do đó, chúng tôi tăng phiên bản lên một đơn vị:<version>0.7.0-SNAPSHOT</version>
Và cập nhật RELEASE_NOTES:
GO TO FULL VERSION