JavaRush /Java Blog /Random-JA /記事のグループを購読する機能を追加しています。(パート 2) - 「Java プロジェクトの A から Z まで」...
Roman Beekeeper
レベル 35

記事のグループを購読する機能を追加しています。(パート 2) - 「Java プロジェクトの A から Z まで」

Random-JA グループに公開済み
こんにちは、みんな!私たちは先週始めたタスクに引き続き取り組んでいます。「Java プロジェクト A to Z」: 記事のグループを購読する機能を追加します。 パート 2 - 1

JRTB-5を実装します

次に、JavaRush から記事のグループを購読できるようにコマンドを追加する必要があります。どうやってするの?私が思いついた最も単純なシナリオに従います。グループIDでアクセスできるので、ユーザーに転送してもらう必要があります。これを行うには、ユーザーはコマンド/addGroupSub GROUP_ID を入力します。これは 2 つの方法のいずれかで機能します。コマンド自体のみが来る場合: /addGroupSub、すべてのグループとその ID のリストが応答として送信されます。その後、ユーザーは必要なグループ ID を選択し、コマンド/addGroupSub GROUP_IDでリクエストの 2 番目のバージョンを作成できるようになります。これにより、このユーザーのこのグループのエントリが作成されます。将来的にはもっと良くできると思います。私たちの目標は開発状況を示すことであり、非常にクールなユーザー エクスペリエンスを示すことではありません(恥ずかしいことに、これを意味するロシア語の用語がわかりません)。アプリケーション全体 (この場合、テレグラム ボット クライアントからデータベースまで) を通過する機能を適切に追加するには、どこかの端から開始する必要があります。これをデータベース側から実行します。

データベースへの新しい移行の追加

最初に行うことは、新しいデータベースの移行と、ユーザー グループのサブスクリプション データを JR に保存する機能を追加することです。どのようにすべきかを思い出すには、「プロジェクト計画: 7 回測定する」の記事に戻ってください。2 番目の写真には、データベースの概略図があります。グループ情報を保存するテーブルを追加する必要があります。
  • JavaRushのグループIDも弊社のIDとなります。私たちは彼らを信頼しており、これらの ID は一意であると信じています。
  • タイトル - 私たちの写真では名前でした - グループの非公式の名前。つまり、JavaRush Web サイトで見られるものです。
  • last_article_id - これは興味深いフィールドです。これには、ボットがすでに購読者に送信した、このグループ内の記事の最後の ID が保存されます。このフィールドを使用すると、新しい記事を検索するメカニズムが機能します。新しい購読者は、ユーザーが購読する前に公開された記事を受け取ることはできません。グループに購読した後に公開された記事のみを受け取ります。
また、各ユーザーは多数のグループ サブスクリプション (1 対多) を持つことができ、各グループ サブスクリプションは多くのユーザー (1 対多のみ) を持つことができるため、グループとユーザー テーブルの間に多対多の関係が存在します。反対側にあります)。これは多対多になることがわかります。質問がある場合は、データベース内の記事を確認してください。はい、近々 Telegram チャネルに投稿を作成し、データベース上のすべての記事をまとめる予定です。2 回目のデータベース移行は次のようになります。
V00002__created_groupsub_many_to_many.sql:

-- add PRIMARY KEY FOR tg_user
ALTER TABLE tg_user ADD PRIMARY KEY (chat_id);

-- ensure that the tables with these names are removed before creating a new one.
DROP TABLE IF EXISTS group_sub;
DROP TABLE IF EXISTS group_x_user;

CREATE TABLE group_sub (
   id INT,
   title VARCHAR(100),
   last_article_id INT,
   PRIMARY KEY (id)
);

CREATE TABLE group_x_user (
   group_sub_id INT NOT NULL,
   user_id VARCHAR(100) NOT NULL,
   FOREIGN KEY (user_id) REFERENCES tg_user(chat_id),
   FOREIGN KEY (group_sub_id) REFERENCES group_sub(id),
   UNIQUE(user_id, group_sub_id)
);
最初に古いテーブルを変更し、そこに主キーを追加することに注意することが重要です。当時はどういうわけかこれを見逃していましたが、現在、MySQL では gorup_x_user テーブルに FOREIGN KEY を追加する機会が与えられていないため、この移行の一環としてデータベースを更新しました。重要な点にご注意ください。データベースの変更は、まさにこの方法で行う必要があります。必要なものはすべて新しい移行に含まれますが、すでにリリースされた移行を更新することではありません。はい、これはテスト プロジェクトであり、1 か所のみにデプロイされることがわかっているため、この場合は何も起こりませんが、これは間違ったアプローチになります。しかし、私たちはすべてが正しくあることを望んでいます。次に、テーブルを作成する前にテーブルを削除します。どうしてこれなの?そのため、データベース内にそのような名前のテーブルが万が一存在したとしても、移行は失敗せず、期待どおりに正確に機能します。次に、テーブルを 2 つ追加します。すべてが私たちの希望通りでした。次に、アプリケーションを起動する必要があります。すべてが開始され、中断しなければ、移行は記録されます。これを再確認するために、データベースにアクセスして次のことを確認します。 a) そのようなテーブルが存在すること。b) フライウェイ技術表に新しい項目が追加されました。これで移行作業は完了です。リポジトリに進みましょう。

リポジトリ層の追加

Spring Boot Data のおかげで、ここではすべてが非常に簡単です。GroupSub エンティティを追加し、TelegramUser をわずかに更新し、ほぼ空の GroupSubRepository を追加する必要があります。GroupSub エンティティを TelegramUser と同じパッケージに追加します。
package com.github.javarushcommunity.jrtb.repository.entity;

import lombok.Data;
import lombok.EqualsAndHashCode;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

import static java.util.Objects.isNull;

@Data
@Entity
@Table(name = "group_sub")
@EqualsAndHashCode
public class GroupSub {

   @Id
   private Integer id;

   @Column(name = "title")
   private String title;

   @Column(name = "last_article_id")
   private Integer lastArticleId;

   @ManyToMany(fetch = FetchType.EAGER)
   @JoinTable(
           name = "group_x_user",
           joinColumns = @JoinColumn(name = "group_sub_id"),
           inverseJoinColumns = @JoinColumn(name = "user_id")
   )
   private List<TelegramUser> users;

   public void addUser(TelegramUser telegramUser) {
       if (isNull(users)) {
           users = new ArrayList<>();
       }
       users.add(telegramUser);
   }
}
注目すべき点の 1 つは、グループに登録しているすべてのユーザーのコレクションを含む追加のユーザー フィールドがあることです。そして、2 つのアノテーション (ManyToMany と JoinTable) がまさにこのために必要なものです。TelegramUser にも同じフィールドを追加する必要があります。
@ManyToMany(mappedBy = "users", fetch = FetchType.EAGER)
private List<GroupSub> groupSubs;
このフィールドは、GroupSub エンティティに記述された結合を使用します。そして実際、GroupSub のリポジトリ クラスはGroupSubRepositoryです。
package com.github.javarushcommunity.jrtb.repository;

import com.github.javarushcommunity.jrtb.repository.entity.GroupSub;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

/**
* {@link Repository} for {@link GroupSub} entity.
*/
@Repository
public interface GroupSubRepository extends JpaRepository<GroupSub, Integer> {
}
この段階では、追加のメソッドは必要ありません。JpaRepository の先祖に実装されているメソッドで十分です。TelegramUserRepositoryIT で多対多が機能することを確認するテストを作成しましょう。テストの目的は、SQL スクリプトを通じてユーザーごとに 5 つのサブスクリプション グループをデータベースに追加し、ID でこのユーザーを取得し、それらのグループとまったく同じ値を受信したことを確認することです。どうやってするの?データにカウンターを埋め込むことができ、それを調べてチェックすることができます。FiveGroupSubsForUser.sql スクリプトは次のとおりです。
INSERT INTO tg_user VALUES (1, 1);

INSERT INTO group_sub VALUES
(1, 'g1', 1),
(2, 'g2', 2),
(3, 'g3', 3),
(4, 'g4', 4),
(5, 'g5', 5);

INSERT INTO group_x_user VALUES
(1, 1),
(2, 1),
(3, 1),
(4, 1),
(5, 1);
そしてテスト自体:
@Sql(scripts = {"/sql/clearDbs.sql", "/sql/fiveGroupSubsForUser.sql"})
@Test
public void shouldProperlyGetAllGroupSubsForUser() {
   //when
   Optional<TelegramUser> userFromDB = telegramUserRepository.findById("1");

   //then
   Assertions.assertTrue(userFromDB.isPresent());
   List<GroupSub> groupSubs = userFromDB.get().getGroupSubs();
   for (int i = 0; i < groupSubs.size(); i++) {
       Assertions.assertEquals(String.format("g%s", (i + 1)), groupSubs.get(i).getTitle());
       Assertions.assertEquals(i + 1, groupSubs.get(i).getId());
       Assertions.assertEquals(i + 1, groupSubs.get(i).getLastArticleId());
   }
}
次に、GroupSub エンティティに対して同じ意味のテストを追加しましょう。これを行うには、 groupSubRepositoryITと同じパッケージ内にテスト クラスgroupSubRepositoryITを作成しましょう。
package com.github.javarushcommunity.jrtb.repository;

import com.github.javarushcommunity.jrtb.repository.entity.GroupSub;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.jdbc.Sql;

import java.util.List;
import java.util.Optional;

import static org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace.NONE;

/**
* Integration-level testing for {@link GroupSubRepository}.
*/
@ActiveProfiles("test")
@DataJpaTest
@AutoConfigureTestDatabase(replace = NONE)
public class GroupSubRepositoryIT {

   @Autowired
   private GroupSubRepository groupSubRepository;

   @Sql(scripts = {"/sql/clearDbs.sql", "/sql/fiveUsersForGroupSub.sql"})
   @Test
   public void shouldProperlyGetAllUsersForGroupSub() {
       //when
       Optional<GroupSub> groupSubFromDB = groupSubRepository.findById(1);

       //then
       Assertions.assertTrue(groupSubFromDB.isPresent());
       Assertions.assertEquals(1, groupSubFromDB.get().getId());
       List<TelegramUser> users = groupSubFromDB.get().getUsers();
       for(int i=0; i<users.size(); i++) {
           Assertions.assertEquals(String.valueOf(i + 1), users.get(i).getChatId());
           Assertions.assertTrue(users.get(i).isActive());
       }
   }
}
そして欠落している FiveUsersForGroupSub.sql スクリプト:
INSERT INTO tg_user VALUES
(1, 1),
(2, 1),
(3, 1),
(4, 1),
(5, 1);

INSERT INTO group_sub VALUES (1, 'g1', 1);

INSERT INTO group_x_user VALUES
(1, 1),
(1, 2),
(1, 3),
(1, 4),
(1, 5);
この時点で、リポジトリでの作業の一部が完了したと見なすことができます。次に、サービス層を作成しましょう。

GroupSubService を書きます

この段階で、サブスクリプションのグループを操作するには、それらを保存できれば問題ありません。GroupSubService サービスとその GroupSubServiceImpl の実装を、他のサービスを含むパッケージ内に作成します。service:
package com.github.javarushcommunity.jrtb.service;

import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupDiscussionInfo;
import com.github.javarushcommunity.jrtb.repository.entity.GroupSub;

/**
* Service for manipulating with {@link GroupSub}.
*/
public interface GroupSubService {

   GroupSub save(String chatId, GroupDiscussionInfo groupDiscussionInfo);
}
そしてその実装:
package com.github.javarushcommunity.jrtb.service;

import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupDiscussionInfo;
import com.github.javarushcommunity.jrtb.repository.GroupSubRepository;
import com.github.javarushcommunity.jrtb.repository.entity.GroupSub;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.ws.rs.NotFoundException;
import java.util.Optional;

@Service
public class GroupSubServiceImpl implements GroupSubService {

   private final GroupSubRepository groupSubRepository;
   private final TelegramUserService telegramUserService;

   @Autowired
   public GroupSubServiceImpl(GroupSubRepository groupSubRepository, TelegramUserService telegramUserService) {
       this.groupSubRepository = groupSubRepository;
       this.telegramUserService = telegramUserService;
   }

   @Override
   public GroupSub save(String chatId, GroupDiscussionInfo groupDiscussionInfo) {
       TelegramUser telegramUser = telegramUserService.findByChatId(chatId).orElseThrow(NotFoundException::new);
       //TODO add exception handling
       GroupSub groupSub;
       Optional<GroupSub> groupSubFromDB = groupSubRepository.findById(groupDiscussionInfo.getId());
       if(groupSubFromDB.isPresent()) {
           groupSub = groupSubFromDB.get();
           Optional<TelegramUser> first = groupSub.getUsers().stream()
                   .filter(it -> it.getChatId().equalsIgnoreCase(chatId))
                   .findFirst();
           if(first.isEmpty()) {
               groupSub.addUser(telegramUser);
           }
       } else {
           groupSub = new GroupSub();
           groupSub.addUser(telegramUser);
           groupSub.setId(groupDiscussionInfo.getId());
           groupSub.setTitle(groupDiscussionInfo.getTitle());
       }
       return groupSubRepository.save(groupSub);
   }
}
Spring Data が正しく機能し、多対多のレコードを作成するには、作成しているサブスクリプション グループのユーザーをデータベースから取得し、GroupSub オブジェクトに追加する必要があります。したがって、このサブスクリプションを保存のために転送すると、group_x_user テーブルを介して接続も作成されます。このようなサブスクリプション グループがすでに作成されており、そこに別のユーザーを追加するだけで済む場合もあります。これを行うには、まずデータベースからグループ ID を取得し、レコードがある場合はそれを操作し、レコードがない場合は新しいレコードを作成します。TelegramUser を操作するには、最後の SOLID 原則に従って TelegramUserService を使用することに注意することが重要です。現時点では、ID でレコードが見つからない場合は、単に例外をスローします。現在、これはいかなる方法でも処理されていません。これは、MVP の前の最後の最後に処理されます。GroupSubServiceTestクラスの 2 つの単体テストを作成してみましょう。どれが必要ですか? Save メソッドが GroupSubRepository で呼び出され、単一のユーザーを持つエンティティが GroupSub に渡されることを確認したいと思います。このエンティティは、提供された ID を使用して TelegramUserService を返します。2 番目のオプションは、同じ ID を持つグループがデータベースにすでに存在し、このグループにすでに 1 人のユーザーが存在し、別のユーザーがこのグループに追加され、このオブジェクトが保存されることを確認する必要がある場合です。実装は次のとおりです。
package com.github.javarushcommunity.jrtb.service;

import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupDiscussionInfo;
import com.github.javarushcommunity.jrtb.repository.GroupSubRepository;
import com.github.javarushcommunity.jrtb.repository.entity.GroupSub;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import java.util.Optional;

@DisplayName("Unit-level testing for GroupSubService")
public class GroupSubServiceTest {

   private GroupSubService groupSubService;
   private GroupSubRepository groupSubRepository;
   private TelegramUser newUser;

   private final static String CHAT_ID = "1";

   @BeforeEach
   public void init() {
       TelegramUserService telegramUserService = Mockito.mock(TelegramUserService.class);
       groupSubRepository = Mockito.mock(GroupSubRepository.class);
       groupSubService = new GroupSubServiceImpl(groupSubRepository, telegramUserService);

       newUser = new TelegramUser();
       newUser.setActive(true);
       newUser.setChatId(CHAT_ID);

       Mockito.when(telegramUserService.findByChatId(CHAT_ID)).thenReturn(Optional.of(newUser));
   }

   @Test
   public void shouldProperlySaveGroup() {
       //given

       GroupDiscussionInfo groupDiscussionInfo = new GroupDiscussionInfo();
       groupDiscussionInfo.setId(1);
       groupDiscussionInfo.setTitle("g1");

       GroupSub expectedGroupSub = new GroupSub();
       expectedGroupSub.setId(groupDiscussionInfo.getId());
       expectedGroupSub.setTitle(groupDiscussionInfo.getTitle());
       expectedGroupSub.addUser(newUser);

       //when
       groupSubService.save(CHAT_ID, groupDiscussionInfo);

       //then
       Mockito.verify(groupSubRepository).save(expectedGroupSub);
   }

   @Test
   public void shouldProperlyAddUserToExistingGroup() {
       //given
       TelegramUser oldTelegramUser = new TelegramUser();
       oldTelegramUser.setChatId("2");
       oldTelegramUser.setActive(true);

       GroupDiscussionInfo groupDiscussionInfo = new GroupDiscussionInfo();
       groupDiscussionInfo.setId(1);
       groupDiscussionInfo.setTitle("g1");

       GroupSub groupFromDB = new GroupSub();
       groupFromDB.setId(groupDiscussionInfo.getId());
       groupFromDB.setTitle(groupDiscussionInfo.getTitle());
       groupFromDB.addUser(oldTelegramUser);

       Mockito.when(groupSubRepository.findById(groupDiscussionInfo.getId())).thenReturn(Optional.of(groupFromDB));

       GroupSub expectedGroupSub = new GroupSub();
       expectedGroupSub.setId(groupDiscussionInfo.getId());
       expectedGroupSub.setTitle(groupDiscussionInfo.getTitle());
       expectedGroupSub.addUser(oldTelegramUser);
       expectedGroupSub.addUser(newUser);

       //when
       groupSubService.save(CHAT_ID, groupDiscussionInfo);

       //then
       Mockito.verify(groupSubRepository).findById(groupDiscussionInfo.getId());
       Mockito.verify(groupSubRepository).save(expectedGroupSub);
   }

}
また、 BeforeEach アノテーションを備えたinit()メソッド も追加しました。このようにして、通常、各テストの実行前に実行されるメソッドを作成し、すべてのテストに共通のロジックを組み込むことができます。このケースでは、このクラスのすべてのテストで同じ方法で TelegramUserService をロックする必要があるため、このロジックを共通のメソッドに転送することは理にかなっています。ここでは 2 つの mokito デザインが使用されています。
  • Mockito.when(o1.m1(a1)).thenReturn(o2) - この中で、メソッドm1が引数a1を指定してオブジェクトo1に対して呼び出された場合、メソッドはオブジェクトo2を返すと述べています。これは、mockito のほぼ最も重要な機能です。モック オブジェクトに必要なものを正確に返させることです。

  • Mockito.verify(o1).m1(a1) -メソッドm1 が引数a1を使用してオブジェクトo1に対して呼び出されたことを検証します。もちろん、save メソッドの返されたオブジェクトを使用することも可能ですが、別の可能なメソッドを示すことで、もう少し複雑にすることにしました。いつ役立つでしょうか? モッククラスのメソッドが void を返す場合。Mockito.verify がないと動作しません)))

私たちは、テストは作成する必要があり、テストの多くは作成する必要があるという考えを堅持し続けています。次の段階は、電報ボット チームとの連携です。

コマンド /addGroupSub を作成します。

ここでは、次のロジックを実行する必要があります。コンテキストなしでコマンドだけを受け取った場合、ユーザーを支援し、ユーザーが必要な情報をボットに渡せるように、ID を含むすべてのグループのリストを提供します。また、ユーザーが他の単語を使用してコマンドをボットに送信した場合は、その ID を持つグループを見つけるか、そのようなグループは存在しないと書き込みます。ename に新しい値 (CommandName) を追加しましょう。
ADD_GROUP_SUB("/addgroupsub")
データベースからテレグラム ボットにさらに進みましょう。コマンド パッケージに AddGroupSubCommandクラスを作成します。
package com.github.javarushcommunity.jrtb.command;

import com.github.javarushcommunity.jrtb.javarushclient.JavaRushGroupClient;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupDiscussionInfo;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupRequestArgs;
import com.github.javarushcommunity.jrtb.repository.entity.GroupSub;
import com.github.javarushcommunity.jrtb.service.GroupSubService;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import org.telegram.telegrambots.meta.api.objects.Update;

import java.util.stream.Collectors;

import static com.github.javarushcommunity.jrtb.command.CommandName.ADD_GROUP_SUB;
import static com.github.javarushcommunity.jrtb.command.CommandUtils.getChatId;
import static com.github.javarushcommunity.jrtb.command.CommandUtils.getMessage;
import static java.util.Objects.isNull;
import static org.apache.commons.lang3.StringUtils.SPACE;
import static org.apache.commons.lang3.StringUtils.isNumeric;

/**
* Add Group subscription {@link Command}.
*/
public class AddGroupSubCommand implements Command {

   private final SendBotMessageService sendBotMessageService;
   private final JavaRushGroupClient javaRushGroupClient;
   private final GroupSubService groupSubService;

   public AddGroupSubCommand(SendBotMessageService sendBotMessageService, JavaRushGroupClient javaRushGroupClient,
                             GroupSubService groupSubService) {
       this.sendBotMessageService = sendBotMessageService;
       this.javaRushGroupClient = javaRushGroupClient;
       this.groupSubService = groupSubService;
   }

   @Override
   public void execute(Update update) {
       if (getMessage(update).equalsIgnoreCase(ADD_GROUP_SUB.getCommandName())) {
           sendGroupIdList(getChatId(update));
           return;
       }
       String groupId = getMessage(update).split(SPACE)[1];
       String chatId = getChatId(update);
       if (isNumeric(groupId)) {
           GroupDiscussionInfo groupById = javaRushGroupClient.getGroupById(Integer.parseInt(groupId));
           if (isNull(groupById.getId())) {
               sendGroupNotFound(chatId, groupId);
           }
           GroupSub savedGroupSub = groupSubService.save(chatId, groupById);
           sendBotMessageService.sendMessage(chatId, "Подписал на группу " + savedGroupSub.getTitle());
       } else {
           sendGroupNotFound(chatId, groupId);
       }
   }

   private void sendGroupNotFound(String chatId, String groupId) {
       String groupNotFoundMessage = "Нет группы с ID = \"%s\"";
       sendBotMessageService.sendMessage(chatId, String.format(groupNotFoundMessage, groupId));
   }

   private void sendGroupIdList(String chatId) {
       String groupIds = javaRushGroupClient.getGroupList(GroupRequestArgs.builder().build()).stream()
               .map(group -> String.format("%s - %s \n", group.getTitle(), group.getId()))
               .collect(Collectors.joining());

       String message = "Whatбы подписаться на группу - передай комадну вместе с ID группы. \n" +
               "Например: /addGroupSub 16. \n\n" +
               "я подготовил список всех групп - выберай Howую хочешь :) \n\n" +
               "Name группы - ID группы \n\n" +
               "%s";

       sendBotMessageService.sendMessage(chatId, String.format(message, groupIds));
   }
}
このクラスは、 Apache-commons ライブラリのisNumericメソッドを使用するので、それをメモリに追加しましょう。
<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-lang3</artifactId>
  <version>${apache.commons.version}</version>
</dependency>
プロパティ ブロックでは次のようになります。
<apache.commons.version>3.11</apache.commons.version>
このロジックはすべてクラス内にあります。注意深く読んでください。ご質問やご提案がございましたら、コメントにご記入ください。この後、コマンド マップの CommandContainer にコマンドを追加する必要があります。
.put(ADD_GROUP_SUB.getCommandName(), new AddGroupSubCommand(sendBotMessageService, javaRushGroupClient, groupSubService))
そしてすべてはこのチームのために。何らかの方法でこの機能をテストしたいのですが、今のところ実際に確認できるのはデータベース内だけです。パート 3 では、ユーザーがサブスクライブしているグループのリストを表示できるように、JRTB-6 からの変更を追加します。ここで、これらすべてを確認してみると良いでしょう。これを行うには、Telegram ですべてのアクションを実行し、データベースをチェックインします。テストを作成したので、すべて問題ないはずです。記事がかなり長くなったので、後でAddGroupSubCommandのテストを書き、忘れないようにコードにTODOを追加します。

結論

この記事では、データベースから始まり、ボットを使用するクライアントとの連携で終わる、アプリケーション全体を通じて機能を追加する作業について説明しました。通常、このようなタスクはプロジェクトを理解し、その本質を理解するのに役立ちます。それがどのように機能するかを理解してください。最近のトピックは簡単なものではありません。恥ずかしがらないでください。コメントに質問を書いてください。お答えできるように努めます。プロジェクトは気に入っていますか? Github でスターを付けてください。こうすることで、彼らがそのプロジェクトに興味を持っていることが明らかになり、私も嬉しくなります。よく言われるように、マスターは自分の仕事が評価されると常に喜びます。このコードには STEP_6 の 3 つの部分がすべて含まれており、この記事の前に利用できるようになります。それを知るにはどうすればよいでしょうか?簡単です。テレグラム チャンネルに参加してください。テレグラム ボットに関する記事に関するすべての情報が公開されています。読んでくれてありがとう!パート 3 はすでにここにあります。

シリーズのすべてのマテリアルのリストは、この記事の冒頭にあります。

コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION