ฉันชื่อวลาดิเมียร์ ฉันอายุ 43 ปี และถ้าคุณผู้อ่านอายุเกิน 40 ปีแล้วล่ะก็ หลังจากอายุ 40 ปีคุณก็สามารถเป็นโปรแกรมเมอร์ได้ถ้าชอบ งานของฉันไม่เกี่ยวกับการเขียนโปรแกรมเลย ฉันเป็นผู้จัดการโครงการในสาขาระบบอัตโนมัติและทั้งหมดนั้น แต่ฉันวางแผนที่จะเปลี่ยนอาชีพของฉัน โอ้ เทรนด์ใหม่เหล่านี้... เปลี่ยนสาขากิจกรรมของคุณทุกๆ 5-7 ปี ดังนั้น : โปรเจ็กต์นี้กลายเป็นโปรเจ็กต์ที่ค่อนข้างใหญ่ เลยต้องละเว้นบางจุดหรือพูดคุยสั้นๆ ด้วยความหวังว่าผู้อ่านจะรู้จัก Google อินเทอร์เน็ตเต็มไปด้วยสิ่งพิมพ์ของบอทโทรเลขที่ทำงานเกี่ยวกับหลักการของการสำรวจความคิดเห็นแบบยาว และมีน้อยมากที่ใช้หลักการ Webhook ได้ มันคืออะไร? การโพลแบบยาว - หมายความว่าแอปพลิเคชันของคุณจะสำรวจเซิร์ฟเวอร์โทรเลขเพื่อหาข้อความที่ความถี่หนึ่งอย่างช้าๆ Webhook - หมายถึงเซิร์ฟเวอร์โทรเลขจะเปลี่ยนเส้นทางข้อความไปยังเซิร์ฟเวอร์ที่คุณระบุทันที ในกรณีของเรา ได้รับความอนุเคราะห์จากบริการ Heroku แน่นอนคุณสามารถอ่านเพิ่มเติมเกี่ยวกับทั้งหมดนี้และเกี่ยวกับบอทโดยทั่วไปได้ที่เว็บไซต์ Telegram - https://tlgrm.ru/docs/bots/api อินเทอร์เฟซของบอทมีลักษณะดังนี้: ฉันถือว่าแอปพลิเคชันนี้เป็นการฝึกอบรมอย่างแม่นยำ โครงการด้วยเหตุผลที่ว่าเมื่อเขียนฉันเรียนรู้ข้อมูลจากบอทนี้มากกว่าตอนฝึกอบรม คุณต้องการเรียนรู้การเขียนโปรแกรมหรือไม่? เริ่มเขียนโค้ด!!! แต่! จะไม่มีคำแนะนำโดยละเอียดเกี่ยวกับวิธีการอัปโหลดแอปพลิเคชันไปยัง GitHub หรือวิธีสร้างฐานข้อมูล มีสิ่งนี้มากมายบนอินเทอร์เน็ตและมีการอธิบายอย่างละเอียด นอกจากนี้ มันจะเป็นการอ่านที่ยาวมาก แอพพลิเคชั่นจะทำงานดังนี้ ใส่คำอธิบายงาน, ใส่วันที่และเวลาของงาน, เลือกความถี่ (ทำได้ครั้งเดียว, ตั้งเตือนได้ทุกวันตามเวลาที่กำหนด, ตั้งได้ครั้งเดียว) เดือนละครั้งหรือปีละครั้ง) สามารถเพิ่มการแจ้งเตือนรูปแบบต่างๆ ได้ไม่รู้จบ ฉันมีไอเดียมากมาย ถัดไป ข้อมูลที่ป้อนจะถูกบันทึกลงในฐานข้อมูล (ใช้งานฟรีบน Heroku ได้ฟรี 10,000 แถว) จากนั้นเมื่อเริ่มต้นวันใหม่เวลา 0:00 น. ตามเวลาเซิร์ฟเวอร์ Spring จะดึงข้อมูลเหตุการณ์ทั้งหมดจากฐานข้อมูลตามเกณฑ์ ที่ควรยิงในวันนั้นและส่งไปปฏิบัติการตามเวลาที่กำหนด ความสนใจ!!! ส่วนนี้ของโปรแกรมเป็นการทดลอง! มีการดำเนินการที่เรียบง่ายและเป็นจริงมากขึ้น! สิ่งนี้ทำขึ้นโดยเฉพาะเพื่อดูว่าคลาสเรียนทำงานอย่างไร! คุณสามารถสัมผัสบอทที่ใช้งานได้ด้วยมือของคุณเองโดยพิมพ์ @calendar_event_bot ลงในรถเข็น แต่อย่าพึ่งเชื่อใจมัน เพราะฉันยังคงสนุกกับมันอยู่ รหัส - https://github.com/papoff8295/webHookBotForHabr โดยพื้นฐานแล้ว ในการเปิดตัวของคุณเอง คุณต้องทำตามขั้นตอนต่อไปนี้: • ลงทะเบียนกับ@BotFatherไม่ยาก รับโทเค็นและชื่อ • แยกโครงการบน github • ลงทะเบียน บนเฮโรกุสร้างแอปพลิเคชัน (เราจะดำเนินการทีละขั้นตอน) ปรับใช้จากพื้นที่เก็บข้อมูลของคุณ • สร้างฐานข้อมูลบน Heroku • แทนที่ฟิลด์ที่เกี่ยวข้องในพื้นที่เก็บข้อมูลด้วยฟิลด์ของคุณเอง (โทเค็น ชื่อของตารางในเอนทิตี webHookPath ชื่อผู้ใช้ รหัสผ่าน และเส้นทางไปยังฐานข้อมูล ซึ่งทั้งหมดนี้จะถูกแยกวิเคราะห์) • ทำให้ Heroku ทำงานได้ 24/ 7 โดยใช้https:/ /uptimerobot.com/ โครงสร้างสุดท้ายของโครงการมีดังนี้: เริ่มต้นด้วยการสร้างโครงการในhttps://start.spring.ioเลือกการพึ่งพาที่เราต้องการดังแสดงในรูป: เลือกของเราเอง ชื่อโครงการแล้วคลิกสร้าง ถัดไปคุณจะได้รับแจ้งให้บันทึกโครงการลงในดิสก์ของคุณ สิ่งที่เหลืออยู่คือการเปิด ไฟล์pom.xm l จากสภาพแวดล้อมการพัฒนาของคุณ มีโครงการที่เสร็จแล้วอยู่ตรงหน้าคุณ ตอนนี้เราเพียงแค่ต้องเพิ่มห้องสมุดหลักของเรา ฉันใช้ไลบรารีจากhttps://github.com/rubenlags/TelegramBots โดยทั่วไปแล้วคุณอาจสับสนและทำไม่ได้ ท้ายที่สุดแล้ว ประเด็นทั้งหมดของงานคือการต่อ URL แบบนี้: https://api.telegram.org/bot1866835969:AAE6gJG6ptUyqhV2XX0MxyUak4QbAGGnz10/setWebhook?url=https://e9c658b548aa.ngrok.io ลองดูกันสักหน่อย : https://api.telegram.org – เซิร์ฟเวอร์โทรเลข bot1866835969:AAE6gJG6ptUyqhV2XX0MxyUak4QbAGGnz10/ - หลังคำว่า bot เป็นโทเค็นลับที่คุณได้รับเมื่อลงทะเบียนบอท setWebhook?url=https://e9c658b548aa.ngrok.io – ชื่อของวิธีการและพารามิเตอร์ ในกรณีนี้ เราติดตั้งเซิร์ฟเวอร์ webhook ของคุณ ข้อความทั้งหมดจะถูกส่งไปยังเซิร์ฟเวอร์นั้น โดยทั่วไป ฉันตัดสินใจว่าโปรเจ็กต์นี้ไม่เล็กเกินไปสำหรับการเผยแพร่ แต่เมื่อใช้งานด้วยตนเอง โดยทั่วไปแล้วจะไม่สามารถอ่านได้ ดังนั้นลักษณะสุดท้ายของ ไฟล์ pomคือ:
<!--?xml version="1.0" encoding="UTF-8"?-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelversion>4.0.0</modelversion>
<parent>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-parent</artifactid>
<version>2.5.0</version>
<relativepath> <!-- lookup parent from repository -->
</relativepath></parent>
<groupid>ru.popov</groupid>
<artifactid>telegrambot</artifactid>
<version>0.0.1-SNAPSHOT</version>
<name>telegrambot</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-web</artifactid>
</dependency>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-data-jpa</artifactid>
</dependency>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-test</artifactid>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.telegram/telegrambots-spring-boot-starter -->
<dependency>
<groupid>org.telegram</groupid>
<artifactid>telegrambots-spring-boot-starter</artifactid>
<version>5.2.0</version>
</dependency>
<dependency>
<groupid>org.projectlombok</groupid>
<artifactid>lombok</artifactid>
<version>1.18.16</version>
</dependency>
<dependency>
<groupid>org.postgresql</groupid>
<artifactid>postgresql</artifactid>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-maven-plugin</artifactid>
</plugin>
</plugins>
</build>
</project>
ทุกอย่างพร้อมที่จะเขียนบอทของเราแล้ว มาสร้าง คลาสTelegramBotกัน ฉันจะไม่เขียนชื่อโฟลเดอร์ คุณสามารถดูได้ในโครงสร้างโปรเจ็กต์ด้านบน
@Getter
@Setter
@FieldDefaults(level = AccessLevel.PRIVATE)
public class TelegramBot extends SpringWebhookBot {
String botPath;
String botUsername;
String botToken;
private TelegramFacade telegramFacade;
public TelegramBot(TelegramFacade telegramFacade, DefaultBotOptions options, SetWebhook setWebhook) {
super(options, setWebhook);
this.telegramFacade = telegramFacade;
}
public TelegramBot(TelegramFacade telegramFacade, SetWebhook setWebhook) {
super(setWebhook);
this.telegramFacade = telegramFacade;
}
@Override
public BotApiMethod<!--?--> onWebhookUpdateReceived(Update update) {
return telegramFacade.handleUpdate(update);
}
}
คลาสขยายSpringWebhookBot จากไลบรารีโทรเลข ของเรา และเราจำเป็นต้องใช้เพียงวิธีเดียวเท่านั้นonWebhookUpdateReceived ยอมรับJSON ที่แยกวิเคราะห์ เป็นวัตถุอัปเดตและส่งคืนสิ่งที่เซิร์ฟเวอร์โทรเลขต้องการ "ได้ยิน" จากเรา เรามีคำอธิบายประกอบจาก ห้องสมุด ลอมบอก ที่ นี่ ลอมบอก – ทำให้ชีวิตของโปรแกรมเมอร์ง่ายขึ้น!! นั่นคือ เราไม่จำเป็นต้องกำหนด getters และ setters ใหม่ ลอมบอกทำสิ่งนี้ให้เรา และเราไม่จำเป็นต้องเขียนตัวระบุระดับการเข้าถึงด้วย ไม่ควรเขียนอีกต่อไปว่าสิ่งนี้เสร็จสิ้นโดยคำอธิบายประกอบ@Getter, @Setter, @FieldDefaults ฟิลด์botPathหมายถึงที่อยู่ webhook ของเรา ซึ่งเราจะได้รับจาก Heroku ในภายหลัง ช่องbotUsernameหมายถึงชื่อของบอทของเรา ซึ่งเราจะได้รับเมื่อลงทะเบียนบอทของเราใน Telegram ช่องbotTokenคือโทเค็นของเรา ซึ่งเราจะได้รับเมื่อลงทะเบียนบอทของเราใน Telegram ฟิลด์telegramFacadeเป็นคลาสของเราที่การประมวลผลข้อความจะเกิดขึ้น เราจะกลับมาดูในภายหลัง ปล่อยให้เป็นสีแดงในตอนนี้ ตอนนี้ถึงเวลาที่เราจะติดต่อ@BotFatherและรับ botToken และ botUsername ที่เป็นที่ต้องการ แค่เขียนถึงเขาทางโทรเลขแล้วเขาจะบอกคุณทุกอย่าง เราเขียนข้อมูลลงใน application.properties ของเรา ในที่สุดก็จะมีลักษณะดังนี้:
server#server.port=5000
telegrambot.userName=@calendar_event_bot
telegrambot.botToken=1731265488:AAFDjUSk3vu5SFfgdfh556gOOFmuml7SqEjwrmnEF5Ak
#telegrambot.webHookPath=https://telegrambotsimpl.herokuapp.com/
telegrambot.webHookPath=https://f5d6beeb7b93.ngrok.io
telegrambot.adminId=39376213
eventservice.period =600000
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/telegramUsers
spring.datasource.username=postgres
spring.datasource.password=password
#spring.datasource.url=jdbc:postgresql:ec2-54-247-158-179.eu-west-1.compute.amazonaws.com:5432/d2um126le5notq?ssl=true&sslmode=require&sslfactory=org.postgresql.ssl.NonValidatingFactory
#spring.datasource.username=ulmbeywyhvsxa
#spring.datasource.password=4c7646c69dbbgeacb98fa96e8daa6d9b1bl4894e67f3f3ddd6a27fe7b0537fd
การกำหนดค่านี้ได้รับการกำหนดค่าให้ทำงานกับฐานข้อมูลท้องถิ่น หลังจากนั้นเราจะทำการเปลี่ยนแปลงที่จำเป็นในภายหลัง แทนที่botTokenและชื่อผู้ใช้ด้วยชื่อผู้ใช้ของคุณเอง การใช้ข้อมูลจาก application.properties โดยตรงในแอปพลิเคชันนั้นไม่ดี มาสร้าง bean หรือคลาส wrapper จากข้อมูลนี้กันดีกว่า
@Component
@Getter
@FieldDefaults(level = AccessLevel.PRIVATE)
public class TelegramBotConfig {
@Value("${telegrambot.webHookPath}")
String webHookPath;
@Value("${telegrambot.userName}")
String userName;
@Value("${telegrambot.botToken}")
String botToken;
ที่นี่คำอธิบายประกอบ @Value จะเริ่มต้นบรรทัดที่เกี่ยวข้องจากไฟล์ application.properties ซึ่ง Spring รู้ตามค่าเริ่มต้น และคำอธิบายประกอบ @Component จะสร้าง Bean ให้เราเมื่อแอปพลิเคชันเริ่มทำงาน ตอนนี้เรามาดูไฟล์คอนฟิกูเรชันของ Spring:
@Configuration
public class AppConfig {
private final TelegramBotConfig botConfig;
public AppConfig(TelegramBotConfig botConfig) {
this.botConfig = botConfig;
}
@Bean
public SetWebhook setWebhookInstance() {
return SetWebhook.builder().url(botConfig.getWebHookPath()).build();
}
@Bean
public TelegramBot springWebhookBot(SetWebhook setWebhook, TelegramFacade telegramFacade) {
TelegramBot bot = new TelegramBot(telegramFacade, setWebhook);
bot.setBotToken(botConfig.getBotToken());
bot.setBotUsername(botConfig.getUserName());
bot.setBotPath(botConfig.getWebHookPath());
return bot;
}
}
ไม่มีเวทย์มนตร์ที่นี่ เมื่อเริ่มต้น Spring จะสร้างวัตถุ SetWebhook และ TelegramBot ให้เรา ตอนนี้เรามาสร้างจุดเริ่มต้นสำหรับข้อความของเรา:
@RestController
public class WebhookController {
private final TelegramBot telegramBot;
public WebhookController(TelegramBot telegramBot) {
this.telegramBot = telegramBot;
}
// point for message
@PostMapping("/")
public BotApiMethod<!--?--> onUpdateReceived(@RequestBody Update update) {
return telegramBot.onWebhookUpdateReceived(update);
}
@GetMapping
public ResponseEntity get() {
return ResponseEntity.ok().build();
}
}
เซิร์ฟเวอร์ Telegram ส่งข้อความในรูปแบบ JSON ไปยังที่อยู่ webhook ที่ลงทะเบียนไว้โดยใช้วิธี POST ตัวควบคุมของเราจะรับข้อความเหล่านั้นและส่งไปยังไลบรารีโทรเลขในรูปแบบของวัตถุอัปเดต ฉันทำวิธี get แบบนั้น) ตอนนี้เราแค่ต้องใช้ตรรกะบางอย่างสำหรับการประมวลผลข้อความและการตอบกลับใน คลาส TelegramFacadeฉันจะให้โค้ดสั้น ๆ เพื่อให้คุณสามารถเปิดแอปพลิเคชันแล้วไปตามทางของคุณเองหรือเปลี่ยนไปปรับใช้ บน Heroku มันจะเป็นเวอร์ชันเต็ม:
@Component
@FieldDefaults(level = AccessLevel.PRIVATE)
public class TelegramFacade {
public BotApiMethod<!--?--> handleUpdate(Update update) {
if (update.hasCallbackQuery()) {
CallbackQuery callbackQuery = update.getCallbackQuery();
return null;
} else {
Message message = update.getMessage();
SendMessage sendMessage = new SendMessage();
sendMessage.setChatId(String.valueOf(message.getChatId()));
if (message.hasText()) {
sendMessage.setText("Hello world");
return sendMessage;
}
}
return null;
}
}
วิธีนี้จะตอบสนองต่อ Hello world! ในการเปิดตัวแอปพลิเคชันของเรา เราเพียงแค่ต้องแน่ใจว่าเราสามารถทดสอบแอปพลิเคชันของเราได้โดยตรงจาก IDEA ในการดำเนินการนี้ เราจำเป็นต้องดาวน์โหลดยูทิลิตี้ ngrok https://ngrok.com/download ยูทิลิตี้นี้เป็นบรรทัดคำสั่งที่ให้ที่อยู่ชั่วคราวแก่เราเป็นเวลา 2 ชั่วโมงและเปลี่ยนเส้นทางข้อความทั้งหมดไปยังพอร์ตที่ระบุของเซิร์ฟเวอร์ท้องถิ่น เราเปิดตัวและเขียน ngrok http 5000ในบรรทัด(หรือคุณสามารถระบุพอร์ตของคุณได้): เราได้รับผลลัพธ์: https://23b1a54ccbbd.ngrok.io - นี่คือที่อยู่ webhook ของเรา ดังที่คุณอาจสังเกตเห็นในไฟล์คุณสมบัติที่เราเขียน server.port=5000 เมื่อเริ่มต้นเซิร์ฟเวอร์ Tomcat ไฟล์นั้นจะครอบครองพอร์ต 5000 ตรวจสอบให้แน่ใจว่าฟิลด์เหล่านี้เหมือนกัน อย่าลืมว่าที่อยู่นั้นให้ไว้เป็นเวลาสองชั่วโมง บนบรรทัดคำสั่ง ข้อมูลนี้จะถูกตรวจสอบโดยฟิลด์ Session Expires เมื่อหมดเวลา คุณจะต้องได้รับที่อยู่อีกครั้งและทำตามขั้นตอนการลงทะเบียนทางโทรเลข ตอนนี้เราใช้บรรทัด https://api.telegram.org/bot1866835969:AAE6gJG6ptUyqhV2XX0MxyUak4QbAGGnz10/setWebhook?url=https://e9c658b548aa.ngrok.io และด้วยการเคลื่อนไหวของมือที่คล่องแคล่วเราจะแทนที่โทเค็นด้วยของเรา, url ของเรา, วาง บรรทัดผลลัพธ์ลงในเบราว์เซอร์แล้วคลิก Enter คุณควรได้รับผลลัพธ์ดังต่อ ไปนี้: เพียงเท่านี้ คุณก็สามารถรันแอปพลิเคชันได้แล้ว: ตรวจสอบว่าคลาสของคุณที่มี เมธอด หลักเป็นดังนี้:
@SpringBootApplication
public class TelegramBotApplication {
public static void main(String[] args) {
SpringApplication.run(TelegramBotApplication.class, args);
}
}
หากคุณทำทุกอย่างถูกต้อง ตอน นี้ บอทของคุณจะตอบสนองต่อข้อความที่มีวลี “ สวัสดีชาวโลก” จากนั้นคุณก็ไปตามทางของคุณเองได้ หากคุณอยู่กับฉันและสนใจที่จะทำตามขั้นตอนทั้งหมด เรามาเริ่มเขียนเอนทิตีสำหรับฐานข้อมูลและสร้างฐานข้อมูลกันดีกว่า เริ่มจากฐานข้อมูลกันก่อน ดังที่ฉันได้กล่าวไปแล้ว ฉันคิดว่าคุณมีทักษะขั้นต่ำในการทำงานกับฐานข้อมูลอยู่แล้ว และคุณได้ ติดตั้งฐานข้อมูล postgreSQL ในเครื่องแล้ว หากไม่มี ให้ทำตามเส้นทางนี้ https://www.postgresql.org/download/ ในไฟล์ application.properties ให้แทนที่ข้อมูลเข้าสู่ระบบฐานข้อมูลและรหัสผ่านของคุณเอง ใน IDEA มีแท็บฐานข้อมูลทางด้านขวา คุณต้องคลิกที่+/Data source/ PostgreSQL ด้วยเหตุนี้ เมื่อคุณคลิกที่ทดสอบการเชื่อมต่อคุณควรได้รับผลลัพธ์ที่น่าพอใจ: ตอนนี้คุณสามารถสร้างฐานข้อมูลพร้อมตารางได้โดยตรงจากสภาพแวดล้อมการพัฒนา หรือคุณสามารถใช้ อินเทอร์เฟซเว็บ pgadminซึ่งอยู่ในเมนูเริ่ม เราจะต้องมี 3 ตาราง:
CREATE TABLE users
(
id INTEGER PRIMARY KEY UNIQUE NOT NULL,
name VARCHAR,
time_zone INTEGER DEFAULT 0,
on_off BOOLEAN DEFAULT true
);
CREATE TABLE user_events
(
user_id INTEGER ,
time timestamp ,
description varchar ,
event_id serial,
event_freq varchar default 'TIME',
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
);
CREATE TABLE event_cash
(
time timestamp ,
description varchar ,
user_id INTEGER ,
id serial
);
ฉันแนะนำให้สร้างสคริปต์นี้แยกกัน เราจะต้องสร้างฐานข้อมูลบน Heroku เพื่อไม่ให้เขียนซ้ำสองครั้ง มาเดินเล่นกันหน่อย ฉันจะบอกทันทีว่าเราต้องการเพียง ตารางevent_cashเพื่อทำงานกับ Heroku เนื่องจากข้อมูลเฉพาะและความปรารถนาอันแรงกล้าของฉันที่จะทำงานกับ คลาส Timeมันจะไม่มีประโยชน์ในเวอร์ชันท้องถิ่น ใน ตาราง ผู้ใช้เราจะบันทึกIDของบัญชีผู้ใช้โทรเลข ชื่อของเขาซึ่งอาจไม่มีอยู่ เขตเวลาของผู้ใช้จะถูกคำนวณสำหรับการส่งการแจ้งเตือนที่ถูกต้อง รวมถึงสถานะเปิด/ปิดของการส่งการแจ้งเตือน เราจะบันทึกID ผู้ใช้ เวลาแจ้งเตือน คำอธิบาย ใน ตาราง user_eventsสร้างIDสำหรับกิจกรรมโดยอัตโนมัติ และตั้งค่าความถี่ของการแจ้งเตือน ตารางevent_cashจะบันทึกการแจ้งเตือนก่อนที่จะส่ง และหากส่งแล้ว ก็จะลบออกจากตาราง ตารางพร้อมแล้ว มาเพิ่มเอนทิตีกันดีกว่า
@Entity
@Table(name = "user_events")
@Getter
@Setter
public class Event {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column( name = "event_id", columnDefinition = "serial")
private int eventId;
@Column(name = "time")
@NotNull(message = "Need date!")
private Date date;
@Column(name = "description")
@Size(min = 4, max = 200, message = "Description must be between 0 and 200 chars!")
private String description;
@Column(name = "event_freq", columnDefinition = "TIME")
@Enumerated(EnumType.STRING)
private EventFreq freq;
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="user_id")
@OnDelete(action = OnDeleteAction.CASCADE)
private User user;
public Event() {
}
public Event(int eventId,
@NotNull(message = "Need date!") Date date,
@Size(min = 4, max = 200, message = "Description must be between 0 and 200 chars!")
String description,
EventFreq freq, User user) {
this.eventId = eventId;
this.date = date;
this.description = description;
this.freq = freq;
this.user = user;
}
}
@Entity
@Table(name = "users")
@Getter
@Setter
public class User {
@Id
@Column(name = "id")
private long id;
@Column(name = "name")
private String name;
@Column(name = "time_zone", columnDefinition = "default 0")
//sets the broadcast time of events for your time zone
private int timeZone;
@OneToMany(mappedBy="user")
private List<event> events;
@Column(name = "on_off")
// on/off send event
private boolean on;
public User() {
}
}
</event>
@Entity
@Table(name = "event_cash")
@Getter
@Setter
//serves to save unhandled events after rebooting heroku
public class EventCashEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column( name = "id", columnDefinition = "serial")
private long id;
@Column(name = "time")
private Date date;
@Column(name = "description")
private String description;
@Column(name = "user_id")
private long userId;
public EventCashEntity() {
}
public static EventCashEntity eventTo(Date date, String description, long userId) {
EventCashEntity eventCashEntity = new EventCashEntity();
eventCashEntity.setDate(date);
eventCashEntity.setDescription(description);
eventCashEntity.setUserId(userId);
return eventCashEntity;
}
}
มาดูประเด็นหลักกันสักหน่อย @Entity – ทำเครื่องหมายคลาสสำหรับ dada jpa ของเราว่าคลาสนี้เป็นเอนทิตีสำหรับฐานข้อมูล เช่น เมื่อดึงข้อมูลจากฐานข้อมูล มันจะถูกนำเสนอแก่เราในรูปแบบของออบเจ็กต์เหตุการณ์ ผู้ใช้ และ EventCashEntity @Table – เราพูดชื่อตารางของเราในฐานข้อมูล เพื่อให้แน่ใจว่าชื่อตารางไม่ได้ขีดเส้นใต้ด้วยสีแดง เราจำเป็นต้องยอมรับตัวเลือกการแก้ไขข้อผิดพลาดที่เสนอใน IDEA แล้วคลิกกำหนดแหล่งข้อมูล และเลือกฐานของเราที่นั่น @id และ @GeneratedValue - ใช้โดย Spring เพื่อสร้างฐานข้อมูลหากไม่มีอยู่ @Columnใช้เพื่อระบุชื่อของเขตข้อมูลในตารางหากไม่ตรงกัน แต่กฎของโค้ดที่ดีขอแนะนำให้คุณเขียนสิ่งนี้เสมอ ทัศนคติของ OneToMany - ฉันขอแนะนำให้ใช้เวลาและค้นหาว่ามันคืออะไรที่นี่ https://en.wikibooks.org/wiki/Java_Persistence ฉันไม่สามารถอธิบายให้ชัดเจนกว่านี้ได้ แค่เชื่อฉัน ฉันขอบอกว่าในกรณีนี้ คำอธิบายประกอบ @OneToManyบอกว่าผู้ใช้หนึ่งคนสามารถมีกิจกรรมได้มากมาย และพวกเขาจะจัดเตรียมไว้ให้เราในรูปแบบของรายการ ตอนนี้เราจำเป็นต้องได้รับข้อมูลจากตาราง ใน ไลบรารี SRING DATA JPAทุกอย่างถูกเขียนสำหรับเราแล้ว เราเพียงแค่ต้องสร้างอินเทอร์เฟซสำหรับแต่ละตารางและขยายจาก JpaRepository
public interface EventRepository extends JpaRepository<event, long=""> {
Event findByEventId(long id);
}
public interface UserRepository extends JpaRepository<user, long=""> {
User findById(long id);
}
public interface EventCashRepository extends JpaRepository<eventcashentity, long=""> {
EventCashEntity findById(long id);
}
</eventcashentity,></user,></event,>
ตรรกะหลักสำหรับการทำงานกับฐานข้อมูลจะถูกถ่ายโอนไปยังบริการที่เรียกว่าData Access Object (DAO):
@Service
public class UserDAO {
private final UserRepository userRepository;
@Autowired
public UserDAO(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User findByUserId(long id) {
return userRepository.findById(id);
}
public List<user> findAllUsers() {
return userRepository.findAll();
}
public void removeUser(User user) {
userRepository.delete(user);
}
public void save(User user) {
userRepository.save(user);
}
public boolean isExist(long id) {
User user = findByUserId(id);
return user != null;
}
}
@Service
public class EventDAO {
private final UserRepository userRepository;
private final EventRepository eventRepository;
@Autowired
public EventDAO(UserRepository userRepository, EventRepository eventRepository) {
this.userRepository = userRepository;
this.eventRepository = eventRepository;
}
public List<event> findByUserId(long userId) {
User user = userRepository.findById(userId);
return user.getEvents();
}
public List<event> findAllEvent() {
return eventRepository.findAll();
}
public Event findByEventId(long eventId) {
return eventRepository.findByEventId(eventId);
}
public void remove(Event event) {
eventRepository.delete(event);
}
public void save(Event event) {
eventRepository.save(event);
}
}
</event></event></user>
@Service
//handles events not dispatched after reboot heroku
public class EventCashDAO {
private EventCashRepository eventCashRepository;
@Autowired
public void setEventCashRepository(EventCashRepository eventCashRepository) {
this.eventCashRepository = eventCashRepository;
}
public List<eventcashentity> findAllEventCash() {
return eventCashRepository.findAll();
}
public void save(EventCashEntity eventCashEntity) {
eventCashRepository.save(eventCashEntity);
}
public void delete(long id) {
eventCashRepository.deleteById(id);
}
}
</eventcashentity>
ในกรณีนี้ เราไม่มีการประมวลผลข้อมูล เราเพียงแค่ดึงข้อมูลจากตารางเท่านั้น เราทุกคนพร้อมที่จะจัดเตรียมโค้ดที่สมบูรณ์ของคลาส T elegramFacadeและเริ่มวิเคราะห์ตรรกะ
@Component
@FieldDefaults(level = AccessLevel.PRIVATE)
public class TelegramFacade {
final MessageHandler messageHandler;
final CallbackQueryHandler callbackQueryHandler;
final BotStateCash botStateCash;
@Value("${telegrambot.adminId}")
int adminId;
public TelegramFacade(MessageHandler messageHandler, CallbackQueryHandler callbackQueryHandler, BotStateCash botStateCash) {
this.messageHandler = messageHandler;
this.callbackQueryHandler = callbackQueryHandler;
this.botStateCash = botStateCash;
}
public BotApiMethod<!--?--> handleUpdate(Update update) {
if (update.hasCallbackQuery()) {
CallbackQuery callbackQuery = update.getCallbackQuery();
return callbackQueryHandler.processCallbackQuery(callbackQuery);
} else {
Message message = update.getMessage();
if (message != null && message.hasText()) {
return handleInputMessage(message);
}
}
return null;
}
private BotApiMethod<!--?--> handleInputMessage(Message message) {
BotState botState;
String inputMsg = message.getText();
//we process messages of the main menu and any other messages
//set state
switch (inputMsg) {
case "/start":
botState = BotState.START;
break;
case "Мои напоминания":
botState = BotState.MYEVENTS;
break;
case "Создать напоминание":
botState = BotState.CREATE;
break;
case "Отключить напоминания":
case "Включить напоминания":
botState = BotState.ONEVENT;
break;
case "All users":
if (message.getFrom().getId() == adminId)
botState = BotState.ALLUSERS;
else botState = BotState.START;
break;
case "All events":
if (message.getFrom().getId() == adminId)
botState = BotState.ALLEVENTS;
else botState = BotState.START;
break;
default:
botState = botStateCash.getBotStateMap().get(message.getFrom().getId()) == null?
BotState.START: botStateCash.getBotStateMap().get(message.getFrom().getId());
}
//we pass the corresponding state to the handler
//the corresponding method will be called
return messageHandler.handle(message, botState);
}
}
มาดูกันว่าฟิลด์ใดที่จำเป็นสำหรับ
final MessageHandler messageHandler;
final CallbackQueryHandler callbackQueryHandler;
final BotStateCash botStateCash;
หากเราทุกคนเขียนโค้ดในคลาสเดียว เราก็จะลงเอยด้วยผ้าเช็ดเท้าไปดวงจันทร์ ดังนั้นเราจึงกำหนดตรรกะสำหรับการทำงานกับข้อความตัวอักษรให้กับคลาส MessageHandler และกำหนดตรรกะสำหรับการทำงานกับข้อความ callbackquery ให้กับคลาสCallbackQueryHandler ถึงเวลาที่จะรู้ว่าallbackquery คืออะไร และมีเมนูประเภทใดบ้าง ในการดำเนินการนี้ ฉันจะให้รูปภาพอินเทอร์เฟซของบอทอีกรูปแก่คุณ: มีเมนูสองประเภท สิ่งที่แนบมาที่ด้านล่างของหน้าต่าง - เมนูหลักและสิ่งที่แนบมากับข้อความเช่นปุ่มสำหรับลบแก้ไขเปลี่ยนสายพาน เมื่อคุณคลิกที่ปุ่มเมนูหลัก ข้อความที่มีชื่อเดียวกันจะถูกส่งไป ตัวอย่างเช่น เมื่อคุณคลิก"การเตือนความจำของฉัน"ข้อความ"การแจ้งเตือนของฉัน"จะถูกส่งไป และเมื่อติดตั้งคีย์บอร์ด callbackquery ค่าเฉพาะจะถูกตั้งค่าสำหรับแต่ละปุ่ม และค่าของมันจะถูกส่งโดยไม่แสดงบนหน้าจอ ต่อไปเราจะมีฟิลด์BotStateCash นี่คือคลาสที่สร้างขึ้นเป็นพิเศษที่จะตรวจสอบสถานะของบอท และความสนใจ นี่เป็นองค์ประกอบที่ซับซ้อน คุณต้องเครียด เกินจำนวนอักขระซึ่งไม่ได้เขียนไว้ที่ใดเลย)) นี่คือลิงค์ไปยังส่วนที่สอง
GO TO FULL VERSION