JavaRush /Java Blog /Random-TL /Nagdaragdag kami ng kakayahang mag-subscribe sa isang pan...

Nagdaragdag kami ng kakayahang mag-subscribe sa isang pangkat ng mga artikulo. (Bahagi 2) - "Proyekto ng Java mula A hanggang Z"

Nai-publish sa grupo
Kamusta kayong lahat! Patuloy kaming gumagawa sa gawaing sinimulan namin noong nakaraang linggo ."Proyekto ng Java mula A hanggang Z": Pagdaragdag ng kakayahang mag-subscribe sa isang pangkat ng mga artikulo.  Bahagi 2 - 1

Ipinapatupad namin ang JRTB-5

Ngayon ay kailangan nating magdagdag ng utos upang makapag-subscribe tayo sa ilang grupo ng mga artikulo mula sa JavaRush. Paano ito gagawin? Susundan natin ang pinakasimpleng senaryo na naisip ko. Dahil mayroon kaming access sa pamamagitan ng group ID, kailangan namin ng user na ilipat ito. Upang gawin ito, ilalagay ng user ang command na /addGroupSub GROUP_ID, na gagana sa isa sa dalawang paraan: kung ang mismong command lang ang darating: /addGroupSub , isang listahan ng lahat ng grupo at ang kanilang mga ID ay ipapadala bilang tugon. Pagkatapos ay mapipili ng user ang group ID na kailangan niya at gagawa ng pangalawang bersyon ng kahilingan sa command na ito: /addGroupSub GROUP_ID - at pagkatapos ay magkakaroon ng talaan ng pangkat na ito kasama ng user na ito. Sa tingin ko, mas makakabuti tayo sa hinaharap. Ang aming layunin ay ipakita ang pag-unlad, at hindi ang sobrang cool na karanasan ng gumagamit (nahihiya akong sabihin, ngunit hindi ko alam ang termino sa Russian na ibig sabihin nito). Upang maayos na magdagdag ng functionality na dumadaan sa buong application (sa aming kaso, mula sa telegram bot client hanggang sa database), kailangan mong magsimula sa ilang dulo. Gagawin namin ito mula sa database side.

Pagdaragdag ng bagong paglipat sa database

Ang unang bagay na dapat gawin ay magdagdag ng bagong paglilipat ng database at ang kakayahang mag-save ng data ng subscription sa pangkat ng user sa JR. Upang matandaan kung paano ito dapat, bumalik sa artikulong " Pagpaplano ng proyekto: sukatin nang pitong beses ." Doon sa pangalawang larawan mayroong isang tinatayang diagram ng database. Kailangan naming magdagdag ng talahanayan upang mag-imbak ng impormasyon ng pangkat:
  • Ang group ID sa JavaRush ay magiging ID din natin. Pinagkakatiwalaan namin sila at naniniwala kami na ang mga ID na ito ay natatangi;
  • pamagat - sa aming mga larawan ito ay pangalan - ang impormal na pangalan ng grupo; iyon ay, kung ano ang nakikita natin sa website ng JavaRush;
  • last_article_id - at ito ay isang kawili-wiling field. Iimbak nito ang huling ID ng artikulo sa pangkat na ito, na ipinadala na ng bot sa mga subscriber nito. Gamit ang field na ito, gagana ang mekanismo para sa paghahanap ng mga bagong artikulo. Ang mga bagong subscriber ay hindi makakatanggap ng mga artikulong nai-publish bago mag-subscribe ang user: ang mga na-publish lamang pagkatapos mag-subscribe sa grupo.
Magkakaroon din kami ng maraming-sa-maraming ugnayan sa pagitan ng mga pangkat at talahanayan ng mga user, dahil ang bawat user ay maaaring magkaroon ng maraming mga subscription ng grupo (isa-sa-marami), at ang bawat subscription ng grupo ay maaaring magkaroon ng maraming user (isa-sa- marami, lamang sa kabila). Ito pala ang magiging many-to-many natin. Para sa mga may katanungan, suriin ang mga artikulo sa database. Oo, malapit na akong magpaplano na lumikha ng isang post sa Telegram channel, kung saan pagsasama-samahin ko ang lahat ng mga artikulo sa database. Ito ang magiging hitsura ng aming pangalawang database migration.
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)
);
Mahalagang tandaan na binago ko muna ang lumang talahanayan - nagdaragdag ako ng pangunahing susi dito. Kahit papaano ay napalampas ko ito noong panahong iyon, ngunit ngayon ay hindi ako binigyan ng MySQL ng pagkakataong magdagdag ng FOREIGN KEY para sa talahanayan ng gorup_x_user, at bilang bahagi ng paglipat na ito ay na-update ko ang database. Mangyaring tandaan ang isang mahalagang aspeto. Ang pagbabago ng database ay dapat gawin nang eksakto sa ganitong paraan - lahat ng kailangan ay nasa bagong migration, ngunit hindi sa pamamagitan ng pag-update ng nailabas na migration. Oo, sa aming kaso walang mangyayari, dahil ito ay isang pagsubok na proyekto at alam namin na ito ay naka-deploy sa isang lugar lamang, ngunit ito ay magiging maling diskarte. Pero gusto naming maging tama ang lahat. Susunod ay ang pagtanggal ng mga talahanayan bago gawin ang mga ito. Bakit ito? Upang kung sa ilang pagkakataon ay may mga talahanayan na may ganitong mga pangalan sa database, ang paglipat ay hindi mabibigo at gagana nang eksakto tulad ng inaasahan. At pagkatapos ay nagdaragdag kami ng dalawang talahanayan. Lahat ay ayon sa gusto namin. Ngayon kailangan naming ilunsad ang aming application. Kung ang lahat ay magsisimula at hindi masira, pagkatapos ay ang paglipat ay naitala. At upang i-double-check ito, pumunta kami sa database upang matiyak na: a) ang mga naturang talahanayan ay lumitaw; b) may bagong entry sa flyway technical table. Nakumpleto nito ang gawaing paglilipat, lumipat tayo sa mga repositoryo.

Pagdaragdag ng layer ng repositoryo

Salamat sa Spring Boot Data, ang lahat ay napaka-simple dito: kailangan naming idagdag ang GroupSub entity, bahagyang i-update ang TelegramUser at magdagdag ng halos walang laman na GroupSubRepository: Idinagdag namin ang GroupSub entity sa parehong pakete bilang 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);
   }
}
Isang bagay na dapat tandaan ay mayroon kaming karagdagang field ng mga user na maglalaman ng koleksyon ng lahat ng user na naka-subscribe sa grupo. At dalawang anotasyon - ManyToMany at JoinTable - ang eksaktong kailangan namin para dito. Ang parehong field ay kailangang idagdag para sa TelegramUser:
@ManyToMany(mappedBy = "users", fetch = FetchType.EAGER)
private List<GroupSub> groupSubs;
Gumagamit ang field na ito ng mga pagsali na nakasulat sa entity ng GroupSub. At, sa katunayan, ang aming klase ng repository para sa GroupSub ay 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> {
}
Sa yugtong ito, hindi namin kailangan ng mga karagdagang pamamaraan: ang mga ipinatupad sa ninuno ng JpaRepository ay sapat na para sa amin. Sumulat tayo ng isang pagsubok sa TelegramUserRepositoryIT na susuriin kung ang aming marami-sa-maraming mga gawa. Ang ideya ng pagsubok ay magdaragdag kami ng 5 grupo ng mga subscription sa bawat user sa database sa pamamagitan ng isang sql script, kunin ang user na ito sa pamamagitan ng kanyang ID at tingnan kung eksaktong natanggap namin ang mga pangkat na iyon at may eksaktong parehong mga halaga. Paano ito gagawin? Maaari kang mag-embed ng isang counter sa data, na maaari naming dumaan at suriin. Narito ang fiveGroupSubsForUser.sql script:
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);
At ang pagsubok mismo:
@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());
   }
}
Ngayon, magdagdag tayo ng pagsubok na may parehong kahulugan para sa entity ng GroupSub. Upang gawin ito, gumawa tayo ng isang test class groupSubRepositoryIT sa parehong pakete bilang 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());
       }
   }
}
At ang nawawalang limangUsersForGroupSub.sql script:
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);
Sa puntong ito, ang bahagi ng trabaho kasama ang imbakan ay maaaring ituring na nakumpleto. Ngayon magsulat tayo ng isang layer ng serbisyo.

Nagsusulat kami ng GroupSubService

Sa yugtong ito, upang gumana sa mga pangkat ng mga subscription, kailangan lang namin na mai-save ang mga ito, kaya walang problema: ginagawa namin ang serbisyo ng GroupSubService at ang pagpapatupad nito ng GroupSubServiceImpl sa isang package na naglalaman ng iba pang mga serbisyo - serbisyo:
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);
}
At ang pagpapatupad nito:
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);
   }
}
Upang gumana nang tama ang Data ng Spring at makagawa ng maraming-sa-maraming tala, kailangan nating kunin ang user mula sa aming database para sa pangkat ng subscription na ginagawa namin at idagdag ito sa object na GroupSub. Kaya, kapag inilipat namin ang subscription na ito para sa pag-save, magkakaroon din ng koneksyon sa pamamagitan ng group_x_user table. Maaaring may sitwasyon kung kailan nagawa na ang naturang pangkat ng subscription at kailangan mo lang magdagdag ng isa pang user dito. Upang gawin ito, makuha muna namin ang ID ng grupo mula sa database, at kung mayroong isang talaan, nakikipagtulungan kami dito, kung hindi, lumikha kami ng bago. Mahalagang tandaan na upang gumana sa TelegramUser ginagamit namin ang TelegramUserService upang sundin ang huling mga prinsipyo ng SOLID. Sa ngayon, kung wala kaming mahanap na record sa pamamagitan ng ID, naglalagay lang ako ng exception. Hindi ito pinoproseso sa anumang paraan ngayon: gagawin namin ito sa pinakadulo, bago ang MVP. Sumulat tayo ng dalawang unit test para sa klase ng GroupSubServiceTest . Alin ang kailangan natin? Gusto kong makatiyak na ang paraan ng pag-save ay tatawagin sa GroupSubRepository at isang entity na may isang solong user ang ipapasa sa GroupSub - ang isa na magbabalik ng TelegramUserService sa amin gamit ang ibinigay na ID. At ang pangalawang opsyon, kapag ang isang grupo na may parehong ID ay nasa database na at ang grupong ito ay mayroon nang isang user, at kailangan mong suriin na ang isa pang user ay idaragdag sa grupong ito at ang bagay na ito ay mai-save. Narito ang pagpapatupad:
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);
   }

}
Idinagdag ko rin ang init() na pamamaraan sa BeforeEach annotation. Sa ganitong paraan, karaniwan kang gumagawa ng paraan na isasagawa bago tumakbo ang bawat pagsubok, at maaari mong ilagay ang karaniwang lohika dito para sa lahat ng pagsubok. Sa aming kaso, kailangan naming i-lock ang TelegramUserService sa parehong paraan para sa lahat ng mga pagsubok ng klase na ito, kaya makatuwirang ilipat ang logic na ito sa isang karaniwang paraan. Mayroong dalawang disenyo ng mokito na ginamit dito:
  • Mockito.when(o1.m1(a1)).thenReturn(o2) - dito sinasabi natin na kapag ang method m1 ay tinawag sa object o1 na may argument a1 , ibabalik ng method ang object o2 . Ito ang halos pinakamahalagang pag-andar ng mockito - upang pilitin ang mock object na ibalik ang eksaktong kailangan natin;

  • Mockito.verify(o1).m1(a1) - na nagpapatunay na ang method na m1 ay tinawag sa object o1 na may argument a1 . Posible, siyempre, na gamitin ang ibinalik na bagay ng paraan ng pag-save, ngunit nagpasya akong gawin itong mas kumplikado sa pamamagitan ng pagpapakita ng isa pang posibleng paraan. Kailan ito maaaring maging kapaki-pakinabang? Sa mga kaso kung saan ang mga pamamaraan ng mock class ay nagbabalik na walang bisa. Then without Mockito.verify there will be no work)))

Patuloy kaming sumunod sa ideya na kailangang isulat ang mga pagsusulit, at marami sa kanila ang kailangang isulat. Ang susunod na yugto ay nagtatrabaho sa telegram bot team.

Lumikha ng command /addGroupSub

Dito kailangan naming gawin ang sumusunod na lohika: kung nakatanggap kami ng isang utos lamang, nang walang anumang konteksto, tinutulungan namin ang gumagamit at binibigyan siya ng isang listahan ng lahat ng mga grupo kasama ang kanilang mga ID upang maipasa niya ang kinakailangang impormasyon sa bot. At kung magpapadala ang user ng command sa bot na may (mga) ibang salita - maghanap ng grupo na may ID na iyon o isulat na walang ganoong grupo. Magdagdag tayo ng bagong halaga sa ating ename - CommandName:
ADD_GROUP_SUB("/addgroupsub")
Lumipat pa tayo mula sa database patungo sa telegram bot - lumikha ng klase ng AddGroupSubCommand sa command package:
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));
   }
}
Ang klase na ito ay gumagamit ng isNumeric method mula sa apache-commons library, kaya't idagdag natin ito sa ating memorya:
<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-lang3</artifactId>
  <version>${apache.commons.version}</version>
</dependency>
At sa block ng properties:
<apache.commons.version>3.11</apache.commons.version>
Ang lahat ng lohika na ito ay nasa klase. Basahin itong mabuti. Kung mayroon kang anumang mga katanungan / mungkahi, isulat ang mga ito sa mga komento. Pagkatapos nito, kailangan naming idagdag ang command sa CommandContainer sa aming command map:
.put(ADD_GROUP_SUB.getCommandName(), new AddGroupSubCommand(sendBotMessageService, javaRushGroupClient, groupSubService))
At lahat para sa pangkat na ito. Gusto kong kahit papaano ay subukan ang pag-andar na ito, ngunit sa ngayon ay maaari ko lamang talagang tingnan ito sa database. Sa ikatlong bahagi, magdaragdag ako ng mga pagbabago mula sa JRTB-6 para makita natin ang listahan ng mga pangkat kung saan naka-subscribe ang isang user. Ngayon ay makabubuting suriin ang lahat ng ito. Upang gawin ito, gagawin namin ang lahat ng mga aksyon sa Telegram at suriin sa database. Dahil mayroon kaming mga nakasulat na pagsusulit, dapat na maayos ang lahat. Medyo mahaba na ang artikulo, kaya susulat tayo ng pagsubok para sa AddGroupSubCommand mamaya, at magdagdag ng TODO sa code para hindi makalimutan.

mga konklusyon

Sa artikulong ito, tiningnan namin ang gawain ng pagdaragdag ng functionality sa buong application, simula sa database at nagtatapos sa pakikipagtulungan sa kliyente na gumagamit ng bot. Karaniwan ang gayong mga gawain ay nakakatulong upang maunawaan ang proyekto at maunawaan ang kakanyahan nito. Unawain kung paano ito gumagana. Sa mga araw na ito ang mga paksa ay hindi madali, kaya huwag mahiya: isulat ang iyong mga tanong sa mga komento, at susubukan kong sagutin ang mga ito. Gusto mo ba ang proyekto? Bigyan ito ng bituin sa Github : sa ganitong paraan magiging malinaw na interesado sila sa proyekto, at magiging masaya ako. Tulad ng sinasabi nila, ang isang master ay palaging nalulugod kapag ang kanyang trabaho ay pinahahalagahan. Maglalaman ang code ng lahat ng tatlong bahagi ng STEP_6 at magiging available bago ang artikulong ito. Paano malalaman ang tungkol dito? Madali lang - sumali sa telegram channel , kung saan ini-publish ko ang lahat ng impormasyon tungkol sa aking mga artikulo tungkol sa telegram bot. Salamat sa pagbabasa! Nandito na ang Part 3 .

Ang isang listahan ng lahat ng mga materyales sa serye ay nasa simula ng artikulong ito.

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