JavaRush /Java блогу /Random-KY /Биз макалалардын тобуна жазылуу мүмкүнчүлүгүн кошуп жатаб...
Roman Beekeeper
Деңгээл

Биз макалалардын тобуна жазылуу мүмкүнчүлүгүн кошуп жатабыз. (2-бөлүк) - "Адан Яга чейин Java долбоору"

Группада жарыяланган
Баарына салам! Өткөн аптада баштаган ишибиздин үстүндө иштөөнү улантып жатабыз ."Java долбоору Адан Яга": макалалардын тобуна жазылуу мүмкүнчүлүгүн кошуу.  2-1-бөлүк

JRTB-5ти ишке ашырабыз

Эми биз JavaRush макалаларынын кээ бир тобуна жазылуу үчүн буйрукту кошушубуз керек. Муну кандай жасаш керек? Мен ойлоп тапкан эң жөнөкөй сценарий боюнча чыгабыз. Бизде топтун идентификатору боюнча кирүү мүмкүнчүлүгү бар болгондуктан, аны өткөрүп берүү үчүн колдонуучу керек. Бул үчүн колдонуучу /addGroupSub GROUP_ID буйругун киргизет, ал эки жолдун биринде иштейт: эгерде команданын өзү гана келсе: /addGroupSub , бардык топтордун тизмеси жана алардын идентификаторлору жооп катары жөнөтүлөт. Андан кийин колдонуучу өзүнө керектүү топтун идентификаторун тандап, бул буйрукта суроо-талаптын экинчи versionсын түзө алат: /addGroupSub GROUP_ID - андан кийин бул колдонуучу менен бул топтун жазуусу болот. Келечекте жакшыраак иштей алабыз деп ойлойм. Биздин максат - супер сонун колдонуучу тажрыйбасын эмес, өнүгүүнү көрсөтүү (мен айткандан уялам, бирок орусча бул деген терминди билбейм). Бүтүндөй тиркеме аркылуу өтүүчү функцияны туура кошуу үчүн (биздин учурда, телеграмма бот кардарынан маалымат базасына чейин), сиз кандайдыр бир аягында башташыңыз керек. Биз муну маалымат базасынан жасайбыз.

Маалымат базасына жаңы миграция кошуу

Биринчи нерсе - жаңы маалымат базасын көчүрүү жана JRде колдонуучулар тобунун жазылуу маалыматтарын сактоо мүмкүнчүлүгүн кошуу. Бул кандай болушу керектигин эстеп калуу үчүн, макалага кайтыңыз " Долбоорду пландаштыруу: жети жолу өлчөө ." Экинчи сүрөттө маалымат базасынын болжолдуу диаграммасы бар. Биз топтун маалыматын сактоо үчүн table кошуу керек:
  • JavaRush ичиндеги топтун идентификатору да биздин ID болот. Биз аларга ишенебиз жана бул ID'лер уникалдуу деп эсептейбиз;
  • аталышы - биздин сүрөттөрдө ал аты болгон - топтун расмий эмес аталышы; башкача айтканда, биз JavaRush веб-сайтында эмнени көрөбүз;
  • last_article_id - бул кызыктуу талаа. Ал бот өзүнүн жазылуучуларына жөнөткөн макаланын акыркы идентификаторун ушул топто сактайт. Бул талааны колдонуу менен жаңы макалаларды издөө механизми иштейт. Жаңы жазылуучулар колдонуучу жазылганга чейин жарыяланган макалаларды алышпайт: топко жазылгандан кийин жарыяланган макалалар гана.
Биз ошондой эле топтор менен колдонуучулардын tableсынын ортосунда көптөн көпкө байланышка ээ болобуз, анткени ар бир колдонуучу көп топко жазыла алат (бирден көпкө) жана ар бир топко жазылууда көп колдонуучулар болушу мүмкүн (бирден көпкө, бир гана башка жагынан). Көрсө, бул биздин көп-көп болот экен. Суроолору барлар үчүн базадагы макалаларды карап чыгыңыз. Ооба, мен жакында 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)
);
Белгилей кетчү нерсе, адегенде мен эски tableны өзгөртөм - мен ага негизги ачкычты кошом. Мен аны кандайдыр бир жол менен сагындым, бирок азыр MySQL мага gorup_x_user tableсы үчүн ТЫШКЫ АЧКЫЧты кошууга мүмкүнчүлүк берген жок жана бул миграциянын алкагында мен маалымат базасын жаңырттым. Маанилүү аспектке көңүл буруңуз. Маалыматтар базасын өзгөртүү дал ушул жол менен жасалышы керек - керектүү нерселердин баары жаңы миграцияда болот, бирок буга чейин чыгарылган миграцияны жаңылоо менен эмес. Ооба, биздин учурда эч нерсе болмок эмес, анткени бул сыноо долбоору жана ал бир гана жерге жайгаштырылып жатканын билебиз, бирок бул туура эмес мамиле болмок. Бирок биз баары туура болушун каалайбыз. Андан кийин tableларды түзүүдөн мурун жок кылуу керек. Эмнеге бул? Эгер кандайдыр бир кокустан маалымат базасында ушундай аталыштар бар tableлар болсо, көчүрүү иштебей калмак жана күтүлгөндөй иштеши үчүн. Анан эки table кошобуз. Баары биз каалагандай болду. Эми биз колдонмобузду ишке киргизишибиз керек. Эгер баары башталып, бузулбаса, анда миграция катталат. Жана муну дагы бир жолу текшерүү үчүн, биз маалымат базасына барабыз: а) мындай tableлар пайда болгон; б) учуу жолунун техникалык tableсында жаңы жазуу бар. Бул миграциялык иштерди бүтүрөт, келгиле репозиторийлерге өтөбүз.

Репозиторий катмарын кошуу

Spring Boot маалыматтарынын аркасында бул жерде бардыгы абдан жөнөкөй: биз GroupSub an objectисин кошуп, TelegramUserди бир аз жаңыртышыбыз керек жана дээрлик бош GroupSubRepository кошуубуз керек: GroupSub an objectисин 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 an objectинде жазылган кошулмаларды колдонот. Жана, чындыгында, 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 an objectиси үчүн бирдей маанидеги тестти кошолу. Бул үчүн, келгиле, 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);
   }
}
Жазгы маалыматтар туура иштеши жана көптөн көпкө жазуу түзүлүшү үчүн, биз түзүп жаткан жазылуу тобу үчүн маалымат базасынан колдонуучуну алып, GroupSub an objectисине кошуубуз керек. Ошентип, биз бул жазылууну сактоого өткөрүп бергенде, group_x_user tableсы аркылуу да байланыш түзүлөт. Мындай жазылуу тобу мурунтан эле түзүлгөн кырдаал болушу мүмкүн жана ага башка колдонуучуну кошуу керек. Бул үчүн биз адегенде базадан топтун идентификаторун алабыз, эгер жазуу болсо аны менен иштейбиз, жок болсо жаңысын түзөбүз. Белгилей кетчү нерсе, TelegramUser менен иштөө үчүн биз TelegramUserService кызматын акыркы SOLID принциптерин кармануу үчүн колдонобуз. Учурда ID боюнча жазууну таппай калсак, мен жөн гана өзгөчөлүктү таштайм. Азыр эч кандай жол менен иштетилбей жатат: биз муну эң аягында, MVP алдында жасайбыз. GroupSubServiceTest классы үчүн эки бирдик тесттерин жазалы . Бизге кайсынысы керек? Сактоо ыкмасы GroupSubRepository'де чакырылып, бир колдонуучу бар уюм GroupSub'ка өткөрүлүп берилерине ишенгим келет - ал берилген ID аркылуу TelegramUserService бизге кайтарып берет. Ал эми экинчи вариант, ошол эле идентификатору бар топ маалымат базасында мурунтан эле бар болгондо жана бул топтун бир колдонуучусу бар болсо жана бул топко башка колдонуучу кошулуп, бул an object сакталаарын текшерүү керек. Бул жерде ишке ашыруу болуп саналат:
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) - анда m1 ыкмасы o1 an objectисинде a1 аргументи менен чакырылганда , метод o2 an objectисин кайтарат деп айтабыз . Бул мокитонун дээрлик эң маанилүү функционалдуулугу - жасалма an objectти бизге керектүү нерсени кайтарууга мажбурлоо;

  • Mockito.verify(o1).m1(a1) - m1 ыкмасы a1 аргументи менен o1 an objectисинде чакырылганын текшерет . Сактоо ыкмасынын кайтарылган an objectисин колдонсо болот, албетте, мүмкүн болчу, бирок мен башка мүмкүн болгон ыкманы көрсөтүү менен аны бир аз татаалдаштырууну чечтим. Качан пайдалуу болушу мүмкүн? Жалган сабактардын ыкмалары жараксыз болуп калган учурларда. Анда Mockito.verify жок жумуш болбойт)))

Биз тесттерди жазуу керек, алардын көбүн жазуу керек деген идеяны карманып келебиз. Кийинки этап телеграмма бот командасы менен иштөө.

/addGroupSub буйругун түзүңүз

Бул жерде биз төмөнкү логиканы аткарышыбыз керек: эгерде биз эч кандай контекстсиз эле буйрук алсак, анда биз колдонуучуга жардам беребиз жана ага керектүү маалыматты ботко өткөрүп бериши үчүн, анын ID'лери менен бардык топтордун тизмесин беребиз. Ал эми колдонуучу ботко башка сөз(дер) менен буйрук жөнөтсө, ошол ID менен топту табыңыз же андай топ жок деп жазыңыз. Келгиле, биздин аталышыбызга жаңы маани кошолу - 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нын үч бөлүгүн тең камтыйт жана бул макалага чейин жеткorктүү болот. Бул тууралуу кантип билсе болот? Бул оңой - телеграм каналына кошулуңуз , анда мен телеграм боту жөнүндө макалаларым тууралуу бардык маалыматты жарыялайм. окуганыңыз үчүн рахмат! 3-бөлүк бул жерде .

Сериядагы бардык материалдардын тизмеси ушул макаланын башында.

Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION