JavaRush /Blog Java /Random-PL /Dodajemy możliwość subskrypcji grupy artykułów. (Część 3)...
Roman Beekeeper
Poziom 35

Dodajemy możliwość subskrypcji grupy artykułów. (Część 3) - „Projekt Java od A do Z”

Opublikowano w grupie Random-PL
Witaj ponownie. To już ostatni artykuł z STEP_6, w którym porozmawiamy o dodaniu funkcjonalności do zadania JRTB-6 . W dwóch poprzednich artykułach ( część 1 , część 2 ) przygotowaliśmy już prawie wszystko, czego potrzebujesz. Ta część stanowi kulminację procesu. Wszystkim, którzy przeczytali tę serię artykułów aż do tego momentu od samego początku – wielki szacunek. Oznacza to, że masz wystarczającą motywację, aby znaleźć świetną pracę. Przejdźmy teraz do rzeczy.„Projekt Java od A do Z”: Dodanie możliwości subskrypcji grupy artykułów.  Część 3 - 1

Wdrażamy JRTB-6

Tym razem zadanie wykonamy od strony bota telegramowego, ponieważ prace nad aktualizacją bazy danych zostały zakończone, jednostki bazy danych są skonfigurowane i gotowe do pracy. Dodajmy nową wartość do CommandName - LIST_GROUP_SUB:
LIST_GROUP_SUB("/listGroupSub");
Utwórzmy polecenie 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);
   }
}
Tutaj wszystko jest tak proste, jak to możliwe - pozyskujemy użytkownika za pomocą istniejącego chat_id, a wszystkie jego subskrypcje do grup zostaną zebrane w jego obiekcie. Ustaliliśmy to w drugiej części. Ponownie dodałem //todo, żeby nie zapomnieć dodać obsługi wyjątków, które mogą pojawić się podczas działania. Następnym krokiem jest aktualizacja CommandContainera poprzez dodanie do niego nowego polecenia:
put(LIST_GROUP_SUB.getCommandName(), new GroupSubListCommand(sendBotMessageService, telegramUserService))
To w zasadzie wszystko: teraz musisz napisać więcej testów, zaktualizować polecenie /help (dodać opis nowych poleceń) i przetestować nową funkcjonalność za pośrednictwem Telegramu. Napiszmy test dla ListGroupSubCommand . Ponieważ logika polecenia nie jest typowa, test napiszemy bez wiązania się z klasą AbstractCommandTest , tak jak to robiliśmy wcześniej:
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;
   }
}

Zaktualizujmy polecenie /help

W naszym przypadku komenda /help pełni rolę dokumentacji do pracy z botem, dlatego musimy pamiętać o jej aktualizacji, aby użytkownik mógł z niej skorzystać. Dodaliśmy dwa polecenia, więc zaktualizujmy tekst, który się pojawi:
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());
Zaktualizowałem także treść odpowiedzi bota: zadbałem o to, aby z użytkownikiem zawsze było po imieniu, inaczej byłoby i „ty”, i „ty”… Teraz będzie można stworzyć przynajmniej jakieś powiązanie w pracy bota.

Testowanie zaktualizowanego bota

Uruchamiamy naszego bota lokalnie i wykonujemy następujące czynności:
  1. Wykonujemy komendę /start, aby mieć pewność, że użytkownik w przypadku testowym został dodany do bazy danych.
  2. Wykonujemy komendę /help - sprawdzamy czy wszystko jest ok, tak jak chcieliśmy.
  3. Następnie wykonujemy polecenie /addGroupSub .
  4. Z proponowanej listy identyfikatorów grup dodajemy kilka do miksu.
  5. Uruchamiamy polecenie /listGroupSub , aby upewnić się, że grupy są zarejestrowane dla użytkownika.
Iść! Uruchamiamy bazę danych poprzez plik docker-compose-test.yml i uruchamiamy naszego SpringBoota. Następnie przejdź do naszego bota testowego i wykonaj polecenie /start, a następnie /help : „Projekt Java od A do Z”: Dodanie możliwości subskrypcji grupy artykułów.  Część 3 - 2Następnie wprowadź polecenie /addGroupSub : „Projekt Java od A do Z”: Dodanie możliwości subskrypcji grupy artykułów.  Część 3 - 3Z rozwijanej listy wynika, że ​​klient Java działa tak, jak powinien: mamy wszystkie grupy z ich ID, opis polecenia pomaga (miejmy nadzieję) zrozumieć, czego potrzebujemy dalej, dlatego dodajemy kilka grup do subskrypcji: „Projekt Java od A do Z”: Dodanie możliwości subskrypcji grupy artykułów.  Część 3 - 4Teraz mamy 5 subskrypcji, więc możemy uruchomić polecenie /listGroupSub : I wtedy otrzymamy jakieś szalone rozwiązanie ... Nie jest jasne, dlaczego tytuł„Projekt Java od A do Z”: Dodanie możliwości subskrypcji grupy artykułów.  Część 3 - 5 po prostu wyświetlał się bez problemów, ale nie tutaj. Przejdźmy do bazy danych, żeby zobaczyć, co tam jest: W bazie zapisane są te same pytania, ale tylko te z cyrylicą. Oznacza to, że wystąpił problem z kodowaniem. Najwyraźniej musisz skonfigurować bazę danych i sterownik do łączenia się z bazą danych. Potrzebujemy UTF-8. Ale jak to dodać? Po kilku minutach poszukiwań w Internecie znalazłem : sterownik musi zaktualizować zmienną url. A do skonfigurowania obrazu dokera w docker-compose, pierwszy link , ale odpowiedź nie jest pierwsza)) Dlatego wiedząc o tym, zaktualizujmy właściwości i pliki docker-compose. „Projekt Java od A do Z”: Dodanie możliwości subskrypcji grupy artykułów.  Część 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
Po tych aktualizacjach należy usunąć wszystkie dane z bazy danych i zacząć od nowa. Kasowanie jest bardzo proste: należy uruchomić komendę: docker-compose -f docker-compose-test.yml down, po czym wszystkie dane i baza danych zostaną usunięte. I uruchom go ponownie ze zaktualizowanym kodowaniem: docker-compose -f docker-compose-test.uml up Baza danych jest gotowa. Uruchommy zaktualizowaną aplikację i spójrzmy. Przeanalizuję to szybko i pokażę wynik: „Projekt Java od A do Z”: Dodanie możliwości subskrypcji grupy artykułów.  Część 3 - 7I teraz mamy dokładnie to, czego chcieliśmy. Teraz wygląda to na prawdę.

Kończący się

Myślę, że teraz możemy zakończyć ten etap. Wiele zostało zrobione, naprawdę dużo. Zaktualizujmy wersję aplikacji do 0.5.0-SNAPSHOT i RELEASE_NOTES.
# Informacje o wydaniu ## 0.5.0-SNAPSHOT * JRTB-5: dodana możliwość subskrypcji w grupie * JRTB-6: dodana możliwość uzyskania listy subskrypcji grupowych.
Potem wszystko jest jak zwykle: tworzymy nowe zatwierdzenie ze wszystkimi zmianami. Najważniejsze jest, aby dodać opis dwóch zadań, które zostały wykonane na tym etapie, na potrzeby raportowania. Oto komentarz:
KROK_6 JRTB-5: dodano możliwość subskrypcji w grupie JRTB-6: dodano możliwość przeglądania listy subskrypcji grupowych.
Spowodowało to zmianę 47 plików... To duża zmiana. Chociaż nie można tego stwierdzić na podstawie opisu funkcjonalności. W końcu, aby zrozumieć pełną głębię, musisz wiedzieć, że musisz napisać klienta Java dla API, zasadniczo aktualizując całą aplikację. Tak to jest z pracą na serwerze - pracy jest dużo, ale widoczność od strony klienta mała...)) Kochani, tradycyjnie oferuję Wam sposób na okazanie zainteresowania moją twórczością - subskrybujcie githuba konto , dołącz do kanału telegramu i napisz pytanie dotyczące artykułu, jeśli coś jest niejasne! Oto link do żądania ściągnięcia ze zmianami dla tego STEP_6 . Dziękuję wszystkim za przeczytanie. Więcej wkrótce — porozmawiajmy o usuwaniu subskrypcji, dezaktywacji profilu i nie tylko. Nie przełączaj))

Lista wszystkich materiałów wchodzących w skład serii znajduje się na początku artykułu.

Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION