JavaRush /Java 博客 /Random-ZH /我们正在添加订阅一组文章的功能。(第 3 部分)-“Java 项目从头到尾”
Roman Beekeeper
第 35 级

我们正在添加订阅一组文章的功能。(第 3 部分)-“Java 项目从头到尾”

已在 Random-ZH 群组中发布
你好,我们又见面了。这是 STEP_6 的最后一篇文章,我们将在其中讨论向JRTB-6任务添加功能。在前面的两篇文章(第 1 部分第 2 部分)中,我们已经准备好了您所需的几乎所有内容。这部分是该过程的高潮。对于所有从一开始就读过本系列文章的人,我们深表敬意。这意味着您有足够的动力去找到一份好工作。现在让我们言归正传吧。“Java 项目从 A 到 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 获取用户,并且他对组的所有订阅都将收集在他的对象中。我们在第二部分中对此进行了设置。再次,我添加了//todo,这样我就不会忘记添加对操作期间可能出现的异常的处理。下一步是通过向 CommandContainer 添加新命令来更新 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命令充当使用机器人的文档,因此我们必须记住更新它,以便用户可以使用它。我们添加了两个命令,所以让我们更新即将出现的文本:
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 到 Z”:添加订阅一组文章的功能。 第 3 - 2 部分接下来,输入命令/addGroupSub“Java 项目从 A 到 Z”:添加订阅一组文章的功能。 第 3 - 3 部分下拉列表表明 Java 客户端正在正常工作:我们拥有所有组及其ID,命令的描述有助于(希望)理解我们接下来需要什么,因此我们向订阅添加了几个组:“Java 项目从 A 到 Z”:添加订阅一组文章的功能。 第 3 - 4 部分现在我们有 5 个订阅,因此我们可以运行/listGroupSub命令:然后我们得到了一些疯狂的事情...目前尚不清楚为什么标题“Java 项目从 A 到 Z”:添加订阅一组文章的功能。 第 3 - 5 部分显示没有任何问题,但不是在这里。让我们去数据库看看有什么:数据库中记录了相同的问题,但仅限于那些带有西里尔字母的问题。这意味着编码存在一些问题。显然,您需要配置数据库以及连接数据库的驱动程序。我们需要UTF-8。但如何添加呢?经过几分钟在互联网上搜索,我发现:驱动程序需要更新 url 变量。对于在 docker-compose 中设置 docker 镜像,这是第一个链接,但答案不是第一个))因此,知道了这一点,让我们更新属性和 docker-compose 文件。 “Java 项目从 A 到 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 到 Z”:添加订阅一组文章的功能。 第 3 - 7 部分现在我们得到了我们想要的结果。现在这看起来像是事实。

结尾

现在我想我们可以完成这一步了。已经做了很多,真的很多。让我们将应用程序版本更新为0.5.0-SNAPSHOT和 RELEASE_NOTES。
# 发行说明 ## 0.5.0-SNAPSHOT * JRTB-5:添加了群组订阅功能 * JRTB-6:添加了获取群组订阅列表的功能。
然后一切都像往常一样:我们创建一个包含所有更改的新提交。主要是添加此步骤中完成的两项任务的描述以用于报告目的。所以这是评论:
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