ส่วนที่สองของโครงการ - นี่คือลิงก์ไปยังส่วนแรก: ดังนั้น คลาส BotState : เพื่อให้บอทของเราเข้าใจสิ่งที่คาดหวัง ณ จุดใดจุดหนึ่ง เช่น การลบการแจ้งเตือน เราจำเป็นต้อง แจ้งให้บอทของเราทราบว่าหมายเลขที่ป้อนและส่งตอนนี้ควรถือเป็นรหัสเตือนความจำจากรายการและควรลบออก ดังนั้น หลังจากคลิกที่ ปุ่ม "ลบ"บอทจะเข้าสู่ สถานะ BotState.ENTERNUMBEREVENTนี่คือคลาส Enum ที่สร้างขึ้นเป็นพิเศษพร้อมสถานะบอท
public enum BotState {
ENTERDESCRIPTION,//the bot will wait for the description to be entered.
START,
MYEVENTS, //the bot show to user list events.
ENTERNUMBEREVENT,//the bot will wait for the number of event to be entered.
ENTERDATE, //the bot will wait for the date to be entered
CREATE, //the bot run created event
ENTERNUMBERFOREDIT, //the bot will wait for the number of event to be entered
EDITDATE, //the bot will wait for the date to be entered
EDITDESCRIPTION,//the bot will wait for the description to be entered
EDITFREQ,//the bot will wait callbackquery
ALLUSERS, // show all users
ALLEVENTS, //show all events
ENTERNUMBERUSER,//the bot will wait for the number of user to be entered.
ENTERTIME,//the bot will wait for the hour to be entered.
ONEVENT // state toggle
}
และตอนนี้เราคาดว่าจะป้อนตัวเลข - “ ป้อนหมายเลขเตือนความจำจากรายการ ” หลังจากกรอกแล้วจะเข้าสู่วิธีการประมวลผลที่ต้องการ นี่คือสวิตช์สถานะของเรา:
public class BotStateCash {
private final Map<long, botstate=""> botStateMap = new HashMap<>();
public void saveBotState(long userId, BotState botState) {
botStateMap.put(userId, botState);
}
}
</long,>
แผนที่ปกติพร้อม ID ผู้ใช้และสถานะ ช่องint adminIdมีไว้สำหรับฉัน) ต่อไป ตรรกะของ เมธอด handleUpdateจะตรวจสอบว่าข้อความนี้เป็นข้อความประเภทใด Callbackqueryหรือเพียงแค่ส่งข้อความ? หากนี่เป็นข้อความปกติ เราจะไปที่ เมธอด handleInputMessageโดยที่เราประมวลผลปุ่มเมนูหลัก และหากปุ่มเหล่านั้นถูกคลิก เราก็จะตั้งค่าสถานะที่ต้องการ แต่ถ้าพวกเขาไม่ได้คลิกและนี่เป็นข้อความที่ไม่คุ้นเคย เราก็จะตั้งค่าสถานะนั้น ตั้งค่าสถานะจากแคช หากไม่มีเราจะตั้งค่าสถานะเริ่มต้น จากนั้นข้อความจะเข้าสู่การประมวลผลวิธีจัดการตามสถานะที่เราต้องการ ตอนนี้เรานำเสนอตรรกะของ คลาส MessageHandlerซึ่งมีหน้าที่ในการประมวลผลข้อความขึ้นอยู่กับสถานะของบอท:
public class MessageHandler {
private final UserDAO userDAO;
private final MenuService menuService;
private final EventHandler eventHandler;
private final BotStateCash botStateCash;
private final EventCash eventCash;
public MessageHandler(UserDAO userDAO, MenuService menuService, EventHandler eventHandler, BotStateCash botStateCash, EventCash eventCash) {
this.userDAO = userDAO;
this.menuService = menuService;
this.eventHandler = eventHandler;
this.botStateCash = botStateCash;
this.eventCash = eventCash;
}
public BotApiMethod<!--?--> handle(Message message, BotState botState) {
long userId = message.getFrom().getId();
long chatId = message.getChatId();
SendMessage sendMessage = new SendMessage();
sendMessage.setChatId(String.valueOf(chatId));
//if new user
if (!userDAO.isExist(userId)) {
return eventHandler.saveNewUser(message, userId, sendMessage);
}
//save state in to cache
botStateCash.saveBotState(userId, botState);
//if state =...
switch (botState.name()) {
case ("START"):
return menuService.getMainMenuMessage(message.getChatId(),
"Воспользуйтесь главным меню", userId);
case ("ENTERTIME"):
//set time zone user. for correct sent event
return eventHandler.enterLocalTimeUser(message);
case ("MYEVENTS"):
//list events of user
return eventHandler.myEventHandler(userId);
case ("ENTERNUMBEREVENT"):
//remove event
return eventHandler.removeEventHandler(message, userId);
case ("ENTERDESCRIPTION"):
//enter description for create event
return eventHandler.enterDescriptionHandler(message, userId);
case ("ENTERDATE"):
//enter date for create event
return eventHandler.enterDateHandler(message, userId);
case ("CREATE"):
//start create event, set state to next step
botStateCash.saveBotState(userId, BotState.ENTERDESCRIPTION);
//set new event to cache
eventCash.saveEventCash(userId, new Event());
sendMessage.setText("Введите описание события");
return sendMessage;
case ("ENTERNUMBERFOREDIT"):
//show to user selected event
return eventHandler.editHandler(message, userId);
case ("EDITDESCRIPTION"):
//save new description in database
return eventHandler.editDescription(message);
case ("EDITDATE"):
//save new date in database
return eventHandler.editDate(message);
case ("ALLEVENTS"):
//only admin
return eventHandler.allEvents(userId);
case ("ALLUSERS"):
//only admin
return eventHandler.allUsers(userId);
case ("ONEVENT"):
// on/off notification
return eventHandler.onEvent(message);
case ("ENTERNUMBERUSER"):
//only admin
return eventHandler.removeUserHandler(message, userId);
default:
throw new IllegalStateException("Unexpected value: " + botState);
}
}
}
ในเมธอด handle เราจะตรวจสอบสถานะของข้อความที่เราได้รับและส่งไปยังตัวจัดการเหตุการณ์ - คลาส EventHandler เรามีคลาสใหม่สองคลาสMenuService และ EventCash MenuService – ที่นี่เราสร้างเมนูทั้งหมดของเรา EventCash - คล้ายกับBotStateCashโดยจะบันทึกบางส่วนของกิจกรรมของเราหลังจากป้อนข้อมูล และเมื่อป้อนข้อมูลเสร็จสิ้น เราจะบันทึกกิจกรรมในฐานข้อมูล
@Service
@Setter
@Getter
// used to save entered event data per session
public class EventCash {
private final Map<long, event=""> eventMap = new HashMap<>();
public void saveEventCash(long userId, Event event) {
eventMap.put(userId, event);
}
}
</long,>
นั่นคือ เมื่อเราสร้างเหตุการณ์ ออบเจ็กต์เหตุการณ์ใหม่จะถูกสร้างขึ้นในแคช -eventCash.saveEventCash(userId, new Event()); จากนั้นเราป้อนคำอธิบายของเหตุการณ์และเพิ่มลงในแคช:
Event event = eventCash.getEventMap().get(userId);
event.setDescription(description);
//save to cache
eventCash.saveEventCash(userId, event);
จากนั้นป้อนหมายเลข:
Event event = eventCash.getEventMap().get(userId);
event.setDate(date);
//save data to cache
eventCash.saveEventCash(userId, event);
คลาส CallbackQueryHandler คล้ายกับMessageHandlerมีเพียงเราเท่านั้นที่ประมวลผลข้อความ callbackquery ที่นั่น ไม่มีเหตุผล ที่จะวิเคราะห์ตรรกะของการทำงานกับเหตุการณ์อย่างสมบูรณ์ - EventHandlerมีตัวอักษรมากเกินไปอยู่แล้วชัดเจนจากชื่อของวิธีการและความคิดเห็นในโค้ด และผมไม่เห็นประเด็นที่ต้องจัดเป็นข้อความให้หมดเลย มีมากกว่า 300 บรรทัด นี่คือลิงค์ไปยังชั้นเรียนบนGithub เช่นเดียวกับ คลาส MenuServiceที่เราสร้างเมนูของเรา คุณสามารถอ่านรายละเอียดเกี่ยวกับพวกเขาได้บนเว็บไซต์ของผู้ผลิตห้องสมุดโทรเลข - https://github.com/rubenlags/TelegramBots/blob/master/TelegramBots.wiki/FAQ.md หรือในหนังสืออ้างอิง Telegram - https:// tlgrm.ru/docs/bots /api ตอนนี้เราเหลือส่วนที่อร่อยที่สุดแล้ว นี่คือคลาสสำหรับจัดการ ข้อความ EventService :
@EnableScheduling
@Service
public class EventService {
private final EventDAO eventDAO;
private final EventCashDAO eventCashDAO;
@Autowired
public EventService(EventDAO eventDAO, EventCashDAO eventCashDAO) {
this.eventDAO = eventDAO;
this.eventCashDAO = eventCashDAO;
}
//start service in 0:00 every day
@Scheduled(cron = "0 0 0 * * *")
// @Scheduled(fixedRateString = "${eventservice.period}")
private void eventService() {
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
int day = calendar.get(Calendar.DAY_OF_MONTH);
int month = calendar.get(Calendar.MONTH);
int year = calendar.get(Calendar.YEAR);
//get event list is now date
List<event> list = eventDAO.findAllEvent().stream().filter(event -> {
if (event.getUser().isOn()) {
EventFreq eventFreq = event.getFreq();
//set user event time
Calendar calendarUserTime = getDateUserTimeZone(event);
int day1 = calendarUserTime.get(Calendar.DAY_OF_MONTH);
int month1 = calendarUserTime.get(Calendar.MONTH);
int year1 = calendarUserTime.get(Calendar.YEAR);
switch (eventFreq.name()) {
case "TIME": //if one time - remove event
if (day == day1 && month == month1 && year == year1) {
eventDAO.remove(event);
return true;
}
case "EVERYDAY":
return true;
case "MONTH":
if (day == day1) return true;
case "YEAR":
if (day == day1 && month == month1) return true;
default: return false;
}
} else return false;
}).collect(Collectors.toList());
for (Event event : list) {
//set user event time
Calendar calendarUserTime = getDateUserTimeZone(event);
int hour1 = calendarUserTime.get(Calendar.HOUR_OF_DAY);
calendarUserTime.set(year, month, day, hour1, 0, 0);
String description = event.getDescription();
String userId = String.valueOf(event.getUser().getId());
//save the event to the database in case the server reboots.
EventCashEntity eventCashEntity = EventCashEntity.eventTo(calendarUserTime.getTime(), event.getDescription(), event.getUser().getId());
eventCashDAO.save(eventCashEntity);
//create a thread for the upcoming event with the launch at a specific time
SendEvent sendEvent = new SendEvent();
sendEvent.setSendMessage(new SendMessage(userId, description));
sendEvent.setEventCashId(eventCashEntity.getId());
new Timer().schedule(new SimpleTask(sendEvent), calendarUserTime.getTime());
}
}
private Calendar getDateUserTimeZone(Event event) {
Calendar calendarUserTime = Calendar.getInstance();
calendarUserTime.setTime(event.getDate());
int timeZone = event.getUser().getTimeZone();
//set correct event time with user timezone
calendarUserTime.add(Calendar.HOUR_OF_DAY, -timeZone);
return calendarUserTime;
}
}
</event>
@EnableScheduling – เปิดใช้งานการทำงานตามกำหนดเวลาใน Spring @Scheduled(cron = "0 0 0 * * *") – เรากำหนดค่าวิธีการให้ทำงานเวลา 0:00 น. ทุกวัน Calendar.setTime(new Date()); - ตั้งเวลาเซิร์ฟเวอร์ เราได้รับรายการเตือนความจำสำหรับวันนี้ ผ่านทางความมหัศจรรย์ของลำธารและแลมบ์ดา เราผ่านรายการที่ได้รับตั้งเวลาส่งที่ถูกต้องCalendarUserTimeและ... นี่คือที่ฉันตัดสินใจหลบและเปิดกระบวนการล่าช้าตามเวลา คลาส Timeใน java รับผิดชอบสิ่งนี้ ตัวจับเวลาใหม่ (). กำหนดการ ( SimpleTask ใหม่ (sendEvent), ปฏิทิน UserTime.getTime ()); เพื่อที่เราจะต้องสร้างกระทู้:
public class SendEvent extends Thread {
private long eventCashId;
private SendMessage sendMessage;
public SendEvent() {
}
@SneakyThrows
@Override
public void run() {
TelegramBot telegramBot = ApplicationContextProvider.getApplicationContext().getBean(TelegramBot.class);
EventCashDAO eventCashDAO = ApplicationContextProvider.getApplicationContext().getBean(EventCashDAO.class);
telegramBot.execute(sendMessage);
//if event it worked, need to remove it from the database of unresolved events
eventCashDAO.delete(eventCashId);
}
}
และการใช้งานTimerTask
public class SimpleTask extends TimerTask {
private final SendEvent sendEvent;
public SimpleTask(SendEvent sendEvent) {
this.sendEvent = sendEvent;
}
@Override
public void run() {
sendEvent.start();
}
}
ใช่ฉันเข้าใจดีว่าคุณสามารถผ่านฐานข้อมูลทุก ๆ 20 นาทีและส่งข้อความ แต่ฉันเขียนทุกอย่างเกี่ยวกับเรื่องนี้ตั้งแต่เริ่มต้น)) ที่นี่เรายังพบกับความทุกข์ยากของ Heroku No. 1 สำหรับแผนแบบฟรี คุณจะได้รับไดโนจำนวน 550 ตัว ซึ่งเท่ากับชั่วโมงการทำงานของแอปพลิเคชันของคุณต่อเดือน นี่ไม่เพียงพอสำหรับการทำงานของแอปพลิเคชันทั้งเดือน แต่ถ้าคุณเชื่อมโยงการ์ด คุณจะได้รับดิโนอีก 450 ตัวซึ่งเพียงพอสำหรับดวงตาของคุณ หากคุณกังวลเกี่ยวกับบัตร คุณสามารถเชื่อมโยงบัตรเปล่าได้ แต่ตรวจสอบให้แน่ใจว่ามี $0.6... นี่คือจำนวนเงินในการยืนยัน เพียงแต่ต้องอยู่ในบัญชี ไม่มีค่าใช้จ่ายแอบแฝง เว้นแต่คุณจะเปลี่ยนอัตราภาษีด้วยตนเอง ในแผนบริการแบบฟรีมีปัญหาเล็กๆ อีกปัญหาหนึ่ง เรียกว่าหมายเลข 1a. พวกเขารีบูตเซิร์ฟเวอร์อย่างต่อเนื่องหรือเพียงแค่ส่งคำสั่งเพื่อรีสตาร์ทแอปพลิเคชัน โดยทั่วไปแล้วจะรีบูตทุกวันที่ไหนสักแห่งในเวลาเที่ยงคืนของมอสโกและในบางครั้ง ในเวลาอื่น จากนี้กระบวนการทั้งหมดของเราในหน่วยความจำจะถูกลบ เพื่อแก้ไขปัญหานี้ ฉันจึงสร้างตาราง EventCash ขึ้นมา ก่อนที่จะส่ง กิจกรรมจะถูกบันทึกในตารางแยกต่างหาก:
EventCashEntity eventCashEntity = EventCashEntity.eventTo(calendarUserTime.getTime(), event.getDescription(), event.getUser().getId());
eventCashDAO.save(eventCashEntity);
และหลังจากส่งแล้ว ข้อมูลต่อไปนี้จะถูกลบ:
@Override
public void run() {
TelegramBot telegramBot = ApplicationContextProvider.getApplicationContext().getBean(TelegramBot.class);
EventCashDAO eventCashDAO = ApplicationContextProvider.getApplicationContext().getBean(EventCashDAO.class);
telegramBot.execute(sendMessage);
//if event it worked, need to remove it from the database of unresolved events
eventCashDAO.delete(eventCashId);
}
ApplicationContextProviderเป็นคลาสพิเศษสำหรับรับบริบทได้ทันที:
@Component
//wrapper to receive Beans
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
public static ApplicationContext getApplicationContext() {
return context;
}
@Override
public void setApplicationContext(ApplicationContext ac)
throws BeansException {
context = ac;
}
}
เพื่อตรวจสอบเหตุการณ์ที่ยังไม่ได้ประมวลผล ฉันได้สร้างบริการพิเศษที่มีเมธอดที่ทำเครื่องหมายว่า@PostConstructซึ่งจะทำงานหลังจากแต่ละแอปพลิเคชันเริ่มทำงาน จะเลือกเหตุการณ์ที่ยังไม่ได้ประมวลผลทั้งหมดจากฐานข้อมูลและส่งกลับไปยังหน่วยความจำ นี่คือ Heroku ที่น่ารังเกียจสำหรับคุณ!
@Component
public class SendEventFromCache {
private final EventCashDAO eventCashDAO;
private final TelegramBot telegramBot;
@Value("${telegrambot.adminId}")
private int admin_id;
@Autowired
public SendEventFromCache(EventCashDAO eventCashDAO, TelegramBot telegramBot) {
this.eventCashDAO = eventCashDAO;
this.telegramBot = telegramBot;
}
@PostConstruct
@SneakyThrows
//after every restart app - check unspent events
private void afterStart() {
List<eventcashentity> list = eventCashDAO.findAllEventCash();
SendMessage sendMessage = new SendMessage();
sendMessage.setChatId(String.valueOf(admin_id));
sendMessage.setText("Произошла перезагрузка!");
telegramBot.execute(sendMessage);
if (!list.isEmpty()) {
for (EventCashEntity eventCashEntity : list) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(eventCashEntity.getDate());
SendEvent sendEvent = new SendEvent();
sendEvent.setSendMessage(new SendMessage(String.valueOf(eventCashEntity.getUserId()), eventCashEntity.getDescription()));
sendEvent.setEventCashId(eventCashEntity.getId());
new Timer().schedule(new SimpleTask(sendEvent), calendar.getTime());
}
}
}
}
</eventcashentity>
แอปพลิเคชันของเราพร้อมแล้ว และถึงเวลาที่เราจะได้รับที่อยู่ Heroku สำหรับแอปพลิเคชันและฐานข้อมูล ใบสมัครของคุณจะต้องเผยแพร่บน Github!!! ไปที่ Heroku.com คลิกสร้างแอปใหม่ป้อนชื่อแอปพลิเคชันของคุณ เลือกยุโรป สร้างแอป เพียงเท่านี้สถานที่สำหรับการสมัครก็พร้อมแล้ว หากคุณคลิกเปิดแอป เบราว์เซอร์จะนำคุณไปยังที่อยู่ของแอปพลิเคชันของคุณ นี่คือที่อยู่ webhook ของคุณ - https://your_name.herokuapp.com/ ลงทะเบียนในโทรเลข และใน การตั้งค่าของ application.propertyให้เปลี่ยนtelegrambot webHookPath=https: //telegrambotsimpl.herokuapp.com/ ไปยัง server.port=5000ของคุณ สามารถลบหรือใส่ความคิดเห็นได้ ตอนนี้เรามาเชื่อมต่อฐานข้อมูลกัน ไปที่ แท็บ ทรัพยากรบน Heroku คลิก: ค้นหาHeroku Postgres ที่นั่น คลิกติดตั้ง : คุณจะถูกเปลี่ยนเส้นทางไปยังหน้าบัญชีฐานข้อมูลของคุณ ค้นหาได้ในการตั้งค่า/ จะมีข้อมูลที่จำเป็นทั้งหมดจากฐานข้อมูลของคุณ ในapplication.propertiesตอนนี้ทุกอย่างควรเป็นดังนี้:
#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/d2um26le5notq?ssl=true&sslmode=require&sslfactory=org.postgresql.ssl.NonValidatingFactory
spring.datasource.username=ulmbeymwyvsxa
spring.datasource.password=4c7646c69dbgeacbk98fa96e8daa6d9b1bl4894e67f3f3ddd6a27fe7b0537fd
แทนที่ข้อมูลจากบัญชีของคุณด้วยข้อมูลของคุณ: ในฟิลด์ jdbc:postgresql:ec2-54-247-158-179.eu-west-1.compute.amazonaws.com:5432/d2um26le5notq?ssl=true&sslmode=require&sslfactory=org postgresql.ssl .NonValidatingFactory จะต้องแทนที่ด้วยตัวหนาด้วยข้อมูลที่เกี่ยวข้องจากบัญชี (โฮสต์, ฐานข้อมูล) ช่องชื่อผู้ใช้และรหัสผ่านนั้นเดาได้ไม่ยาก ตอนนี้เราต้องสร้างตารางในฐานข้อมูล ฉันทำสิ่งนี้จาก IDEA สคริปต์ของเราจะมีประโยชน์สำหรับการสร้างฐานข้อมูล เราเพิ่มฐานข้อมูลตามที่เขียนไว้ด้านบน: เรานำ ฟิลด์Host, User, Password, Databaseจากบัญชี ฟิลด์URlคือฟิลด์ spring.datasource.url ของเราจนถึงเครื่องหมายคำถาม ไปที่ แท็บ ขั้นสูงมันควรจะเป็นดังนี้: หากคุณทำทุกอย่างถูกต้องแล้วหลังจากคลิกแบบทดสอบแล้วจะมีเครื่องหมายถูกสีเขียว คลิกตกลง คลิกขวาที่ฐานข้อมูลของเรา และเลือกJump to Query Console คัดลอกสคริปต์ของเราที่นั่นแล้วคลิกดำเนินการ ควรสร้างฐานข้อมูล ให้คุณใช้งานได้ฟรี 10,000 บรรทัด! ทุกอย่างพร้อมสำหรับการปรับใช้ ไปที่แอปพลิเคชันของเราบน Heroku ในส่วนปรับใช้ เลือกส่วน Github ที่นั่น: เชื่อมโยงพื้นที่เก็บข้อมูลของคุณกับ Heroku ตอนนี้กิ่งก้านของคุณจะปรากฏให้เห็น อย่าลืมส่งการเปลี่ยนแปลงล่าสุดของคุณไปที่ .properties ด้าน ล่างเลือกสาขาที่จะดาวน์โหลด และคลิกปรับใช้สาขา หากทุกอย่างถูกต้อง คุณจะได้รับแจ้งว่าแอปพลิเคชันได้รับการปรับใช้เรียบร้อยแล้ว อย่าลืมเปิดใช้งานการปรับใช้อัตโนมัติจาก .. เพื่อให้แอปพลิเคชันของคุณเริ่มทำงานโดยอัตโนมัติ อย่างไรก็ตาม เมื่อคุณกดการเปลี่ยนแปลงไปที่ GitHub Heroku จะรีสตาร์ทแอปพลิเคชันโดยอัตโนมัติ โปรดใช้ความระมัดระวังในเรื่องนี้ สร้างกระทู้แยกต่างหากสำหรับการกลั่นแกล้ง และใช้กระทู้หลักสำหรับแอปพลิเคชันที่ใช้งานได้เท่านั้น ตอนนี้ราคาถูก #2! นี่เป็นข้อเสียที่รู้จักกันดีของแผนฟรีสำหรับ Heroku หากไม่มีข้อความเข้าแอปพลิเคชันจะเข้าสู่โหมดสแตนด์บายและหลังจากได้รับข้อความแล้วจะใช้เวลานานในการเริ่มต้นซึ่งไม่น่าพอใจ มีวิธีแก้ไขง่ายๆ สำหรับสิ่งนี้ - https://uptimerobot.com/ และไม่ อุปกรณ์ปิงของ Google จะไม่ช่วย ฉันไม่รู้ด้วยซ้ำว่าข้อมูลนี้มาจากไหน ฉันค้นหาคำถามนี้ใน Google และเป็นเวลาประมาณ 10 ปีแล้วที่หัวข้อนี้ใช้งานไม่ได้อย่างแน่นอน ถ้ามันได้ผลเลย แอปพลิเคชันนี้จะส่งคำขอ HEAD ไปยังที่อยู่ที่คุณระบุตามเวลาที่คุณตั้งไว้ และหากไม่ตอบสนอง ก็จะส่งข้อความทางอีเมล คุณจะเข้าใจได้ไม่ยาก ปุ่มมีไม่มากพอที่จะสับสน)) ยินดีด้วย!! หากฉันไม่ลืมสิ่งใดและคุณใส่ใจ แสดงว่าคุณก็มีแอปพลิเคชันของคุณเองที่ทำงานได้ฟรีและไม่เคยขัดข้อง โอกาสในการกลั่นแกล้งและการทดลองเปิดอยู่ตรงหน้าคุณ ยังไงก็พร้อมตอบทุกคำถามและทุกคำวิจารณ์! รหัส: https://github.com/papoff8295/webHookBotForHabr วัสดุที่ใช้: https://tlgrm.ru/docs/bots/api - เกี่ยวกับบอท https://en.wikibooks.org/wiki/Java_Persistence - เกี่ยวกับความสัมพันธ์ในฐานข้อมูล https://stackoverflow.com/questions/11432498/how-to-call-a-thread-to-run-on-special-time-in-java - คลาสเวลาและ TimerTask https://www.youtube.com/ watch?v=CUDgSbaYGx4 – วิธีโพสต์โค้ดบน Github https://github.com/rubenlags/TelegramBots - ไลบรารีโทรเลขและข้อมูลที่เป็นประโยชน์มากมายเกี่ยวกับมัน
GO TO FULL VERSION