JavaRush /Java блогы /Random-KK /Біз мақалалар тобына жазылу мүмкіндігін қосамыз. (2 бөлім...
Roman Beekeeper
Деңгей

Біз мақалалар тобына жазылу мүмкіндігін қосамыз. (2 бөлім) - «Java жобасы А-дан Я-ға дейін»

Топта жарияланған
Бәріңе сәлем! Өткен аптада бастаған тапсырмамызбен жұмысты жалғастырамыз .«А-дан Я-ға Java жобасы»: мақалалар тобына жазылу мүмкіндігін қосу.  2 - 1 бөлім

Біз JRTB-5 енгіземіз

Енді JavaRush мақалаларының кейбір тобына жазылу үшін пәрменді қосу керек. Бұны қалай істейді? Біз мен ойлап тапқан ең қарапайым сценарийді ұстанамыз. Бізде топ идентификаторы арқылы кіру мүмкіндігі болғандықтан, оны тасымалдау үшін бізге пайдаланушы қажет. Ол үшін пайдаланушы /addGroupSub GROUP_ID пәрменін енгізеді, ол екі жолдың бірімен жұмыс істейді: пәрменнің өзі ғана келсе: /addGroupSub , жауап ретінде барлық топтардың тізімі және олардың идентификаторлары жіберіледі. Содан кейін пайдаланушы өзіне қажет топ идентификаторын таңдай алады және осы пәрменде сұраудың екінші нұсқасын жасай алады: /addGroupSub GROUP_ID - содан кейін осы пайдаланушымен осы топтың жазбасы болады. Менің ойымша, біз болашақта жақсы жұмыс істей аламыз. Біздің мақсатымыз - керемет қолданушы тәжірибесін емес, дамуды көрсету (айтуға ұяламын, бірақ мен орыс тілінде мұны білдіретін терминді білмеймін). Бүкіл қолданба арқылы өтетін функционалдылықты дұрыс қосу үшін (біздің жағдайда, телеграмма бот клиентінен дерекқорға дейін) сіз бір жерден бастауыңыз керек. Біз мұны дерекқор жағынан жасаймыз.

Дерекқорға жаңа тасымалдауды қосу

Бірінші істеу керек - жаңа дерекқорды тасымалдауды және JR-де пайдаланушылар тобының жазылу деректерін сақтау мүмкіндігін қосу. Бұл қалай болуы керек екенін есте сақтау үшін « Жобаны жоспарлау: жеті рет өлшеңіз » мақаласына оралыңыз . Екінші фотода дерекқордың шамамен диаграммасы бар. Топ ақпаратын сақтау үшін бізге кесте қосу керек:
  • JavaRush ішіндегі топ идентификаторы да біздің идентификаторымыз болады. Біз оларға сенеміз және бұл идентификаторлардың бірегей екеніне сенеміз;
  • тақырып - біздің суреттерімізде бұл атау болды - топтың бейресми атауы; яғни JavaRush веб-сайтында көретініміз;
  • last_article_id - бұл қызықты өріс. Ол осы топтағы мақаланың соңғы идентификаторын сақтайды, оны бот өз жазылушыларына жіберген. Осы өрісті пайдалану арқылы жаңа мақалаларды іздеу механизмі жұмыс істейді. Жаңа жазылушылар пайдаланушы жазылғанға дейін жарияланған мақалаларды алмайды: тек топқа жазылғаннан кейін жарияланған мақалалар.
Сондай-ақ бізде топтар мен пайдаланушылар кестесінің арасында көптен көпке қатынасы болады, себебі әрбір пайдаланушының көптеген топтық жазылымдары (бірден көпке) болуы мүмкін және әр топ жазылымында көптеген пайдаланушылар болуы мүмкін (бірден көпке, тек басқа жағынан). Бұл біздің көп-көп болады екен. Сұрақтары барлар үшін дерекқордағы мақалаларды қарап шығыңыз. Иә, мен жақын арада Telegram арнасында жазба жасауды жоспарлап отырмын, онда дерекқордағы барлық мақалаларды жинаймын. Біздің екінші дерекқор тасымалдауымыз осылай болады.
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 кестесіне ШЕТЕЛДІК КІЛТ қосу мүмкіндігін бермеді және осы тасымалдаудың бөлігі ретінде мен дерекқорды жаңарттым. Маңызды аспектіні ескеріңіз. Дерекқорды өзгерту дәл осылай жасалуы керек - қажет нәрсенің бәрі жаңа тасымалдауда, бірақ бұрыннан шығарылған тасымалдауды жаңарту арқылы емес. Иә, біздің жағдайда ештеңе болмас еді, өйткені бұл сынақ жобасы және біз оның тек бір жерде орналастырылғанын білеміз, бірақ бұл дұрыс емес тәсіл болар еді. Бірақ біз бәрі дұрыс болғанын қалаймыз. Содан кейін кестелерді жасамас бұрын жою керек. Бұл не үшін? Егер кездейсоқ дерекқорда осындай атаулары бар кестелер болса, көшіру сәтсіз аяқталмайды және күткендей жұмыс істейді. Содан кейін біз екі кестені қосамыз. Барлығы біз қалағандай болды. Енді біз қолданбамызды іске қосуымыз керек. Егер бәрі басталып, үзілмесе, көшу жазылады. Ал мұны екі рет тексеру үшін мәліметтер базасына барамыз: а) мұндай кестелер пайда болғанына; б) ұшу жолының техникалық кестесінде жаңа жазба бар. Бұл көшіру жұмысын аяқтайды, репозитарийлерге көшейік.

Репозиторий қабатын қосу

Spring Boot деректерінің арқасында мұнда бәрі өте қарапайым: бізге 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);
   }
}
Айта кету керек, бізде топқа жазылған барлық пайдаланушылар жиынтығын қамтитын қосымша пайдаланушылар өрісі бар. Және екі annotation - 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 тобын қосамыз, осы пайдаланушыны оның идентификаторы бойынша аламыз және дәл сол топтарды және дәл сол мәндерді алғанымызды тексереміз. Бұны қалай істейді? Есептегішті деректерге енгізуге болады, содан кейін біз оны тексеріп, тексере аламыз. Міне 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());
       }
   }
}
Және жетіспейтін бесUsersForGroupSub.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 іске асыруы басқа қызметтерді қамтитын пакетте - сервис:
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 кестесі арқылы да қосылым жасалады. Мұндай жазылым тобы бұрыннан жасалған жағдай болуы мүмкін және оған басқа пайдаланушы қосу керек. Ол үшін алдымен деректер қорынан топ идентификаторын аламыз, егер жазба болса онымен жұмыс істейміз, жоқ болса жаңасын жасаймыз. TelegramUser-пен жұмыс істеу үшін біз TelegramUserService қызметін SOLID қағидаларының соңғысын ұстанатынымызды ескеру маңызды. Қазіргі уақытта идентификатор бойынша жазба табылмаса, мен жай ғана ерекшелік жіберемін. Ол қазір ешқандай жолмен өңделмейді: біз мұны ең соңында, MVP алдында жасаймыз. GroupSubServiceTest сыныбы үшін екі бірлік сынақтарын жазайық . Бізге қайсысы керек? Сақтау әдісі GroupSubRepository-де шақырылатынына және бір пайдаланушысы бар нысан GroupSub-қа жіберілетініне сенімді болғым келеді - ол берілген идентификаторды пайдаланып бізге TelegramUserService қайтарады. Ал екінші опция, сол идентификаторы бар топ дерекқорда бұрыннан бар болса және бұл топтың бір пайдаланушысы болса және осы топқа басқа пайдаланушы қосылатынын және бұл нысан сақталатынын тексеру керек. Міне, іске асыру:
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);
   }

}
Мен init() әдісін BeforeEach annotationсымен қостым . Осылайша, олар әдетте әрбір сынақ орындалмас бұрын орындалатын әдісті жасайды және оған барлық сынақтар үшін жалпы логиканы қоюға болады. Біздің жағдайда TelegramUserService қызметін осы сыныптың барлық сынақтары үшін бірдей құлыптауымыз керек, сондықтан бұл логиканы жалпы әдіске көшіру мағынасы бар. Мұнда екі мокито дизайны қолданылады:
  • Mockito.when(o1.m1(a1)).thenReturn(o2) - онда a1 аргументі бар o1 нысанында m1 әдісі шақырылғанда , әдіс o2 нысанын қайтаратынын айтамыз . Бұл мокитоның ең маңызды функционалдығы дерлік - жалған нысанды бізге қажет нәрсені қайтаруға мәжбүрлеу;

  • Mockito.verify(o1).m1(a1) - m1 әдісі a1 аргументі арқылы o1 нысанында шақырылғанын тексереді . Әрине, сақтау әдісінің қайтарылған нысанын пайдалану мүмкін болды, бірақ мен басқа ықтимал әдісті көрсету арқылы оны біршама күрделендіруді шештім. Қашан пайдалы болуы мүмкін? Жалған сабақтардың әдістері жарамсыз болып табылатын жағдайларда. Сонда Mockito.verify болмаса жұмыс болмайды)))

Біз тестілеуді жазу керек және олардың көпшілігін жазу керек деген идеяны ұстануды жалғастырамыз. Келесі кезең - телеграм бот командасымен жұмыс.

/addGroupSub пәрменін жасаңыз

Мұнда біз келесі логиканы орындауымыз керек: егер біз ешқандай контекстсіз жай ғана пәрменді алсақ, біз пайдаланушыға көмектесеміз және оған қажетті ақпаратты ботқа бере алуы үшін идентификаторлары бар барлық топтардың тізімін береміз. Ал егер пайдаланушы басқа сөз(дер) арқылы ботқа пәрмен жіберсе, сол идентификаторы бар топты табыңыз немесе ондай топ жоқ деп жазыңыз. Біздің атауымызға жаңа мән қосайық - 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))
Және бәрі осы команда үшін. Мен бұл функцияны қандай да бір түрде тексергім келеді, бірақ әзірге мен оны дерекқорда шынымен қарай аламын. Үшінші бөлімде мен JRTB-6 өзгерістерін қосамын, осылайша біз пайдаланушы жазылған топтардың тізімін көре аламыз. Енді осының бәрін тексеріп көрсек жақсы болар еді. Ол үшін біз Telegram-да барлық әрекеттерді орындап, дерекқорда тексереміз. Тесттерді жазғандықтан, бәрі жақсы болуы керек. Мақала өте ұзақ, сондықтан біз кейінірек AddGroupSubCommand үшін сынақ жазамыз және ұмытып кетпеу үшін codeқа TODO қосамыз.

қорытындылар

Бұл мақалада біз дерекқордан бастап, ботты пайдаланатын клиентпен жұмыс істеуге дейін бүкіл қолданба арқылы функционалдылықты қосу жұмысын қарастырдық. Әдетте мұндай тапсырмалар жобаны түсінуге және оның мәнін түсінуге көмектеседі. Оның қалай жұмыс істейтінін түсініңіз. Бұл күндері тақырыптар оңай емес, сондықтан ұялмаңыз: сұрақтарыңызды түсініктемелерде жазыңыз, мен оларға жауап беруге тырысамын. Сізге жоба ұнады ма? Оған Github-да жұлдыз беріңіз : осылайша олардың жобаға қызығушылық танытатыны анық болады, мен бақытты боламын. Шебердің еңбегі бағаланса риза болады дегендей. Код STEP_6 барлық үш бөлігін қамтиды және осы мақалаға дейін қолжетімді болады. Ол туралы қалай білуге ​​болады? Бұл оңай – телеграм-каналға қосылыңыз , онда мен телеграм боты туралы мақалаларым туралы барлық ақпаратты жариялаймын. Оқығаныңызға рахмет! 3-бөлім осында .

Сериядағы барлық материалдардың тізімі осы мақаланың басында.

Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION