JavaRush /جاوا بلاگ /Random-SD /Spring Boot Pt.2: Quiz Bot استعمال ڪندي ٽيليگرام بوٽ ٺاهڻ...
Whiskels
سطح
Москва

Spring Boot Pt.2: Quiz Bot استعمال ڪندي ٽيليگرام بوٽ ٺاهڻ

گروپ ۾ شايع ٿيل
حصو 1 الوها! پوئين آرٽيڪل ۾، اسان هڪ سادو بوٽ ٺاهيو جيڪو اسان کي ڪنهن به تقريب ۾ ڀليڪار ڪيو. اسان اڳ ۾ ئي ڪوڊ جون هزارين لائينون لکي چڪا آهيون، ۽ اهو وقت آهي اسان جي بوٽ ۾ وڌيڪ پيچيده ڪارڪردگي شامل ڪرڻ جو. اڄ اسان ڪوشش ڪنداسين ته هڪ سادو بوٽ لکڻ جي ته جيئن اسان جي فارغ وقت ۾ اسان جاوا ڪور جي پنهنجي ڄاڻ کي انٽرويو کان اڳ حاصل ڪري سگهون (حيراني ڳالهه اها آهي ته مون کي هن قسم جو هڪ به ڪم ڪندڙ بوٽ نه مليو آهي). هن کي ڪرڻ لاءِ اسان هيٺيون ڪم ڪنداسين:
  • هيروڪو کي ٻاهرين پوسٽ گريس ڊيٽابيس سان ڳنڍيو؛
  • اچو ته ڊيٽابيس کي شروع ڪرڻ ۽ آباد ڪرڻ لاءِ اسان جون پھريون اسڪرپٽ لکون؛
  • اچو ته ڊيٽابيس سان ڪم ڪرڻ لاءِ اسپرنگ بوٽ ڊيٽا JPA کي ڳنڍيون؛
  • اسان بوٽ جي رويي جي مختلف منظرنامي تي عمل ڪندا آهيون.
جيڪڏھن اھو توھان لاءِ دلچسپ آھي، ۽ مضمون پڙھڻ کان پوءِ توھان نه ٿا چاھيو سڙيل ٽماڪن کي اُڇليو، پوءِ منھنجي ذخيري ۾ ھڪڙو تارو وجھو ، مان خوش ٿيندس! جيڪڏهن توهان وٽ ڪي سوال آهن، اسان انهن تي تبصرن ۾ بحث ڪنداسين. اھو اھو آھي جيڪو اسان آخر ۾ حاصل ڪنداسين: Spring Boot Pt.2 استعمال ڪندي ٽيليگرام بوٽ ٺاهڻ: Quiz Bot - 1Spring Boot Pt.2 استعمال ڪندي ٽيليگرام بوٽ ٺاهڻ: Quiz Bot - 2Spring Boot Pt.2 استعمال ڪندي ٽيليگرام بوٽ ٺاهڻ: Quiz Bot - 3<h2>سو، اچو ته ھلون!</h2><h3>ھيروڪو تي ڊيٽابيس ٺاھيو</h3>اچو پنھنجي پھرين خارجي ڊيٽابيس ٺاھڻ سان شروع ڪريون. مقامي ڪم لاءِ، مان چيڪ ڪرڻ جي صلاح ڏيان ٿو pgAdmin . پر مان چاهيان ٿو ته توهان هن حقيقت کان رهنمائي حاصل ڪريو ته مستقبل ۾ توهان بوٽ کي هيروڪو تي لڳايو ته جيئن اهو توهان جي مقامي مشين تي منحصر نه ٿئي، ۽ ان لاءِ اچو ته هن خدمت کان واقف ٿي وڃون. طريقو:
  • Heroku تي رجسٽر ٿيو ؛
  • اسان جي ڊيش بورڊ ڏانھن وڃو -> نئون -> نئون ايپ ٺاھيو ۽ نئين ايپليڪيشن ٺاھيو؛
  • اسان نئين ٺاهيل ايپليڪيشن ۾ وڃون ٿا، اسان ڪيترن ئي بٽڻن کان ڊڄي ويا آهيون، پر اسان "انسٽال ٿيل ايڊ آنز" پينل تي ڌيان ڏيون ٿا - ان جي اڳيان هڪ ايڊڊ آنز کي ترتيب ڏيڻ وارو بٽڻ آهي، اسان ان کي ڪلڪ ڪندا آهيون؛
  • داخل ڪريو "Heroku Postgres" ڳولا ۾، چونڊيو "شوق ديو - مفت" منصوبو -> آرڊر فارم جمع ڪريو؛
  • نئون حاصل ڪيل ڊيٽابيس کوليو -> سيٽنگون -> ڏسو سندون. هي ٽيب ڊيٽابيس تائين رسائي حاصل ڪرڻ لاءِ اسان جي ڪنجين تي مشتمل هوندو. اسان کي انهن جو مقام ياد آهي - اسان کي انهن جي ضرورت پوندي ڊيٽابيس کي ڳنڍڻ لاءِ، جهڙوڪ IDEA ۾ DataSource.
<h3>pom.xml تي انحصار شامل ڪريو</h3>اسان جي بوٽ تي ڪم ڪرڻ جي حصي جي طور تي، اسان پنھنجي پوم ۾ ھيٺيون انحصار شامل ڪنداسين: Lombok، Spring Boot Data JPA، PostgreSQL. رکو! هي سڀ ڇا آهي ۽ اسان ان کي ڇو شامل ڪري رهيا آهيون؟
  • Lombok هڪ لائبريري آهي جنهن جي مهرباني جنهن ۾ اسان مختلف ڪوڊ جي مقدار کي گھٽائي ڇڏيندو. ان سان گڏ اسان پاڻمرادو ٺاھي سگھون ٿا ٺاھيندڙ، سيٽر، گيٽر ۽ گھڻو ڪجھ.
  • اسپرنگ ڊيٽا JPA ڊيٽابيس سان ڪم ڪرڻ لاءِ هڪ فريم ورڪ آهي (جيتوڻيڪ اهو آواز تمام سادو آهي). بهار جي ڊيٽا JPA جي صلاحيتن جي وضاحت مضمونن جي هڪ سيريز جي برابر هوندي، ۽ انحصار جيڪو اسان بيان ڪيو آهي اهو پڻ شامل آهي Hibernate ۽ گهڻو ڪجهه، تنهنڪري اچو ته تفصيل کي ڇڏي ڏيو ۽ صرف اسپرنگ JPA استعمال ڪندي ڪجهه لکڻ جي ڪوشش ڪريو اڄ.
  • PostgreSQL - اسان هڪ ڊرائيور حاصل ڪرڻ لاء لائبريري کي ڇڪيندا آهيون جيڪو اسان جي ڊيٽابيس سان ڪم ڪندو.
اسان جو pom.xml هن طرح ڏسڻ شروع ٿئي ٿو: پراپرٽيز: Spring Boot Pt.2 استعمال ڪندي ٽيليگرام بوٽ ٺاهڻ: Quiz Bot - 1انحصار: Spring Boot Pt.2 استعمال ڪندي ٽيليگرام بوٽ ٺاهڻ: Quiz Bot - 2جيڪڏهن توهان اڳوڻو مضمون نه پڙهيو آهي، مهرباني ڪري نوٽ ڪريو ته اسان هتي نوان انحصار شامل ڪري رهيا آهيون، تنهنڪري هي مڪمل pom.xml جوڙجڪ ناهي. انهن انحصار کي اسان جي پروجيڪٽ ۾ لوڊ ڪرڻ نه وساريو (مثال طور، Maven ڏانهن وڃڻ سان -> Reimport all Maven پروجيڪٽس ونڊو).<h3>ڊيٽابيس کي IDEA ۾ ڳنڍڻ</h3>جيڪڏهن توهان IDEA ڪميونٽي ايڊيشن استعمال ڪندا آهيو، توهان ڪري سگهو ٿا. DataSource ٽيب کي ھيٺ ڏنل طور تي فعال ڪريو . پلگ ان کي شامل ڪرڻ کان پوء، اسان کي ڊيٽا سورس کي ترتيب ڏيڻ جي ضرورت آھي. هن کي ڪرڻ لاء، پهريان پلگ ان ڊسپلي کي فعال ڪريو: ڏسو -> اوزار ونڊوز -> ڊي بي برائوزر. ونڊو ۾ جيڪو کلي ٿو، سائي پلس تي ڪلڪ ڪريو (نئون ڪنيڪشن) -> PostgreSQL. هتي اسان کي سند جي ضرورت پوندي، جيڪا اسان اڳ ۾ ئي هيروڪو تي ڏٺي آهي. ونڊو ڀريو: Spring Boot Pt.2 استعمال ڪندي ٽيليگرام بوٽ ٺاهڻ: Quiz Bot - 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
);
اسان جي رسم الخط ڇا ڪندو؟ پهرين ٻه لائينون ميز کي ختم ڪن ٿيون، جيڪڏهن موجود آهن، انهن کي ٻيهر ٺاهڻ لاء. ٽين لائين ھڪڙي ترتيب ٺاھي ٿي جيڪا اسان جي ڊيٽابيس ۾ منفرد id داخل ڪرڻ لاء استعمال ڪئي ويندي. اڳيون اسان ٻه جدول ٺاھيون ٿا: صارفين لاءِ ۽ سوالن لاءِ. صارف وٽ هڪ منفرد آئي ڊي، ٽيليگرام چيٽ جي سڃاڻپ، نالو، پوائنٽن جو تعداد (موجوده ۽ وڌ ۾ وڌ)، ۽ انهي سان گڏ بوٽ جي موجوده حيثيت. سوالن ۾ به هڪ منفرد آئي ڊي هوندي، انهي سان گڏ فيلڊز به ان لاءِ سوال ۽ جواب جي آپشن جا ذميوار هوندا. اسان نتيجن واري اسڪرپٽ تي عمل ڪري سگھون ٿا ان تي صحيح ڪلڪ ڪري ۽ "Execute SQL Script" کي چونڊيو. خاص ڌيان ڏيڻ گهرجي "Cmd-Line انٽرفيس" شيءِ تي - هتي اسان کي تازو انسٽال ٿيل PostgreSQL جي ضرورت پوندي. جڏهن هن فيلڊ کي ترتيب ڏيو، "نئون Cmd-Line انٽرفيس" چونڊيو ۽ psql.exe ڏانهن رستو بيان ڪريو. نتيجي طور، سيٽنگون ڪجهه هن طرح ڏسڻ گهرجن: Spring Boot Pt.2 استعمال ڪندي ٽيليگرام بوٽ ٺاهڻ: Quiz Bot - 4اسان اسڪرپٽ تي عمل ڪيو ۽ جيڪڏهن اسان ڪٿي به غلطي نه ڪئي آهي، اسان جي ڪم جو نتيجو هن ريت ٿيندو: Spring Boot Pt.2 استعمال ڪندي ٽيليگرام بوٽ ٺاهڻ: Quiz Bot - 8<h3>هڪ ماڊل ٺاهيو</h3>هاڻي اهو وقت آهي جاوا ڪوڊ لکڻ لاءِ واپس وڃڻ لاءِ. مضمون کي مختصر ڪرڻ لاءِ، مان ڪلاسن کي لکڻ لاءِ استعمال ٿيندڙ تشريحن جي وضاحت کي ڇڏي ڏيندس ته جيئن توهان انهن سان پاڻ کي واقف ڪري سگهو. اچو ته هڪ ماڊل پيڪيج ٺاهيون جنهن ۾ اسان وٽ ٽي طبقا هوندا:
  • AbstractBaseEntity ھڪڙو طبقو آھي جيڪو بيان ڪري ٿو ڪنھن شئي کي جنھن جي سڃاڻپ ٿي سگھي ٿي (ھي ڪلاس ھڪڙو مضبوط سادو آھي جيڪو توھان انٽرنشپ ۾ ڏسي سگھو ٿا):
    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>هاڻي اچو ته لکون Spring Data Jpa repositories. اسان هڪ ريپوزٽري پيڪيج ٺاهيندا آهيون جنهن ۾ ٻه انٽرفيس هوندا : 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)؛ حقيقت ۾ اهي هن طرح نظر اچن ٿا، پر ڪوڊ فارميٽ انهن کي ٽوڙي ڇڏيو:اسپرنگ بوٽ Pt.2 استعمال ڪندي ٽيليگرام بوٽ ٺاهڻ: Quiz Bot - 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>
۽ اسان ان کي Bot ڪلاس ۾ پروسيسنگ جو نمائندو ڏيون ٿا:
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 ڪوڊ) مختلف نمونن کي استعمال ڪندي تمام سٺو ريفڪٽر ٿي سگهي ٿو. پر اسان سکي رهيا آهيون ۽ اسان جو مقصد گهٽ ۾ گهٽ قابل عمل بوٽ آهي، تنهنڪري هڪ ٻي هوم ورڪ اسائنمينٽ جي طور تي، توهان هر شيءِ کي ريفيڪٽر ڪري سگهو ٿا جيڪو توهان ڏٺو :) يوٽيل پيڪيج ٺاهيو، ۽ ان ۾ - ٽيليگرام يوٽيل ڪلاس :
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);
    }
}
اسان چار هينڊلر لکنداسين: HelpHandler، QuizHandler، RegistrationHandler، StartHandler. 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<?>
QuizHandler (بدترين
تبصرا
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION