JavaRush /جاوا بلاگ /Random-UR /Spring Boot Pt.2 کا استعمال کرتے ہوئے ٹیلیگرام بوٹ بنانا:...
Whiskels
سطح
Москва

Spring Boot Pt.2 کا استعمال کرتے ہوئے ٹیلیگرام بوٹ بنانا: کوئز بوٹ

گروپ میں شائع ہوا۔
حصہ 1 الوہا! پچھلے مضمون میں، ہم نے ایک سادہ بوٹ بنایا جو کسی بھی تقریب میں ہمارا استقبال کرتا ہے۔ ہم پہلے ہی کوڈ کی ہزاروں لائنیں لکھ چکے ہیں، اور اب وقت آگیا ہے کہ ہم اپنے بوٹ میں مزید پیچیدہ فعالیت شامل کریں۔ آج ہم ایک سادہ بوٹ لکھنے کی کوشش کریں گے تاکہ اپنے فارغ وقت میں ہم انٹرویو سے پہلے جاوا کور کے بارے میں اپنے علم کو بہتر بنا سکیں (حیرت کی بات ہے کہ مجھے اس قسم کا ایک بھی کام کرنے والا بوٹ نہیں ملا)۔ ایسا کرنے کے لیے ہم درج ذیل کام کریں گے۔
  • ایک بیرونی پوسٹگریس ڈیٹا بیس کو ہیروکو سے جوڑیں؛
  • آئیے ڈیٹا بیس کو شروع کرنے اور آباد کرنے کے لیے اپنی پہلی اسکرپٹ لکھتے ہیں۔
  • آئیے ڈیٹا بیس کے ساتھ کام کرنے کے لیے اسپرنگ بوٹ ڈیٹا JPA کو جوڑتے ہیں۔
  • ہم بوٹ رویے کے مختلف منظرناموں کو نافذ کرتے ہیں۔
اگر یہ آپ کے لیے دلچسپ ہے، اور مضمون پڑھنے کے بعد آپ سڑے ہوئے ٹماٹر نہیں پھینکنا چاہتے، تو میرے ذخیرے میں ایک ستارہ لگائیں ، مجھے خوشی ہوگی! اگر آپ کے کوئی سوالات ہیں، تو ہم تبصروں میں ان پر بات کریں گے۔ آخر میں ہمیں یہی ملے گا: Spring Boot Pt.2 کا استعمال کرتے ہوئے ٹیلیگرام بوٹ بنانا: کوئز بوٹ - 1Spring Boot Pt.2 کا استعمال کرتے ہوئے ٹیلیگرام بوٹ بنانا: کوئز بوٹ - 2Spring Boot Pt.2 کا استعمال کرتے ہوئے ٹیلیگرام بوٹ بنانا: کوئز بوٹ - 3<h2>تو، چلیں!</h2><h3>ہیروکو پر ایک ڈیٹا بیس بنانا</h3>آئیے اپنا پہلا بیرونی ڈیٹا بیس بنا کر شروع کریں۔ مقامی کام کے لیے، میں pgAdmin کو چیک کرنے کی تجویز کرتا ہوں ۔ لیکن میں چاہتا ہوں کہ آپ اس حقیقت سے رہنمائی حاصل کریں کہ مستقبل میں آپ بوٹ کو ہیروکو میں تعینات کریں گے تاکہ یہ آپ کی مقامی مشین پر منحصر نہ ہو، اور اس کے لیے آئیے اس سروس سے واقف ہوں۔ طریقہ کار:
  • ہیروکو پر رجسٹر کریں ؛
  • ہمارے ڈیش بورڈ پر جائیں -> نیا -> نئی ایپ بنائیں اور ایک نئی ایپلیکیشن بنائیں؛
  • ہم نئی تخلیق کردہ ایپلی کیشن میں جاتے ہیں، ہمیں بہت سے بٹنوں سے خوف آتا ہے، لیکن ہم "انسٹالڈ ایڈ آنز" پینل پر توجہ مرکوز کرتے ہیں - اس کے آگے ایک کنفیگر ایڈ آنز بٹن ہے، ہم اس پر کلک کرتے ہیں۔
  • تلاش میں "ہیروکو پوسٹگریس" درج کریں، "شوق دیو - مفت" پلان منتخب کریں -> آرڈر فارم جمع کروائیں؛
  • نیا حاصل کردہ ڈیٹا بیس کھولیں -> ترتیبات -> اسناد دیکھیں۔ اس ٹیب میں ڈیٹا بیس تک رسائی کے لیے ہماری کلیدیں شامل ہوں گی۔ ہمیں ان کا مقام یاد ہے - ہمیں ڈیٹا بیس کو جوڑنے کے لیے ان کی ضرورت ہوگی، جیسے IDEA میں ڈیٹا سورس۔
<h3>pom.xml میں انحصار شامل کریں رکو! یہ سب کیا ہے اور ہم اسے کیوں شامل کر رہے ہیں؟
  • لومبوک ایک لائبریری ہے جس کی بدولت ہم مختلف کوڈ کی مقدار کو نمایاں طور پر کم کر دیں گے۔ اس کے ساتھ ہم خود بخود کنسٹرکٹرز، سیٹرز، گیٹرز اور بہت کچھ بنا سکتے ہیں۔
  • Spring Data JPA ڈیٹا بیس کے ساتھ کام کرنے کا ایک فریم ورک ہے (حالانکہ یہ بہت آسان لگتا ہے)۔ Spring Data JPA کی صلاحیتوں کی تفصیل مضامین کی ایک سیریز کے برابر ہوگی، اور ہم نے جس انحصار کی وضاحت کی ہے اس میں Hibernate اور بہت کچھ شامل ہے، لہذا آئیے تفصیلات کو چھوڑ دیں اور آج Spring JPA کا استعمال کرتے ہوئے کچھ لکھنے کی کوشش کریں۔
  • PostgreSQL - ہم ایک ڈرائیور حاصل کرنے کے لیے لائبریری کو کھینچتے ہیں جو ہمارے ڈیٹا بیس کے ساتھ کام کرے گا۔
ہمارا pom.xml اس طرح نظر آنا شروع ہوتا ہے: خواص: Spring Boot Pt.2 کا استعمال کرتے ہوئے ٹیلیگرام بوٹ بنانا: کوئز بوٹ - 1انحصار: Spring Boot Pt.2 کا استعمال کرتے ہوئے ٹیلیگرام بوٹ بنانا: کوئز بوٹ - 2اگر آپ نے پچھلا مضمون نہیں پڑھا، تو براہ کرم نوٹ کریں کہ ہم یہاں نئے انحصار شامل کر رہے ہیں، اس لیے یہ مکمل pom.xml ڈھانچہ نہیں ہے۔ ان انحصاروں کو ہمارے پروجیکٹ میں لوڈ کرنا نہ بھولیں (مثال کے طور پر Maven -> تمام Maven پروجیکٹس کی ونڈو پر جا کر)۔<h3>ڈیٹا بیس کو IDEA میں جوڑنا</h3>اگر آپ IDEA کمیونٹی ایڈیشن استعمال کرتے ہیں، تو آپ مندرجہ ذیل ڈیٹا سورس ٹیب کو فعال کریں ۔ پلگ ان کو شامل کرنے کے بعد، ہمیں ڈیٹا سورس کو کنفیگر کرنے کی ضرورت ہے۔ ایسا کرنے کے لیے، پہلے پلگ ان ڈسپلے کو فعال کریں: دیکھیں -> ٹول ونڈوز -> ڈی بی براؤزر۔ کھلنے والی ونڈو میں، گرین پلس (نیا کنکشن) -> PostgreSQL پر کلک کریں۔ یہاں ہمیں اسناد کی ضرورت ہوگی، جو ہم پہلے ہیروکو پر دیکھ چکے ہیں۔ ونڈو کو پُر کریں: Spring Boot Pt.2 کا استعمال کرتے ہوئے ٹیلیگرام بوٹ بنانا: کوئز بوٹ - 3اور "ٹیسٹ کنکشن" پر کلک کریں۔ اگر سب کچھ صحیح طریقے سے کیا گیا ہے تو، ایک پاپ اپ ونڈو ظاہر ہوگی جو اس بات کی نشاندہی کرے گی کہ ڈیٹا بیس سے کنکشن کامیاب ہوگیا ہے۔ ہمارے ڈیٹا سورس کو محفوظ کریں۔<h3>ڈیٹا بیس میں ٹیبلز بنائیں</h3>اب آئیے وہ ٹیبلز بنائیں جن کے ساتھ ہم کام کریں گے۔ پہلے، PostgreSQL انسٹال کرتے ہیں ۔ تنصیب کے بعد، src/main/resources فولڈر میں initDB.sql فائل بنائیں:
DROP TABLE IF EXISTS java_quiz;
DROP TABLE IF EXISTS users;
CREATE SEQUENCE global_seq START WITH 100000;

CREATE TABLE users
(
    id         INTEGER PRIMARY KEY DEFAULT nextval('global_seq'),
    chat_id    INTEGER UNIQUE                NOT NULL,
    name       VARCHAR                       NOT NULL,
    score      INTEGER             DEFAULT 0 NOT NULL,
    high_score INTEGER             DEFAULT 0 NOT NULL,
    bot_state  VARCHAR                       NOT NULL
);

CREATE TABLE java_quiz
(
    id             INTEGER PRIMARY KEY DEFAULT nextval('global_seq'),
    question       VARCHAR NOT NULL,
    answer_correct VARCHAR NOT NULL,
    option1        VARCHAR NOT NULL,
    option2        VARCHAR NOT NULL,
    option3        VARCHAR NOT NULL
);
ہمارا اسکرپٹ کیا کرتا ہے؟ پہلی دو سطریں میزوں کو مٹا دیتی ہیں، اگر موجود ہوں تو انہیں دوبارہ بنانے کے لیے۔ تیسری لائن ایک ترتیب بناتی ہے جو ہمارے ڈیٹا بیس میں منفرد شناختی اندراجات بنانے کے لیے استعمال ہوگی۔ اگلا، ہم دو میزیں بناتے ہیں: صارفین کے لیے اور سوالات کے لیے۔ صارف کے پاس ایک منفرد آئی ڈی، ٹیلی گرام چیٹ آئی ڈی، نام، پوائنٹس کی تعداد (موجودہ اور زیادہ سے زیادہ) کے ساتھ ساتھ بوٹ کی موجودہ حیثیت بھی ہوگی۔ سوالات کی ایک منفرد آئی ڈی بھی ہوگی، ساتھ ہی اس کے لیے سوال و جواب کے اختیارات کے لیے ذمہ دار فیلڈز بھی ہوں گی۔ ہم اس پر دائیں کلک کرکے اور "Execute SQL Script" کو منتخب کر کے نتیجے میں آنے والے اسکرپٹ کو انجام دے سکتے ہیں۔ "Cmd-Line انٹرفیس" آئٹم پر خاص توجہ دی جانی چاہئے - یہاں ہمیں تازہ انسٹال کردہ PostgreSQL کی ضرورت ہوگی۔ اس فیلڈ کو کنفیگر کرتے وقت، "New Cmd-Line انٹرفیس" کو منتخب کریں اور psql.exe کا راستہ بتائیں۔ نتیجے کے طور پر، ترتیبات کچھ اس طرح نظر آنی چاہئیں: Spring Boot Pt.2 کا استعمال کرتے ہوئے ٹیلیگرام بوٹ بنانا: کوئز بوٹ - 4ہم اسکرپٹ پر عمل کرتے ہیں اور اگر ہم نے کہیں غلطی نہیں کی ہے، تو ہمارے کام کا نتیجہ یہ ہوگا: Spring Boot Pt.2 کا استعمال کرتے ہوئے ٹیلیگرام بوٹ بنانا: کوئز بوٹ - 8<h3>ایک ماڈل بنائیں</h3>اب وقت آگیا ہے۔ جاوا کوڈ لکھنے پر واپس جانے کے لیے۔ مضمون کو مختصر کرنے کے لیے، میں کلاسز لکھنے کے لیے استعمال ہونے والی تشریحات کی تفصیل کو چھوڑ دوں گا تاکہ آپ ان سے خود کو واقف کر سکیں۔ آئیے ایک ماڈل پیکج بنائیں جس میں ہماری تین کلاسیں ہوں گی۔
  • AbstractBaseEntity ایک ایسی کلاس ہے جو کسی بھی شے کی وضاحت کرتی ہے جس کی id ہو سکتی ہے (یہ کلاس اس بات کی مضبوط سادگی ہے جو آپ انٹرنشپ میں دیکھ سکتے ہیں):
    package com.whiskels.telegram.model;
    
    import lombok.Getter;
    import lombok.Setter;
    
    import javax.persistence.*;
    // Аннотация, которая говорит нам, что это суперкласс для всех Entity
    // https://vladmihalcea.com/how-to-inherit-properties-from-a-base-class-entity-using-mappedsuperclass-with-jpa-and-hibernate/
    @MappedSuperclass
    // http://stackoverflow.com/questions/594597/hibernate-annotations-which-is-better-field-or-property-access
    @Access(AccessType.FIELD)
    
    // Аннотации Lombok для автогенерации сеттеров и геттеров на все поля
    @Getter
    @Setter
    public abstract class AbstractBaseEntity {
    
    // Аннотации, описывающие механизм генерации id - разберитесь в documentации каждой!
        @Id
        @SequenceGenerator(name = "global_seq", sequenceName = "global_seq", allocationSize = 1, initialValue = START_SEQ)
        @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "global_seq")
    //  See https://hibernate.atlassian.net/browse/HHH-3718 and https://hibernate.atlassian.net/browse/HHH-12034
    //  Proxy initialization when accessing its identifier managed now by JPA_PROXY_COMPLIANCE setting
        protected Integer id;
    
        protected AbstractBaseEntity() {
        }
    }
  • صارف :
    package com.whiskels.telegram.model;
    
    import com.whiskels.telegram.bot.State;
    import lombok.AllArgsConstructor;
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.Setter;
    import org.hibernate.annotations.BatchSize;
    
    import javax.persistence.*;
    import javax.validation.constraints.NotBlank;
    import javax.validation.constraints.NotNull;
    import java.util.Set;
    
    import static javax.persistence.FetchType.EAGER;
    
    @Entity
    @Table(name = "users", uniqueConstraints = {@UniqueConstraint(columnNames = "chat_id", name = "users_unique_chatid_idx")})
    @Getter
    @Setter
    @NoArgsConstructor
    @AllArgsConstructor
    public class User extends AbstractBaseEntity {
        @Column(name = "chat_id", unique = true, nullable = false)
        @NotNull
        private Integer chatId;
    
        @Column(name = "name", unique = true, nullable = false)
        @NotBlank
        private String name;
    
        @Column(name = "score", nullable = false)
        @NotNull
        private Integer score;
    
        @Column(name = "high_score", nullable = false)
        @NotNull
        private Integer highScore;
    
        @Column(name = "bot_state", nullable = false)
        @NotBlank
        private State botState;
    
    // Конструктор нужен для создания нового пользователя (а может и нет? :))
        public User(int chatId) {
            this.chatId = chatId;
            this.name = String.valueOf(chatId);
            this.score = 0;
            this.highScore = 0;
            this.botState = State.START;
        }
    }
  • سوال کی کلاس :
    package com.whiskels.telegram.model;
    
    import lombok.AllArgsConstructor;
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.Setter;
    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.Table;
    import javax.validation.constraints.NotBlank;
    
    @Entity
    @Table(name = "java_quiz")
    @Getter
    @Setter
    @NoArgsConstructor
    @AllArgsConstructor
    public class Question extends AbstractBaseEntity {
        @Column(name = "question", nullable = false)
        @NotBlank
        private String question;
    
        @Column(name = "answer_correct", nullable = false)
        @NotBlank
        private String correctAnswer;
    
        @Column(name = "option2", nullable = false)
        @NotBlank
        private String optionOne;
    
        @Column(name = "option1", nullable = false)
        @NotBlank
        private String optionTwo;
    
        @Column(name = "option3", nullable = false)
        @NotBlank
        private String optionThree;
    
        @Override
        public String toString() {
            return "Question{" +
                    "question='" + question + '\'' +
                    ", correctAnswer='" + correctAnswer + '\'' +
                    ", optionOne='" + optionOne + '\'' +
                    ", optionTwo='" + optionTwo + '\'' +
                    ", optionThree='" + optionThree + '\'' +
                    '}';
        }
    }
<h3>ریپوزٹریز بنانا</h3>اب آئیے اسپرنگ ڈیٹا جے پی اے ریپوزٹریز لکھتے ہیں۔ ہم ایک ریپوزٹری پیکج بناتے ہیں جس کے دو انٹرفیس ہوں گے : JpaUserRepository، JpaQuestionRepository۔ وہ JpaRepository سے وراثت میں ہوں گے، ایک اسپرنگ ڈیٹا انٹرفیس جو ہمیں عملی طور پر جادو بنانے کی اجازت دیتا ہے۔ ان کے کام کو سمجھنے کے لیے، میں Evgeny Borisov کی ویڈیو دیکھنے کی تجویز کرتا ہوں ۔ کلاسز بہت چھوٹے ہوں گے:
  • JpaUserRepository:
    package com.whiskels.telegram.repository;
    
    import com.whiskels.telegram.model.User;
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.stereotype.Repository;
    import org.springframework.transaction.annotation.Transactional;
    
    import java.util.Optional;
    
    @Repository
    @Transactional(readOnly = true)
    public interface JpaUserRepository extends JpaRepository<user, integer=""> {
    // По названию метода Spring сам поймет, что мы хотим получить пользователя по переданному chatId
        Optional<user> getByChatId(int chatId);
    }
    </user></user,>
  • JpaQuestionRepository:
    package com.whiskels.telegram.repository;
    
    import com.whiskels.telegram.model.Question;
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.data.jpa.repository.Query;
    
    @Repository
    @Transactional(readOnly = true)
    public interface JpaQuestionRepository extends JpaRepository<question, integer=""> {
    // А здесь мы написали SQL Query, которая будет выбирать 1 случайный вопрос из таблицы вопросов
        @Query(nativeQuery = true, value = "SELECT *  FROM java_quiz ORDER BY random() LIMIT 1")
        Question getRandomQuestion();
    }
    </question,>
<h3>بوٹ میں فعالیت شامل کریں</h3> صارف کی کلاس میں ہمارے پاس ابھی تک نہیں بنائی گئی اسٹیٹ کلاس کا ایک فیلڈ ہے ، جو ہمیں بتائے گا کہ صارف اس وقت بوٹ کے ساتھ کام کرنے کے کس مرحلے پر ہے۔ آئیے اسے /bot پیکیج میں بنائیں:
package com.whiskels.telegram.bot;

public enum State {
    NONE,
    START,
    ENTER_NAME,
    PLAYING_QUIZ,
}
اگلا، ہم ایک بوٹ/ہینڈلر پیکیج بنائیں گے جس میں ہم ہینڈلر انٹرفیس کا اعلان کریں گے:
package com.whiskels.telegram.bot.handler;

import com.whiskels.telegram.bot.State;
import com.whiskels.telegram.model.User;
import org.telegram.telegrambots.meta.api.methods.PartialBotApiMethod;

import java.io.Serializable;
import java.util.List;

public interface Handler {

// основной метод, который будет обрабатывать действия пользователя
    List<partialbotapimethod<? extends="" serializable="">> handle(User user, String message);
// метод, который позволяет узнать, можем ли мы обработать текущий State у пользователя
    State operatedBotState();
// метод, который позволяет узнать, Howие команды CallBackQuery мы можем обработать в этом классе
    List<string> operatedCallBackQuery();
}

</string></partialbotapimethod<?>
ہم تھوڑی دیر بعد ہینڈلرز بنائیں گے، لیکن فی الحال آئیے ایونٹ پروسیسنگ کو نئی UpdateReceiver کلاس کو سونپتے ہیں، جسے ہم بوٹ پیکیج کی جڑ میں بنائیں گے: توجہ! یہاں اور آگے ایسے طریقے ہوں گے جو بطور List> handle(args) ظاہر ہوتے ہیں؛ حقیقت میں وہ اس طرح نظر آتے ہیں، لیکن کوڈ فارمیٹر نے انہیں توڑ دیا:Spring Boot Pt.2 کا استعمال کرتے ہوئے ٹیلیگرام بوٹ بنانا: کوئز بوٹ - 6
package com.whiskels.telegram.bot;

import com.whiskels.telegram.bot.handler.Handler;
import com.whiskels.telegram.model.User;
import com.whiskels.telegram.repository.JpaUserRepository;
import org.springframework.stereotype.Component;
import org.telegram.telegrambots.meta.api.methods.PartialBotApiMethod;
import org.telegram.telegrambots.meta.api.objects.CallbackQuery;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.Update;

import java.io.Serializable;
import java.util.Collections;
import java.util.List;

@Component
public class UpdateReceiver {
    // Храним доступные хендлеры в списке (подсмотрел у Miroha)
    private final List<handler> handlers;
    // Имеем доступ в базу пользователей
    private final JpaUserRepository userRepository;

    public UpdateReceiver(List<handler> handlers, JpaUserRepository userRepository) {
        this.handlers = handlers;
        this.userRepository = userRepository;
    }

    // Обрабатываем полученный Update
    public List<partialbotapimethod<? extends="" serializable="">> handle(Update update) {
        // try-catch, чтобы при несуществующей команде просто возвращать пустой список
        try {
            // Проверяем, если Update - сообщение с текстом
            if (isMessageWithText(update)) {
                // Получаем Message из Update
                final Message message = update.getMessage();
                // Получаем айди чата с пользователем
                final int chatId = message.getFrom().getId();

                // Просим у репозитория пользователя. Если такого пользователя нет - создаем нового и возвращаем его.
                // Как раз на случай нового пользователя мы и сделали конструктор с одним параметром в классе User
                final User user = userRepository.getByChatId(chatId)
                        .orElseGet(() -> userRepository.save(new User(chatId)));
                // Ищем нужный обработчик и возвращаем результат его работы
                return getHandlerByState(user.getBotState()).handle(user, message.getText());

            } else if (update.hasCallbackQuery()) {
                final CallbackQuery callbackQuery = update.getCallbackQuery();
                final int chatId = callbackQuery.getFrom().getId();
                final User user = userRepository.getByChatId(chatId)
                        .orElseGet(() -> userRepository.save(new User(chatId)));

                return getHandlerByCallBackQuery(callbackQuery.getData()).handle(user, callbackQuery.getData());
            }

            throw new UnsupportedOperationException();
        } catch (UnsupportedOperationException e) {
            return Collections.emptyList();
        }
    }

    private Handler getHandlerByState(State state) {
        return handlers.stream()
                .filter(h -> h.operatedBotState() != null)
                .filter(h -> h.operatedBotState().equals(state))
                .findAny()
                .orElseThrow(UnsupportedOperationException::new);
    }

    private Handler getHandlerByCallBackQuery(String query) {
        return handlers.stream()
                .filter(h -> h.operatedCallBackQuery().stream()
                        .anyMatch(query::startsWith))
                .findAny()
                .orElseThrow(UnsupportedOperationException::new);
    }

    private boolean isMessageWithText(Update update) {
        return !update.hasCallbackQuery() && update.hasMessage() && update.getMessage().hasText();
    }
}

</partialbotapimethod<?></handler></handler>
اور ہم بوٹ کلاس میں اس پر کارروائی کرتے ہیں:
package com.whiskels.telegram.bot;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.meta.api.methods.PartialBotApiMethod;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;

import java.io.Serializable;
import java.util.List;

@Slf4j
@Component
public class Bot extends TelegramLongPollingBot {
    @Value("${bot.name}")
    @Getter
    private String botUsername;

    @Value("${bot.token}")
    @Getter
    private String botToken;

    private final UpdateReceiver updateReceiver;

    public Bot(UpdateReceiver updateReceiver) {
        this.updateReceiver = updateReceiver;
    }

    @Override
    public void onUpdateReceived(Update update) {
        List<partialbotapimethod<? extends="" serializable="">> messagesToSend = updateReceiver.handle(update);

        if (messagesToSend != null && !messagesToSend.isEmpty()) {
            messagesToSend.forEach(response -> {
                if (response instanceof SendMessage) {
                    executeWithExceptionCheck((SendMessage) response);
                }
            });
        }
    }

    public void executeWithExceptionCheck(SendMessage sendMessage) {
        try {
            execute(sendMessage);
        } catch (TelegramApiException e) {
            log.error("oops");
        }
    }
}

</partialbotapimethod<?>
اب ہمارا بوٹ ایونٹ پروسیسنگ کو UpdateReceiver کلاس میں بھیجتا ہے، لیکن ہمارے پاس ابھی تک کوئی ہینڈلر نہیں ہے۔ آئیے انہیں بنائیں! ڈس کلیمر! میں واقعی میں اس طرح کے بوٹ کو لکھنے کے امکانات کا اشتراک کرنا چاہتا تھا، لہذا مزید کوڈ (جیسا کہ اصولی طور پر UpdateReceiver کوڈ) مختلف نمونوں کا استعمال کرتے ہوئے بہت اچھی طرح سے ریفیکٹر کیا جا سکتا ہے۔ لیکن ہم سیکھ رہے ہیں اور ہمارا مقصد ایک کم سے کم قابل عمل بوٹ ہے، لہذا ایک اور ہوم ورک اسائنمنٹ کے طور پر، آپ جو کچھ بھی دیکھا ہے اسے ری فییکٹر کر سکتے ہیں :) ایک util پیکیج بنائیں، اور اس میں - TelegramUtil کلاس :
package com.whiskels.telegram.util;

import com.whiskels.telegram.model.User;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.InlineKeyboardButton;

public class TelegramUtil {
    public static SendMessage createMessageTemplate(User user) {
        return createMessageTemplate(String.valueOf(user.getChatId()));
    }

    // Создаем шаблон SendMessage с включенным Markdown
    public static SendMessage createMessageTemplate(String chatId) {
        return new SendMessage()
                .setChatId(chatId)
                .enableMarkdown(true);
    }

    // Создаем кнопку
    public static InlineKeyboardButton createInlineKeyboardButton(String text, String command) {
        return new InlineKeyboardButton()
                .setText(text)
                .setCallbackData(command);
    }
}
ہم چار ہینڈلر لکھیں گے: ہیلپ ہینڈلر، کوئز ہینڈلر، رجسٹریشن ہینڈلر، اسٹارٹ ہینڈلر۔ StartHandler:
package com.whiskels.telegram.bot.handler;

import com.whiskels.telegram.bot.State;
import com.whiskels.telegram.model.User;
import com.whiskels.telegram.repository.JpaUserRepository;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.telegram.telegrambots.meta.api.methods.PartialBotApiMethod;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;

import java.io.Serializable;
import java.util.Collections;
import java.util.List;

import static com.whiskels.telegram.util.TelegramUtil.createMessageTemplate;

@Component
public class StartHandler implements Handler {
    @Value("${bot.name}")
    private String botUsername;

    private final JpaUserRepository userRepository;

    public StartHandler(JpaUserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public List<partialbotapimethod<? extends="" serializable="">> handle(User user, String message) {
        // Приветствуем пользователя
        SendMessage welcomeMessage = createMessageTemplate(user)
                .setText(String.format(
                        "Hola! I'm *%s*%nI am here to help you learn Java", botUsername
                ));
        // Просим назваться
        SendMessage registrationMessage = createMessageTemplate(user)
                .setText("In order to start our journey tell me your name");
        // Меняем пользователю статус на - "ожидание ввода имени"
        user.setBotState(State.ENTER_NAME);
        userRepository.save(user);

        return List.of(welcomeMessage, registrationMessage);
    }

    @Override
    public State operatedBotState() {
        return State.START;
    }

    @Override
    public List<string> operatedCallBackQuery() {
        return Collections.emptyList();
    }
}

</string></partialbotapimethod<?>
رجسٹریشن ہینڈلر:
package com.whiskels.telegram.bot.handler;

import com.whiskels.telegram.bot.State;
import com.whiskels.telegram.model.User;
import com.whiskels.telegram.repository.JpaUserRepository;
import org.springframework.stereotype.Component;
import org.telegram.telegrambots.meta.api.methods.PartialBotApiMethod;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.InlineKeyboardMarkup;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.InlineKeyboardButton;

import java.io.Serializable;
import java.util.List;

import static com.whiskels.telegram.bot.handler.QuizHandler.QUIZ_START;
import static com.whiskels.telegram.util.TelegramUtil.createInlineKeyboardButton;
import static com.whiskels.telegram.util.TelegramUtil.createMessageTemplate;

@Component
public class RegistrationHandler implements Handler {
    //Храним поддерживаемые CallBackQuery в виде констант
    public static final String NAME_ACCEPT = "/enter_name_accept";
    public static final String NAME_CHANGE = "/enter_name";
    public static final String NAME_CHANGE_CANCEL = "/enter_name_cancel";

    private final JpaUserRepository userRepository;

    public RegistrationHandler(JpaUserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public List<partialbotapimethod<? extends="" serializable="">> handle(User user, String message) {
        // Проверяем тип полученного события
        if (message.equalsIgnoreCase(NAME_ACCEPT) || message.equalsIgnoreCase(NAME_CHANGE_CANCEL)) {
            return accept(user);
        } else if (message.equalsIgnoreCase(NAME_CHANGE)) {
            return changeName(user);
        }
        return checkName(user, message);

    }

    private List<partialbotapimethod<? extends="" serializable="">> accept(User user) {
        // Если пользователь принял Name - меняем статус и сохраняем
        user.setBotState(State.NONE);
        userRepository.save(user);

        // Создаем кнопку для начала игры
        InlineKeyboardMarkup inlineKeyboardMarkup = new InlineKeyboardMarkup();

        List<inlinekeyboardbutton> inlineKeyboardButtonsRowOne = List.of(
                createInlineKeyboardButton("Start quiz", QUIZ_START));

        inlineKeyboardMarkup.setKeyboard(List.of(inlineKeyboardButtonsRowOne));

        return List.of(createMessageTemplate(user).setText(String.format(
                "Your name is saved as: %s", user.getName()))
                .setReplyMarkup(inlineKeyboardMarkup));
    }

    private List<partialbotapimethod<? extends="" serializable="">> checkName(User user, String message) {
        // При проверке имени мы превентивно сохраняем пользователю новое Name в базе
        // идея для рефакторинга - добавить временное хранение имени
        user.setName(message);
        userRepository.save(user);

        // Doing кнопку для применения изменений
        InlineKeyboardMarkup inlineKeyboardMarkup = new InlineKeyboardMarkup();

        List<inlinekeyboardbutton> inlineKeyboardButtonsRowOne = List.of(
                createInlineKeyboardButton("Accept", NAME_ACCEPT));

        inlineKeyboardMarkup.setKeyboard(List.of(inlineKeyboardButtonsRowOne));

        return List.of(createMessageTemplate(user)
                .setText(String.format("You have entered: %s%nIf this is correct - press the button", user.getName()))
                .setReplyMarkup(inlineKeyboardMarkup));
    }

    private List<partialbotapimethod<? extends="" serializable="">> changeName(User user) {
        // При requestе изменения имени мы меняем State
        user.setBotState(State.ENTER_NAME);
        userRepository.save(user);

        // Создаем кнопку для отмены операции
        InlineKeyboardMarkup inlineKeyboardMarkup = new InlineKeyboardMarkup();

        List<inlinekeyboardbutton> inlineKeyboardButtonsRowOne = List.of(
                createInlineKeyboardButton("Cancel", NAME_CHANGE_CANCEL));

        inlineKeyboardMarkup.setKeyboard(List.of(inlineKeyboardButtonsRowOne));

        return List.of(createMessageTemplate(user).setText(String.format(
                "Your current name is: %s%nEnter new name or press the button to continue", user.getName()))
                .setReplyMarkup(inlineKeyboardMarkup));
    }

    @Override
    public State operatedBotState() {
        return State.ENTER_NAME;
    }

    @Override
    public List<string> operatedCallBackQuery() {
        return List.of(NAME_ACCEPT, NAME_CHANGE, NAME_CHANGE_CANCEL);
    }
}

</string></inlinekeyboardbutton></partialbotapimethod<?></inlinekeyboardbutton></partialbotapimethod<?></inlinekeyboardbutton></partialbotapimethod<?></partialbotapimethod<?>
ہیلپ ہینڈلر:
package com.whiskels.telegram.bot.handler;

import com.whiskels.telegram.bot.State;
import com.whiskels.telegram.model.User;
import org.springframework.stereotype.Component;
import org.telegram.telegrambots.meta.api.methods.PartialBotApiMethod;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.InlineKeyboardMarkup;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.InlineKeyboardButton;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static com.whiskels.telegram.bot.handler.RegistrationHandler.NAME_CHANGE;
import static com.whiskels.telegram.util.TelegramUtil.createInlineKeyboardButton;
import static com.whiskels.telegram.util.TelegramUtil.createMessageTemplate;

@Component
public class HelpHandler implements Handler {

    @Override
    public List<partialbotapimethod<? extends="" serializable="">> handle(User user, String message) {
        // Создаем кнопку для смены имени
        InlineKeyboardMarkup inlineKeyboardMarkup = new InlineKeyboardMarkup();

        List<inlinekeyboardbutton> inlineKeyboardButtonsRowOne = List.of(
                createInlineKeyboardButton("Change name", NAME_CHANGE));

        inlineKeyboardMarkup.setKeyboard(List.of(inlineKeyboardButtonsRowOne));

        return List.of(createMessageTemplate(user).setText(String.format("" +
                "You've asked for help %s? Here it comes!", user.getName()))
        .setReplyMarkup(inlineKeyboardMarkup));

    }

    @Override
    public State operatedBotState() {
        return State.NONE;
    }

    @Override
    public List<string> operatedCallBackQuery() {
        return Collections.emptyList();
    }
}

</string></inlinekeyboardbutton></partialbotapimethod<?>
کوئز ہینڈلر (بدترین
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION