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

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

Random-JA グループに公開済み
また会ったね。これは STEP_6 の最後の記事であり、 JRTB-6タスクへの機能の追加について説明します。前の 2 つの記事 (パート 1パート 2 ) で、必要なものはほぼすべて準備済みです。この部分はプロセスの頂点です。この連載を最初からここまで読んでくださった皆様、大変敬意を表します。これは、あなたが素晴らしい仕事を見つけるのに十分な動機を持っていることを意味します。さて、本題に入りましょう。「Java プロジェクト A to Z」: 記事のグループを購読する機能を追加します。 パート 3 - 1

JRTB-6を実装します

今回は、データベースの更新作業がすべて完了し、データベース エンティティが構成され、作業の準備ができているため、テレグラム ボット側からタスクを実行します。CommandName - LIST_GROUP_SUBに新しい値を追加しましょう。
LIST_GROUP_SUB("/listGroupSub");
ListGroupSubCommand コマンドを作成しましょう。
package com.github.javarushcommunity.jrtb.command;

import com.github.javarushcommunity.jrtb.repository.entity.GroupSub;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import org.telegram.telegrambots.meta.api.objects.Update;

import javax.ws.rs.NotFoundException;
import java.util.stream.Collectors;

import static com.github.javarushcommunity.jrtb.command.CommandUtils.getChatId;

/**
* {@link Command} for getting list of {@link GroupSub}.
*/
public class ListGroupSubCommand implements Command {

   private final SendBotMessageService sendBotMessageService;
   private final TelegramUserService telegramUserService;

   public ListGroupSubCommand(SendBotMessageService sendBotMessageService, TelegramUserService telegramUserService) {
       this.sendBotMessageService = sendBotMessageService;
       this.telegramUserService = telegramUserService;
   }

   @Override
   public void execute(Update update) {
       //todo add exception handling
       TelegramUser telegramUser = telegramUserService.findByChatId(getChatId(update))
               .orElseThrow(NotFoundException::new);

       String message = "Я нашел все подписки на группы: \n\n";
       String collectedGroups = telegramUser.getGroupSubs().stream()
               .map(it -> "Группа: " + it.getTitle() + " , ID = " + it.getId() + " \n")
               .collect(Collectors.joining());

       sendBotMessageService.sendMessage(telegramUser.getChatId(), message + collectedGroups);
   }
}
ここではすべてが可能な限り単純です。既存の chat_id を使用してユーザーを取得し、そのユーザーのグループへのすべてのサブスクリプションがそのオブジェクトに収集されます。これを第 2 部で設定します。ここでも、動作中に発生する例外処理の追加を忘れないように //todo を追加しました。次のステップでは、新しいコマンドを追加して CommandContainerを更新します。
put(LIST_GROUP_SUB.getCommandName(), new GroupSubListCommand(sendBotMessageService, telegramUserService))
基本的にこれで終わりです。次に、さらにテストを作成し、/helpコマンドを更新し (新しいコマンドの説明を追加し)、Telegram 経由で新しい機能をテストする必要があります。ListGroupSubCommandのテストを書いてみましょう。コマンドのロジックは一般的ではないため、前に行ったように、 AbstractCommandTestクラスに結び付けずにテストを作成します。
package com.github.javarushcommunity.jrtb.command;

import com.github.javarushcommunity.jrtb.repository.entity.GroupSub;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.Update;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.github.javarushcommunity.jrtb.command.CommandName.LIST_GROUP_SUB;

@DisplayName("Unit-level testing for ListGroupSubCommand")
public class ListGroupSubCommandTest {

   @Test
   public void shouldProperlyShowsListGroupSub() {
       //given
       TelegramUser telegramUser = new TelegramUser();
       telegramUser.setActive(true);
       telegramUser.setChatId("1");

       List<GroupSub> groupSubList = new ArrayList<>();
       groupSubList.add(populateGroupSub(1, "gs1"));
       groupSubList.add(populateGroupSub(2, "gs2"));
       groupSubList.add(populateGroupSub(3, "gs3"));
       groupSubList.add(populateGroupSub(4, "gs4"));

       telegramUser.setGroupSubs(groupSubList);

       SendBotMessageService sendBotMessageService = Mockito.mock(SendBotMessageService.class);
       TelegramUserService telegramUserService = Mockito.mock(TelegramUserService.class);

       Mockito.when(telegramUserService.findByChatId(telegramUser.getChatId())).thenReturn(Optional.of(telegramUser));

       ListGroupSubCommand command = new ListGroupSubCommand(sendBotMessageService, telegramUserService);

       Update update = new Update();
       Message message = Mockito.mock(Message.class);
       Mockito.when(message.getChatId()).thenReturn(Long.valueOf(telegramUser.getChatId()));
       Mockito.when(message.getText()).thenReturn(LIST_GROUP_SUB.getCommandName());
       update.setMessage(message);

       String collectedGroups = "Я нашел все подписки на группы: \n\n" +
               telegramUser.getGroupSubs().stream()
                       .map(it -> "Группа: " + it.getTitle() + " , ID = " + it.getId() + " \n")
                       .collect(Collectors.joining());

       //when
       command.execute(update);

       //then
       Mockito.verify(sendBotMessageService).sendMessage(telegramUser.getChatId(), collectedGroups);
   }

   private GroupSub populateGroupSub(Integer id, String title) {
       GroupSub gs = new GroupSub();
       gs.setId(id);
       gs.setTitle(title);
       return gs;
   }
}

/help コマンドを更新しましょう

この例の場合、/helpコマンドはボットを操作するためのドキュメントとして機能するため、ユーザーが使用できるように忘れずに更新する必要があります。2 つのコマンドを追加したので、表示されるテキストを更新しましょう。
public static final String HELP_MESSAGE = String.format("✨Дотупные команды✨\n\n"

               + "Начать\\закончить работу с ботом:\n"
               + "%s - начать работу со мной\n"
               + "%s - приостановить работу со мной\n\n"

               + "Работа с подписками на группы:\n"
               + "%s - подписаться на группу статей\n"
               + "%s - получить список групп, на которые подписан\n\n"

               + "%s - получить помощь в работе со мной\n"
               + "%s - получить мою статистику использования\n",
       START.getCommandName(), STOP.getCommandName(), ADD_GROUP_SUB.getCommandName(),
       LIST_GROUP_SUB.getCommandName(), HELP.getCommandName(), STAT.getCommandName());
また、ボットの応答のテキストも更新しました。ユーザーとは常にファーストネームで表記されるようにしました。そうしないと、「あなた」と「あなた」の両方が表示されてしまいます...これで、少なくとも次のメッセージを作成できるようになります。ボットの仕事における何らかのつながり。

更新されたボットのテスト

ボットをローカルで起動し、次のことを行います。
  1. /startコマンドを実行して、テスト ケース内のユーザーがデータベースに追加されたことを確認します。
  2. /helpコマンドを実行します。希望どおり、すべてが正常であることを確認します。
  3. 次に、/addGroupSubコマンドを実行します。
  4. 提案されたグループ ID のリストから、いくつかのグループ ID をミックスに追加します。
  5. /listGroupSubコマンドを実行して、グループがユーザーに登録されていることを確認します。
行く!docker-compose-test.yml 経由でデータベースを起動し、SpringBoot を開始します。次に、テスト ボットに移動し、 /start コマンドを実行し、続いて/helpを実行します。「Java プロジェクト A to Z」: 記事のグループを購読する機能を追加します。 パート 3 - 2次に、コマンド/addGroupSubを入力します。「Java プロジェクト A to Z」: 記事のグループを購読する機能を追加します。 パート 3 - 3ドロップダウン リストには、Java クライアントが正常に動作していることが示されています。すべてのグループがその属性を持っています。 ID、コマンドの説明は、次に何が必要かを理解するのに役立つと思います。そこで、サブスクリプションにいくつかのグループを追加します。これで 5 つのサブスクリプションができたので、 /listGroupSub「Java プロジェクト A to Z」: 記事のグループを購読する機能を追加します。 パート 3 ~ 4コマンドを実行できます。すると、ある種のクレイジーな結果が得られます。 ...タイトルだけは問題なく表示されていたのに、ここでは表示されなかった理由は不明です。データベースに行って、そこに何があるか見てみましょう。同じ質問がデータベースに記録されていますが、キリル文字を含む質問のみです。これは、エンコードに何らかの問題があることを意味します。どうやら、データベースとデータベースに接続するためのドライバーを構成する必要があるようです。UTF-8が必要です。しかし、どうやって追加するのでしょうか?インターネットで数分間検索した後、ドライバーは url 変数を更新する必要があることを発見しました。そして、 docker-compose で docker イメージをセットアップする場合は、最初のリンクですが、答えは最初ではありません)) したがって、これを理解した上で、プロパティと docker-compose ファイルを更新しましょう。 「Java プロジェクト A to Z」: 記事のグループを購読する機能を追加します。 パート 3 ~ 5「Java プロジェクト A to Z」: 記事のグループを購読する機能を追加します。 パート 3 ~ 6
application.properties:
spring.datasource.url=jdbc:mysql://jrtb-db:3306/jrtb_db?characterEncoding=UTF-8

application-test.properties:
spring.datasource.url=jdbc:mysql://localhost:3306/dev_jrtb_db?characterEncoding=UTF-8

docker-compose.yml (добавил последнюю строку):
jrtb-db:
 image: mysql:5.7
 restart: always
 environment:
   MYSQL_USER: ${BOT_DB_USERNAME}
   MYSQL_PASSWORD: ${BOT_DB_PASSWORD}
   MYSQL_DATABASE: 'jrtb_db'
   MYSQL_ROOT_PASSWORD: 'root'
 ports:
   - '3306:3306'
 expose:
   - '3306'
 command: --character-set-server=utf8 --collation-server=utf8_general_ci

docker-compose-test.yml (добавил последнюю строку)
jrtb-db-dev:
 image: mysql:5.7
 restart: always
 environment:
   MYSQL_DATABASE: 'dev_jrtb_db'
   # So you don't have to use root, but you can if you like
   MYSQL_USER: 'dev_jrtb_db_user'
   # You can use whatever password you like
   MYSQL_PASSWORD: 'dev_jrtb_db_password'
   # Password for root access
   MYSQL_ROOT_PASSWORD: 'root'
 ports:
   # <Port exposed> : < MySQL Port running inside container>
   - '3306:3306'
 expose:
   # Opens port 3306 on the container
     - '3306'
 command: --character-set-server=utf8 --collation-server=utf8_general_ci
これらの更新後は、データベース内のすべてのデータを消去して、最初からやり直す必要があります。消去は非常に簡単です。コマンド docker-compose -f docker-compose-test.yml downを実行する必要があります 。その後、すべてのデータとデータベースが削除されます。そして、更新されたエンコーディングを使用して、再度実行します。 docker-compose -f docker-compose-test.uml up データベースの準備ができました。更新されたアプリケーションを起動して見てみましょう。簡単に説明して結果をお見せします。「Java プロジェクト A to Z」: 記事のグループを購読する機能を追加します。 パート 3 ~ 7そして今、まさに私たちが望んでいたものを手に入れることができました。これが真実のようです。

エンディング

これでこのステップを完了できると思います。本当にたくさんのことが行われてきました。アプリケーションのバージョンを0.5.0-SNAPSHOTとRELEASE_NOTESに更新しましょう。
# リリース ノート ## 0.5.0-SNAPSHOT * JRTB-5: グループでサブスクライブする機能を追加 * JRTB-6: グループ サブスクリプションのリストを取得する機能を追加。
その後はすべて通常どおりです。すべての変更を含む新しいコミットを作成します。主なことは、レポート目的で、このステップ中に完了した 2 つのタスクの説明を追加することです。それで、コメントは次のとおりです。
STEP_6 JRTB-5: グループでサブスクライブする機能を追加 JRTB-6: グループサブスクリプションのリストを表示する機能を追加しました。
その結果、47 個のファイルが変更されました...これは大きな変更です。機能の説明だけではわかりませんが。結局のところ、完全に理解するには、API 用の Java クライアントを作成し、基本的にアプリケーション全体を更新する必要があることを知る必要があります。これがサーバー上での作業の様子です - 作業はたくさんありますが、クライアント側からの可視性は小さいです...)) 皆さん、私は伝統的に私の仕事に興味を示す方法を提供しています - githubを購読してくださいアカウント、不明な点がある場合は、電報チャンネルに参加して、記事についての質問を書いてください。このSTEP_6 の変更を含むプル リクエストへのリンクは次のとおりです。読んでくれた皆さん、ありがとう。今後、サブスクリプションの削除、プロファイルの非アクティブ化などについて説明します。切り替えないでください))

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

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