다시 안녕. 이것은 JRTB-6 작업 에 기능을 추가하는 방법에 대해 설명하는 STEP_6의 마지막 기사입니다 . 이전 두 기사( 1부 , 2부 )에서 우리는 이미 필요한 거의 모든 것을 준비했습니다. 이 부분이 프로세스의 정점입니다. 처음부터 지금까지 이 시리즈의 기사를 읽어주신 모든 분들께 큰 존경을 표합니다. 이는 당신이 훌륭한 직업을 찾을 만큼 충분한 동기를 갖고 있다는 것을 의미합니다. 이제 사업을 시작하겠습니다.
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를 업데이트하는 것입니다.
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());
또한 봇의 응답 텍스트도 업데이트했습니다. 사용자와 항상 이름을 사용하도록 만들었습니다. 그렇지 않으면 "당신"과 "당신"이 모두 있을 것입니다... 이제 최소한 봇 작업에 일종의 연결이 있습니다.
업데이트된 봇 테스트
우리는 로컬에서 봇을 시작하고 다음을 수행합니다.- 테스트 케이스의 사용자가 데이터베이스에 추가되었는지 확인하기 위해 /start 명령을 실행합니다 .
- /help 명령을 실행합니다 . 원하는 대로 모든 것이 정상인지 확인합니다.
- 다음으로 /addGroupSub 명령을 실행합니다 .
- 제안된 그룹 ID 목록에서 몇 가지를 혼합에 추가합니다.
- /listGroupSub 명령을 실행하여 그룹이 사용자에게 등록되었는지 확인합니다.
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 데이터베이스가 준비되었습니다. 업데이트된 애플리케이션을 실행하고 살펴보겠습니다. 신속하게 검토하고 결과를 보여 드리겠습니다. 이제 우리가 원하는 것을 정확하게 얻었습니다. 이제 이것이 진실처럼 보입니다.
종결
이제 이 단계를 완료할 수 있을 것 같습니다. 정말 많은 일이 이루어졌습니다. 애플리케이션 버전을 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 에 대한 변경 사항이 포함된 풀 요청 링크입니다 . 읽어주신 모든 분들께 감사드립니다. 앞으로 더 많은 정보를 제공하겠습니다. 구독 삭제, 프로필 비활성화 등에 대해 이야기해 보겠습니다. 전환하지 마세요))
GO TO FULL VERSION