สวัสดีทุกคนเพื่อนรักของฉัน ในบทความก่อนหน้านี้เราได้เตรียมไคลเอนต์สำหรับการทำงานกับ JavaRush API สำหรับบทความ ตอนนี้เราสามารถเขียนตรรกะสำหรับงานของเราได้ ซึ่งจะถูกดำเนินการทุกๆ 15 นาที ตรงตามที่แสดงในแผนภาพนี้:
ทุก ๆ 15 นาทีจะมีการเปิดตัวงาน (ในความเห็นของเรา เป็นเพียงวิธีการในคลาสเฉพาะ) ซึ่งจะดำเนินการในพื้นหลังของแอปพลิเคชันหลักและทำสิ่งต่อไปนี้:
ต่อไปเราไปที่ไซต์จัดเรียงบทความในกลุ่มโครงการ Java - บทความใหม่ก่อน - และไปที่บทความที่สามจากรายการ:
ไปที่บทความด้านล่างและจากแถบที่อยู่เราจะได้รหัสบทความ - 3313:
ถัดไป ไปที่ MySQL Workbench และเปลี่ยน ค่า LastArticleIdเป็น 3313 เรามาดูกันว่ากลุ่มดังกล่าวอยู่ในฐานข้อมูล:
และสำหรับมันเราจะดำเนินการคำสั่ง:
เท่านี้ก็เรียบร้อยตอนนี้คุณต้องรอจนกว่าจะมีการเปิดตัวงานครั้งถัดไป ค้นหาบทความใหม่ เราคาดว่าจะได้รับข้อความสองข้อความเกี่ยวกับบทความใหม่จากกลุ่มโครงการ Java อย่างที่พวกเขาพูดกันว่าผลลัพธ์จะเกิดขึ้นไม่นาน:
ปรากฎว่าบอททำงานตามที่เราคาดหวัง
กดไลค์ - ติดตาม - กระดิ่งติดดาวสำหรับโครงการของเราแสดงความคิดเห็นและให้คะแนนบทความ! ขอบคุณทุกคนที่อ่าน
-
ค้นหาในทุกกลุ่มที่อยู่ในฐานข้อมูลของเราบทความใหม่ที่เผยแพร่หลังจากการดำเนินการครั้งก่อน
รูปแบบนี้ระบุกลุ่มจำนวนน้อยกว่า - เฉพาะกลุ่มที่มีผู้ใช้งานอยู่เท่านั้น ในเวลานั้นมันดูสมเหตุสมผลสำหรับฉัน แต่ตอนนี้ฉันเข้าใจแล้วว่าไม่ว่าจะมีผู้ใช้งานที่สมัครเป็นสมาชิกกลุ่มใดกลุ่มหนึ่งหรือไม่ คุณยังคงต้องเก็บบทความล่าสุดที่บอทประมวลผลให้ทันสมัยอยู่เสมอ สถานการณ์อาจเกิดขึ้นเมื่อผู้ใช้ใหม่ได้รับบทความที่เผยแพร่ครบจำนวนทันทีนับตั้งแต่การปิดใช้งานกลุ่มนี้ นี่ไม่ใช่พฤติกรรมที่คาดหวัง และเพื่อหลีกเลี่ยงสิ่งนี้ เราจำเป็นต้องเก็บกลุ่มเหล่านั้นจากฐานข้อมูลของเราซึ่งปัจจุบันยังไม่มีผู้ใช้งานอยู่ -
หากมีบทความใหม่ ให้สร้างข้อความสำหรับผู้ใช้ทุกคนที่สมัครเป็นสมาชิกกลุ่มนี้ หากไม่มีบทความใหม่ เราก็ดำเนินการให้เสร็จสิ้น
ค้นหาบริการบทความใหม่:
package com.github.javarushcommunity.jrtb.service;
/**
* Service for finding new articles.
*/
public interface FindNewArticleService {
/**
* Find new articles and notify subscribers about it.
*/
void findNewArticles();
}
ง่ายมากใช่มั้ย? นี่คือสาระสำคัญและความยากลำบากทั้งหมดจะอยู่ที่การดำเนินการ:
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);
}
}
ที่นี่เราจะจัดการกับทุกสิ่งตามลำดับ:
-
การใช้groupServiceเราจะค้นหากลุ่มทั้งหมดที่อยู่ในฐานข้อมูล
-
จากนั้นเราก็แยกย้ายกันไปทุกกลุ่มและสำหรับแต่ละกลุ่มเราเรียกไคลเอนต์ที่สร้างขึ้นในบทความที่แล้ว- javaRushPostClient.findNewPosts
-
ต่อไป โดยใช้ เมธอด setNewArticleIdเราจะอัปเดต ID บทความของบทความใหม่ล่าสุดของเรา เพื่อให้ฐานข้อมูลของเราทราบว่าเราได้ประมวลผลบทความใหม่แล้ว
-
และด้วยความจริงที่ว่า GroupSub มีกลุ่มผู้ใช้ เราจะดำเนินการผ่านกลุ่มที่ใช้งานอยู่และส่งการแจ้งเตือนเกี่ยวกับบทความใหม่
สร้าง FindNewArticleJob
เราได้พูดคุยไปแล้วว่า SpringScheduler คืออะไร แต่มาทำซ้ำกันอย่างรวดเร็ว: มันเป็นกลไกใน Spring Framework สำหรับการสร้างกระบวนการพื้นหลังที่จะทำงานในเวลาที่เรากำหนดไว้ คุณต้องการอะไรสำหรับสิ่งนี้? ขั้นตอนแรกคือการเพิ่ม คำอธิบายประกอบ @EnableSchedulingให้กับคลาสอินพุตสปริงของเรา: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);
}
}
ขั้นตอนที่สองคือการสร้างคลาส เพิ่มคลาสลงในApplicationContextและสร้างเมธอดในคลาสที่จะเรียกใช้เป็นระยะ เราสร้างแพ็กเกจงานที่ระดับเดียวกับพื้นที่เก็บข้อมูล การบริการ และอื่นๆ และที่นั่นเราสร้าง คลาส 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));
}
}
หากต้องการเพิ่มคลาสนี้ในบริบทแอปพลิเคชันฉันใช้ คำอธิบาย ประกอบ @Component และเพื่อให้เมธอดภายในคลาสรู้ว่าจำเป็นต้องรันเป็นระยะ ฉันจึงเพิ่มคำอธิบายประกอบให้กับเมธอด: @Scheduled(fixedRateString = "${bot.recountNewArticleFixedRate}" ) แต่มันจะเป็นค่าอะไร - เราตั้งค่าไว้แล้วในไฟล์ application.properties:
bot.recountNewArticleFixedRate = 900000
โดยค่านี้จะอยู่ในหน่วยมิลลิวินาที จะเป็นเวลา 15 นาที ในวิธีนี้ ทุกอย่างง่ายดาย: ฉันได้เพิ่มหน่วยเมตริกที่เรียบง่ายสุด ๆ สำหรับตัวเองลงในบันทึกเพื่อคำนวณการค้นหาบทความใหม่ เพื่อที่จะได้เข้าใจคร่าวๆ ว่ามันทำงานเร็วแค่ไหน
การทดสอบฟังก์ชันการทำงานใหม่
ตอนนี้เราจะทดสอบกับบอททดสอบของเรา แต่อย่างไร? ฉันจะไม่ลบบทความทุกครั้งเพื่อแสดงว่ามีการแจ้งเตือนเข้ามา? ไม่แน่นอน เราจะแก้ไขข้อมูลในฐานข้อมูลและเปิดแอปพลิเคชัน ฉันจะทดสอบบนเซิร์ฟเวอร์ทดสอบของฉัน หากต้องการทำสิ่งนี้ ให้สมัครเป็นสมาชิกกลุ่มบางกลุ่ม เมื่อการสมัครสมาชิกเสร็จสมบูรณ์ กลุ่มจะได้รับ ID ปัจจุบันของบทความล่าสุด ไปที่ฐานข้อมูลและเปลี่ยนค่าสองบทความกลับ ด้วยเหตุนี้ เราจึงคาดหวังว่าจะมีบทความมากเท่ากับที่เราตั้งค่าLastArticleId เป็นก่อน หน้า





ตอนจบ
เช่นเคย เราอัปเดตเวอร์ชันใน pom.xml และเพิ่มรายการใน RELEASE_NOTES เพื่อให้บันทึกประวัติการทำงาน และคุณสามารถย้อนกลับไปและทำความเข้าใจสิ่งที่เปลี่ยนแปลงได้ตลอดเวลา ดังนั้นเราจึงเพิ่มเวอร์ชันทีละหนึ่งหน่วย:<version>0.7.0-SNAPSHOT</version>
และอัปเดต RELEASE_NOTES:
## 0.7.0-SNAPSHOT * JRTB-4: เพิ่มความสามารถในการส่งการแจ้งเตือนเกี่ยวกับบทความใหม่ * JRTB-8: เพิ่มความสามารถในการตั้งค่าผู้ใช้โทรเลขที่ไม่ใช้งาน * JRTB-9: เพิ่มความสามารถในการตั้งค่าผู้ใช้ที่ใช้งานอยู่และ/หรือเริ่มใช้งาน
ตอนนี้คุณสามารถสร้างคำขอดึงและอัปโหลดการเปลี่ยนแปลงใหม่ได้ นี่คือคำขอดึงที่มีการเปลี่ยนแปลงทั้งหมดในสองส่วน: STEP_8 อะไรต่อไป? ดูเหมือนทุกอย่างจะพร้อมแล้วอย่างที่เราบอกไปว่าสามารถเข้าสู่การผลิตได้ แต่ก็ยังมีบางอย่างที่อยากทำ ตัวอย่างเช่น กำหนดค่าการทำงานของผู้ดูแลระบบสำหรับบอท เพิ่มและเพิ่มความสามารถในการตั้งค่า เป็นความคิดที่ดีที่จะอ่านโค้ดก่อนที่จะเสร็จสิ้นและดูว่ามีสิ่งใดบ้างที่สามารถปรับโครงสร้างใหม่ได้ ฉันเห็นการไม่ซิงโครไนซ์ในการตั้งชื่อบทความ/โพสต์แล้ว ในตอนท้ายเราจะทำการย้อนหลังสิ่งที่เราวางแผนไว้และสิ่งที่เราได้รับ และคุณอยากจะทำอะไรในอนาคต? ตอนนี้ ฉันจะแบ่งปันแนวคิดที่ค่อนข้างหยาบคายกับคุณซึ่งสามารถและจะเห็นแสงสว่างของวัน: เพื่อสร้างตัวเริ่มต้น springboot ที่จะมีฟังก์ชันการทำงานทั้งหมดสำหรับการทำงานกับบอตโทรเลขและค้นหาบทความ สิ่งนี้จะทำให้สามารถรวมแนวทางและใช้กับบอทโทรเลขตัวอื่นได้ สิ่งนี้จะทำให้โครงการนี้เข้าถึงผู้อื่นได้มากขึ้นและเป็นประโยชน์ต่อผู้คนมากขึ้น นี่คือหนึ่งในความคิด อีกแนวคิดหนึ่งคือการเจาะลึกการพัฒนาการแจ้งเตือน แต่เราจะพูดถึงเรื่องนี้อีกสักหน่อย ขอขอบคุณทุกท่านที่ให้ความสนใจเช่นเคย:
GO TO FULL VERSION