JavaRush /مدونة جافا /Random-AR /روبوت Telegram - تذكير عبر webHook في Java أو قل لا لتقوي...
Vladimir Popov
مستوى

روبوت Telegram - تذكير عبر webHook في Java أو قل لا لتقويم Google! الجزء 1

نشرت في المجموعة
اسمي فلاديمير. عمري 43 سنة. وإذا كان عمرك أيها القارئ أكثر من 40 عامًا، فنعم، بعد الأربعين يمكنك أن تصبح مبرمجًا إذا أردت ذلك. عملي ليس له علاقة بالبرمجة على الإطلاق، أنا مدير مشروع في مجال الأتمتة وكل ذلك. لكني أخطط لتغيير مهنتي. اه الاتجاهات الجديدة دي... غير مجال نشاطك كل 5-7 سنوات. لذا : تبين أن المشروع كبير جدًا، لذا يجب حذف بعض النقاط أو التحدث عنها باختصار، على أمل أن يعرف القارئ كيفية البحث في جوجل. الإنترنت مليء بمنشورات روبوتات البرقية التي تعمل على مبدأ الاقتراع الطويل. وهناك عدد قليل جدًا من الأشخاص الذين يعملون وفقًا لمبدأ Webhook. ما هو؟ الاستقصاء الطويل - هذا يعني أن تطبيقك نفسه سيقوم باستقصاء خادم التليجرام بحثًا عن الرسائل بتردد معين، ببطء. Webhook - يعني أن خادم التليجرام سيعيد توجيه الرسائل على الفور إلى الخادم الذي تحدده. في حالتنا، من باب المجاملة خدمة Heroku. يمكنك بالطبع قراءة المزيد عن كل هذا وعن الروبوت بشكل عام على موقع Telegram - https://tlgrm.ru/docs/bots/api تبدو واجهة الروبوت كما يلي: روبوت Telegram - تذكير عبر webHook في Java أو قل لا لتقويم Google!  - 1 أنا أعتبر هذا التطبيق على وجه التحديد بمثابة تدريب المشروع لأنني تعلمت معلومات من هذا الروبوت أثناء الكتابة أكثر مما تعلمته أثناء التدريب. هل تريد أن تتعلم البرمجة؟ البدء في كتابة التعليمات البرمجية!!! لكن! لن تكون هناك تعليمات مفصلة حول كيفية تحميل التطبيق على جيثب أو كيفية إنشاء قاعدة بيانات. هناك الكثير من هذا على الإنترنت، وقد تم وصفه بتفصيل كبير، علاوة على ذلك، ستكون قراءته طويلة جدًا. سيعمل التطبيق على النحو التالي: أدخل وصفًا للحدث، أدخل تاريخ ووقت الحدث، حدد التكرار (يمكنك القيام بذلك مرة واحدة، يمكنك الحصول على تذكير كل يوم في وقت معين، يمكنك الحصول عليه مرة واحدة) شهرًا في وقت معين، أو مرة واحدة في السنة). يمكن إضافة أشكال مختلفة من الإخطارات إلى ما لا نهاية، ولدي الكثير من الأفكار. بعد ذلك، يتم حفظ البيانات المدخلة في قاعدة البيانات (يتم نشرها أيضًا مجانًا على Heroku، 10000 صف مجاني) ثم، مرة واحدة في بداية اليوم عند الساعة 0:00 بتوقيت الخادم، يسترد Spring من قاعدة البيانات جميع الأحداث بناءً على المعايير يجب أن يطلق النار في ذلك اليوم ويرسلهم للتنفيذ في الوقت المحدد. انتباه!!! هذا الجزء من البرنامج تجريبي! هناك طريقة تنفيذ أكثر بساطة وحقيقية! لقد تم ذلك خصيصًا لمعرفة كيفية عمل الفصل الزمني! يمكنك لمس الروبوت العامل بيديك عن طريق كتابة @calendar_event_bot في العربة، لكن لا تعتمد عليه، لأنني مازلت أسخر منه. الكود - https://github.com/papoff8295/webHookBotForHabr بشكل أساسي، لإطلاق مشروعك الخاص، عليك اتخاذ الخطوات التالية: • التسجيل مع @BotFather ، الأمر ليس بالأمر الصعب، احصل على رمز مميز واسم • قم بتقسيم المشروع على github • سجل على هيروكو، أنشئ تطبيقًا (سنتناوله خطوة بخطوة)، ثم انشره من مستودعك. • قم بإنشاء قاعدة بيانات على Heroku • استبدل الحقول المقابلة في المستودع بحقلك (الرمز المميز، اسم الجداول في الكيانات، webHookPath، اسم المستخدم، كلمة المرور والمسار إلى قاعدة البيانات، سيتم تحليل كل هذا) • اجعل Heroku يعمل 24/ 7 باستخدام https://uptimerobot.com/ الهيكل النهائي للمشروع كما يلي: روبوت Telegram - تذكير عبر webHook في Java أو قل لا لتقويم Google!  - 2 لنبدأ بإنشاء مشروع في https://start.spring.io حدد التبعيات التي نحتاجها كما هو موضح في الشكل: روبوت Telegram - تذكير عبر webHook في Java أو قل لا لتقويم Google!  - 3حدد التبعيات الخاصة بنا اسم المشروع وانقر فوق إنشاء . بعد ذلك سيُطلب منك حفظ المشروع على القرص الخاص بك. كل ما تبقى هو فتح الملف pom.xm l من بيئة التطوير الخاصة بك. هناك مشروع جاهز أمامك. الآن نحتاج فقط إلى إضافة مكتبتنا الرئيسية. لقد استخدمت المكتبة من https://github.com/rubenlagus/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 – اسم الطريقة ومعلماتها. في هذه الحالة، نقوم بتثبيت خادم الويب هوك الخاص بك، وسيتم إرسال جميع الرسائل إليه. بشكل عام، قررت أن المشروع ليس صغيرًا جدًا للنشر، ولكن مع التنفيذ اليدوي سيكون غير قابل للقراءة بشكل عام. إذن، الشكل النهائي لملف 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 الذي تم تحليله ككائن تحديث ويعيد ما يريد خادم البرقية "سماعه" منا. لدينا هنا شروح من مكتبة لومبوك . لومبوك – جعل حياة المبرمج أسهل!! حسنا، هذا هو. لا نحتاج إلى إعادة تعريف الحروف والمحددات، فLombok يقوم بذلك نيابةً عنا، ولا نحتاج أيضًا إلى كتابة معرف مستوى الوصول. لم يعد من المفيد أن نكتب أن هذا يتم عن طريق التعليقات التوضيحية Getter وSetter وFieldDefaults. يعني حقل botPath عنوان خطاف الويب الخاص بنا، والذي سنتلقاه على Heroku لاحقًا. حقل botUsername يعني اسم الروبوت الخاص بنا، والذي سنحصل عليه عند تسجيل الروبوت الخاص بنا في Telegram. حقل botToken هو الرمز المميز الخاص بنا، والذي سنتلقاه عند تسجيل الروبوت الخاص بنا في Telegram. حقل telegramFacade هو فصلنا الذي ستتم فيه معالجة الرسائل، وسنعود إليه بعد قليل، فليكن باللون الأحمر في الوقت الحالي. حان الوقت الآن للتواصل مع @BotFather والحصول على botToken وbotUsername المرغوبين. روبوت Telegram - تذكير عبر webHook في Java أو قل لا لتقويم Google!  - 4فقط راسله على التليجرام وسيخبرك بكل شيء. نكتب البيانات في 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 مباشرة في التطبيق. لنقم بإنشاء فول أو فئة مجمعة من هذه البيانات.
@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 لنا عند بدء تشغيل التطبيق. دعونا الآن نلقي نظرة على ملف تكوين الربيع:
@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، وتستقبلها وحدة التحكم لدينا وترسلها إلى مكتبة telegram في شكل كائن تحديث. لقد قمت باستخدام طريقة 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;
    }

}
هذه الطريقة سوف تستجيب لأي مرحبا بالعالم! من أجل إطلاق تطبيقنا، نحتاج إلى التأكد من أنه يمكننا اختبار تطبيقنا مباشرة من IDEA. للقيام بذلك، نحتاج إلى تنزيل الأداة المساعدة ngrok. https://ngrok.com/download هذه الأداة المساعدة عبارة عن سطر أوامر يمنحنا عنوانًا مؤقتًا لمدة ساعتين ويعيد توجيه جميع الرسائل إلى المنفذ المحدد للخادم المحلي. نطلق ونكتب ngrok http 5000 في السطر (أو يمكنك تحديد المنفذ الخاص بك): روبوت Telegram - تذكير عبر webHook في Java أو قل لا لتقويم Google!  - 5نحصل على النتيجة: روبوت Telegram - تذكير عبر webHook في Java أو قل لا لتقويم Google!  - 6https://23b1a54ccbbd.ngrok.io - هذا هو عنوان webhook الخاص بنا. كما لاحظت في ملف الخصائص كتبنا server.port=5000 عند بدء تشغيل خادم Tomcat، سيشغل المنفذ 5000، تأكد من أن هذه الحقول هي نفسها. ولا تنس أيضًا أن العنوان يُعطى لمدة ساعتين. في سطر الأوامر، تتم مراقبة ذلك من خلال حقل انتهاء صلاحية الجلسة. عندما ينتهي الوقت، ستحتاج إلى الحصول على العنوان مرة أخرى وإجراء إجراءات تسجيله على برقية. الآن نأخذ السطر https://api.telegram.org/bot1866835969:AAE6gJG6ptUyqhV2XX0MxyUak4QbAGGnz10/setWebhook?url=https://e9c658b548aa.ngrok.io وبحركات اليد الماهرة نستبدل الرمز المميز برمزنا، وعنوان url برمزنا، نلصق السطر الناتج في المتصفح وانقر فوق إدخال. يجب أن تحصل على النتيجة التالية: روبوت Telegram - تذكير عبر webHook في Java أو قل لا لتقويم Google!  - 7هذا كل شيء، الآن يمكنك تشغيل التطبيق: روبوت Telegram - تذكير عبر webHook في Java أو قل لا لتقويم Google!  - 8تأكد من أن فصلك باستخدام الطريقة الرئيسية كان على النحو التالي:
@SpringBootApplication
public class TelegramBotApplication {

   public static void main(String[] args) {
      SpringApplication.run(TelegramBotApplication.class, args);
   }
}
إذا فعلت كل شيء بشكل صحيح، فسوف يستجيب الروبوت الخاص بك لأي رسالة تحتوي على عبارة " Hello World" . ثم يمكنك الذهاب في طريقك الخاص. إذا كنت معي وترغب في تنفيذ جميع الخطوات، فلنبدأ في كتابة الكيانات لقاعدة البيانات وإنشاء قاعدة البيانات نفسها. لنبدأ بقاعدة البيانات: كما قلت سابقًا، أفترض أن لديك بالفعل الحد الأدنى من المهارات في العمل مع قاعدة البيانات، وأن لديك قاعدة بيانات PostgreSQL محلية مثبتة ، إذا لم يكن الأمر كذلك، فاتبع هذا المسار. https://www.postgresql.org/download/ في ملف application.properties، استبدل معلومات تسجيل الدخول وكلمة المرور الخاصة بقاعدة البيانات بأخرى خاصة بك. في IDEA توجد علامة تبويب قاعدة البيانات على اليمين، حيث تحتاج إلى النقر فوق +/Data source/PostgreSQL . ونتيجة لذلك، عند النقر فوق اختبار الاتصال ، يجب أن تحصل على نتيجة مرضية: روبوت Telegram - تذكير عبر webHook في Java أو قل لا لتقويم Google!  - 9يمكنك الآن إنشاء قاعدة بيانات تحتوي على جداول مباشرة من بيئة التطوير، أو يمكنك استخدام واجهة الويب 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، حتى لا نكتبه مرتين. دعونا نسير قليلا. سأقول على الفور أننا نحتاج فقط إلى جدول events_cash للعمل مع Heroku نظرًا لخصائصه ورغبتي الشديدة في العمل مع فئة Time ؛ فلن يكون مفيدًا في الإصدار المحلي. في جدول المستخدمين ، سنقوم بتسجيل معرف حساب مستخدم تيليجرام، واسمه الذي قد لا يكون موجودًا، وسيتم حساب المنطقة الزمنية للمستخدم لإرسال الإشعارات بشكل صحيح، بالإضافة إلى حالة تشغيل/إيقاف إرسال الإشعارات. سنقوم بتسجيل معرف المستخدم ووقت الإشعار والوصف في جدول user_events ، وإنشاء معرف للحدث تلقائيًا ، وتعيين تكرار الإشعارات. سيقوم جدول events_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 - يشير إلى فئة دادا jpa الخاصة بنا والتي تشير إلى أن هذه الفئة هي كيان لقاعدة البيانات، أي. عند استرداد البيانات من قاعدة البيانات، سيتم تقديمها لنا في شكل كائن Event وUser و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,>
يتم نقل المنطق الرئيسي للعمل مع قاعدة البيانات إلى خدمة تسمى كائن الوصول إلى البيانات (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 وما هي أنواع القوائم الموجودة. للقيام بذلك، سأعطيك صورة أخرى لواجهة الروبوت: روبوت Telegram - تذكير عبر webHook في Java أو قل لا لتقويم Google!  - 10هناك نوعان من القوائم. تلك المرتبطة بأسفل النافذة - القائمة الرئيسية، وتلك المخصصة للرسالة، على سبيل المثال، أزرار الحذف والتحرير وتغيير الحزام. عند النقر على زر القائمة الرئيسية، يتم إرسال رسالة بنفس الاسم، على سبيل المثال، عند النقر على "تذكيراتي" ، سيتم إرسال النص "تذكيراتي" ببساطة . وعند تثبيت لوحة المفاتيح callbackquery يتم تحديد قيمة محددة لكل زر وسيتم إرسال قيمتها دون عرضها على الشاشة. التالي لدينا حقل BotStateCash . هذه فئة تم إنشاؤها خصيصًا والتي ستراقب حالة الروبوت، والانتباه، هذا عنصر معقد، تحتاج إلى الضغط عليه. تم تجاوز عدد الأحرف، والذي، بالمناسبة، لم يتم كتابته في أي مكان)). إذن هذا هو الرابط للجزء الثاني
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION