JavaRush /Java blogi /Random-UZ /Biz maqolalar guruhiga obuna bo'lish imkoniyatini qo'shmo...

Biz maqolalar guruhiga obuna bo'lish imkoniyatini qo'shmoqdamiz. (2-qism) - "A dan Zgacha Java loyihasi"

Guruhda nashr etilgan
Hammaga salom! O'tgan hafta boshlagan vazifamiz ustida ishlashda davom etamiz ."A dan Zgacha Java loyihasi": Maqolalar guruhiga obuna bo'lish imkoniyatini qo'shish.  2-1-qism

Biz JRTB-5 ni amalga oshiramiz

Endi biz JavaRush-dan ba'zi maqolalar guruhiga obuna bo'lishimiz uchun buyruq qo'shishimiz kerak. Buni qanday qilish kerak? Men o'ylab topgan eng oddiy stsenariyga amal qilamiz. Guruh identifikatori orqali kirish imkonimiz borligi sababli, uni o'tkazish uchun bizga foydalanuvchi kerak. Buning uchun foydalanuvchi /addGroupSub GROUP_ID buyrug'ini kiritadi, bu ikki usuldan birida ishlaydi: agar faqat buyruqning o'zi kelsa: /addGroupSub , javob sifatida barcha guruhlar ro'yxati va ularning identifikatorlari yuboriladi. Keyin foydalanuvchi o'ziga kerak bo'lgan guruh identifikatorini tanlashi va ushbu buyruqda so'rovning ikkinchi versiyasini yaratishi mumkin: /addGroupSub GROUP_ID - va keyin ushbu foydalanuvchi bilan ushbu guruhning yozuvi bo'ladi. O'ylaymanki, biz kelajakda yaxshiroq ish qila olamiz. Bizning maqsadimiz ajoyib foydalanuvchi tajribasini emas, balki rivojlanishni ko'rsatishdir (aytishga uyalaman, lekin rus tilida buni anglatuvchi atamani bilmayman). Butun ilova bo'ylab o'tadigan funksionallikni to'g'ri qo'shish uchun (bizning holatlarimizda, telegram bot mijozidan ma'lumotlar bazasigacha) siz qaysidir nuqtadan boshlashingiz kerak. Biz buni ma'lumotlar bazasi tomonidan qilamiz.

Ma'lumotlar bazasiga yangi migratsiya qo'shish

Qilish kerak bo'lgan birinchi narsa - yangi ma'lumotlar bazasi migratsiyasini va JR-da foydalanuvchi guruhi obuna ma'lumotlarini saqlash qobiliyatini qo'shish. Bu qanday bo'lishi kerakligini eslash uchun " Loyihani rejalashtirish: etti marta o'lchash " maqolasiga qayting . Ikkinchi fotosuratda ma'lumotlar bazasining taxminiy diagrammasi mavjud. Guruh ma'lumotlarini saqlash uchun jadval qo'shishimiz kerak:
  • JavaRush-dagi guruh identifikatori ham bizning identifikatorimiz bo'ladi. Biz ularga ishonamiz va bu identifikatorlar noyob ekanligiga ishonamiz;
  • sarlavha - bizning rasmlarimizda bu nom edi - guruhning norasmiy nomi; ya'ni JavaRush veb-saytida ko'rgan narsamiz;
  • last_article_id - va bu qiziqarli maydon. U ushbu guruhdagi maqolaning so'nggi identifikatorini saqlaydi, bot allaqachon o'z obunachilariga yuborgan. Ushbu maydondan foydalanib, yangi maqolalarni qidirish mexanizmi ishlaydi. Yangi obunachilar foydalanuvchi obuna bo'lishidan oldin chop etilgan maqolalarni olmaydilar: faqat guruhga obuna bo'lgandan keyin nashr etilgan maqolalar.
Shuningdek, biz guruhlar va foydalanuvchilar jadvali o‘rtasida ko‘pdan ko‘pga munosabatga ega bo‘lamiz, chunki har bir foydalanuvchi ko‘plab guruh obunalariga ega bo‘lishi mumkin (birdan ko‘pga) va har bir guruh obunasida ko‘p foydalanuvchi bo‘lishi mumkin (birdan ko‘pga, faqat boshqa tomonda). Ma'lum bo'lishicha, bu bizning ko'p-ko'p bo'ladi. Savollari bo'lganlar uchun ma'lumotlar bazasidagi maqolalarni ko'rib chiqing. Ha, men tez orada Telegram kanalida post yaratishni rejalashtiryapman, u erda ma'lumotlar bazasidagi barcha maqolalarni jamlayman. Bizning ikkinchi ma'lumotlar bazasi ko'chishimiz shunday ko'rinadi.
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)
);
Shuni ta'kidlash kerakki, avval men eski jadvalni o'zgartiraman - unga asosiy kalit qo'shaman. O'sha paytda men buni qandaydir tarzda o'tkazib yubordim, lekin endi MySQL gorup_x_user jadvali uchun FOREIGN KEY qo'shish imkoniyatini bermadi va bu migratsiyaning bir qismi sifatida ma'lumotlar bazasini yangiladim. Muhim jihatga e'tibor bering. Ma'lumotlar bazasini o'zgartirish aynan shu tarzda amalga oshirilishi kerak - kerak bo'lgan hamma narsa yangi migratsiyada bo'ladi, lekin allaqachon chiqarilgan migratsiyani yangilash orqali emas. Ha, bizning holatlarimizda hech narsa bo'lmaydi, chunki bu sinov loyihasi va biz bilamizki, u faqat bitta joyda joylashtirilgan, ammo bu noto'g'ri yondashuv bo'ladi. Lekin biz hamma narsa to'g'ri bo'lishini xohlaymiz. Keyinchalik, ularni yaratishdan oldin jadvallarni o'chirish keladi. Nima uchun bu? Shunday qilib, agar tasodifan ma'lumotlar bazasida bunday nomlar bilan jadvallar mavjud bo'lsa, migratsiya muvaffaqiyatsiz bo'lmaydi va xuddi kutilganidek ishlaydi. Va keyin biz ikkita jadvalni qo'shamiz. Hammasi biz xohlagandek edi. Endi biz ilovamizni ishga tushirishimiz kerak. Agar hamma narsa boshlansa va buzilmasa, u holda migratsiya qayd etiladi. Va buni ikki marta tekshirish uchun biz ma'lumotlar bazasiga ishonch hosil qilish uchun o'tamiz: a) bunday jadvallar paydo bo'lgan; b) parvoz yo'lining texnik jadvalida yangi yozuv mavjud. Bu migratsiya ishlarini yakunlaydi, keling, omborlarga o'tamiz.

Repozitoriy qatlamini qo'shish

Spring Boot Data tufayli bu erda hamma narsa juda oddiy: biz GroupSub ob'ektini qo'shishimiz, TelegramUserni biroz yangilashimiz va deyarli bo'sh GroupSubRepository qo'shishimiz kerak: GroupSub ob'ektini TelegramUser bilan bir xil paketga qo'shamiz:
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);
   }
}
Shuni ta'kidlash kerakki, bizda guruhga obuna bo'lgan barcha foydalanuvchilar to'plamini o'z ichiga olgan qo'shimcha foydalanuvchilar maydoni mavjud. Va ikkita izoh - ManyToMany va JoinTable - bu bizga kerak bo'lgan narsadir. Xuddi shu maydon TelegramUser uchun qo'shilishi kerak:
@ManyToMany(mappedBy = "users", fetch = FetchType.EAGER)
private List<GroupSub> groupSubs;
Bu maydon GroupSub ob'ektida yozilgan birlashmalardan foydalanadi. Va, aslida, GroupSub uchun bizning omborimiz klassi GroupSubRepository hisoblanadi :
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> {
}
Ushbu bosqichda bizga qo'shimcha usullar kerak emas: JpaRepository ajdodida amalga oshirilganlar biz uchun etarli. Keling, TelegramUserRepositoryIT-da test yozamiz, u bizning ko'pdan ko'pga ishlashini tekshiradi. Sinovning g'oyasi shundan iboratki, biz SQL skripti orqali ma'lumotlar bazasiga har bir foydalanuvchi uchun 5 ta obuna guruhini qo'shamiz, ushbu foydalanuvchini uning identifikatori bo'yicha olamiz va aynan shu guruhlarni va aynan bir xil qiymatlarni olganimizni tekshiramiz. Buni qanday qilish kerak? Hisoblagichni ma'lumotlarga joylashtirishingiz mumkin, keyin biz uni tekshirib ko'ramiz. Mana FiveGroupSubsForUser.sql skripti:
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);
Va sinovning o'zi:
@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());
   }
}
Endi GroupSub ob'ekti uchun bir xil ma'noga ega testni qo'shamiz. Buni amalga oshirish uchun groupSubRepositoryIT bilan bir xil paketda groupSubRepositoryIT test sinfini yaratamiz :
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());
       }
   }
}
Va etishmayotgan beshUsersForGroupSub.sql skripti:
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);
Shu nuqtada, ombor bilan ishlashning bir qismini tugallangan deb hisoblash mumkin. Endi xizmat qatlamini yozamiz.

Biz GroupSubService yozamiz

Ushbu bosqichda, obunalar guruhlari bilan ishlash uchun biz faqat ularni saqlab qolishimiz kerak, shuning uchun muammo yo'q: biz GroupSubService xizmatini yaratamiz va uning GroupSubServiceImpl-ni boshqa xizmatlarni o'z ichiga olgan paketda amalga oshiramiz - xizmat:
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);
}
Va uni amalga oshirish:
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 to'g'ri ishlashi va ko'pdan ko'pga yozuv yaratilishi uchun biz yaratayotgan obuna guruhi uchun ma'lumotlar bazasidan foydalanuvchini olishimiz va GroupSub ob'ektiga qo'shishimiz kerak. Shunday qilib, biz ushbu obunani saqlashga o'tkazganimizda, ulanish group_x_user jadvali orqali ham yaratiladi. Bunday obuna guruhi allaqachon yaratilgan va siz unga boshqa foydalanuvchi qo'shishingiz kerak bo'lgan vaziyat bo'lishi mumkin. Buning uchun birinchi navbatda ma'lumotlar bazasidan guruh identifikatorini olamiz, agar yozuv bo'lsa, u bilan ishlaymiz, bo'lmasa, biz yangisini yaratamiz. Shuni ta'kidlash kerakki, TelegramUser bilan ishlash uchun biz TelegramUserService-dan so'nggi SOLID tamoyillariga amal qilish uchun foydalanamiz. Ayni paytda, agar ID bo'yicha rekord topa olmasak, men faqat istisno qilaman. Hozir hech qanday tarzda qayta ishlanmayapti: biz buni eng oxirida, MVPdan oldin qilamiz. Keling, GroupSubServiceTest klassi uchun ikkita birlik testini yozaylik . Bizga qaysilari kerak? Ishonchim komilki, saqlash usuli GroupSubRepository-da chaqiriladi va bitta foydalanuvchiga ega bo'lgan ob'ekt GroupSub-ga o'tkaziladi - u taqdim etilgan identifikator yordamida TelegramUserService-ni bizga qaytaradi. Va ikkinchi variant, agar bir xil identifikatorga ega bo'lgan guruh allaqachon ma'lumotlar bazasida bo'lsa va bu guruh allaqachon bitta foydalanuvchiga ega bo'lsa va siz ushbu guruhga boshqa foydalanuvchi qo'shilishi va ushbu ob'ekt saqlanadiganligini tekshirishingiz kerak. Mana amalga oshirish:
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);
   }

}
Bundan tashqari, init() usulini BeforeEach izohi bilan qo'shdim . Shu tarzda, ular odatda har bir testdan oldin bajariladigan usulni yaratadilar va unga barcha testlar uchun umumiy mantiqni kiritish mumkin. Bizning holatda, biz TelegramUserService-ni ushbu sinfning barcha testlari uchun xuddi shunday tarzda bloklashimiz kerak, shuning uchun bu mantiqni umumiy usulga o'tkazish mantiqan. Bu erda ikkita mokito dizayni qo'llaniladi:
  • Mockito.when(o1.m1(a1)).thenReturn(o2) - unda aytamizki, m1 usuli o1 ob'ektida a1 argumenti bilan chaqirilganda , usul o2 ob'ektini qaytaradi . Bu mokitoning deyarli eng muhim funksionalligi - soxta ob'ektni bizga kerak bo'lgan narsani qaytarishga majburlash;

  • Mockito.verify(o1).m1(a1) - bu m1 usuli o1 ob'ektida a1 argumenti bilan chaqirilganligini tasdiqlaydi . Albatta, saqlash usulining qaytarilgan ob'ektidan foydalanish mumkin edi, lekin men boshqa mumkin bo'lgan usulni ko'rsatib, uni biroz murakkablashtirishga qaror qildim. Qachon foydali bo'lishi mumkin? Soxta darslar usullari bekor qilingan hollarda. Keyin Mockito.verify holda ish bo'lmaydi)))

Biz testlar yozilishi kerak va ularning ko'pi yozilishi kerak degan fikrga amal qilishda davom etamiz. Keyingi bosqich - telegram bot jamoasi bilan ishlash.

/addGroupSub buyrug'ini yarating

Bu erda biz quyidagi mantiqni bajarishimiz kerak: agar biz hech qanday kontekstsiz shunchaki buyruq olsak, foydalanuvchiga yordam beramiz va botga kerakli ma'lumotlarni uzatishi uchun unga barcha guruhlar ro'yxatini ularning identifikatorlari bilan beramiz. Agar foydalanuvchi boshqa so'z(lar) bilan botga buyruq yuborsa, o'sha identifikatorli guruhni toping yoki bunday guruh yo'qligini yozing. Keling, nomimizga yangi qiymat qo'shamiz - Buyruqning nomi:
ADD_GROUP_SUB("/addgroupsub")
Keling, ma'lumotlar bazasidan telegram botga o'tamiz - buyruqlar paketida AddGroupSubCommand sinfini yarating:
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));
   }
}
Bu sinf apache-commons kutubxonasidagi isNumeric usulidan foydalanadi , shuning uchun uni xotiramizga qo'shamiz:
<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-lang3</artifactId>
  <version>${apache.commons.version}</version>
</dependency>
Va xususiyatlar blokida:
<apache.commons.version>3.11</apache.commons.version>
Bu mantiqning barchasi sinfda. Uni diqqat bilan o'qing. Agar sizda biron bir savol/taklif bo'lsa, ularni izohlarda yozing. Shundan so'ng, biz buyruqlar xaritamizdagi CommandContainer-ga buyruq qo'shishimiz kerak:
.put(ADD_GROUP_SUB.getCommandName(), new AddGroupSubCommand(sendBotMessageService, javaRushGroupClient, groupSubService))
Va bu jamoa uchun hamma narsa. Men bu funksiyani qandaydir tarzda sinab ko'rmoqchiman, lekin hozircha men uni faqat ma'lumotlar bazasida ko'rib chiqa olaman. Uchinchi qismda men JRTB-6 dan o'zgarishlar kiritaman, shunda biz foydalanuvchi obuna bo'lgan guruhlar ro'yxatini ko'rishimiz mumkin. Endi bularning barchasini tekshirib ko'rish yaxshi bo'lardi. Buning uchun biz Telegram’dagi barcha amallarni bajaramiz va ma’lumotlar bazasida tekshiramiz. Biz testlarni yozganimiz uchun hamma narsa yaxshi bo'lishi kerak. Maqola ancha uzun, shuning uchun keyinroq AddGroupSubCommand uchun test yozamiz va unutmaslik uchun kodga TODO ni qo'shamiz.

xulosalar

Ushbu maqolada biz ma'lumotlar bazasidan tortib botdan foydalanadigan mijoz bilan ishlashgacha bo'lgan butun dastur orqali funksionallikni qo'shish ishini ko'rib chiqdik. Odatda bunday vazifalar loyihani tushunishga va uning mohiyatini tushunishga yordam beradi. Bu qanday ishlashini tushuning. Bugungi kunda mavzular oson emas, shuning uchun uyalmang: savollaringizni sharhlarda yozing, men ularga javob berishga harakat qilaman. Loyiha sizga yoqdimi? Bunga Github-da yulduz bering : shu tarzda ular loyihaga qiziqishlari aniq bo'ladi va men xursand bo'laman. Ustoz deganlaridek, mehnati qadrlansa, doim xursand bo‘ladi. Kod STEP_6 ning barcha uch qismini o'z ichiga oladi va ushbu maqoladan oldin mavjud bo'ladi. Bu haqda qanday bilish mumkin? Bu juda oson - telegram bot haqidagi maqolalarim haqidagi barcha ma'lumotlarni e'lon qiladigan telegram kanaliga qo'shiling. O'qiganingiz uchun tashakkur! 3-qism allaqachon shu yerda .

Seriyadagi barcha materiallar ro'yxati ushbu maqolaning boshida.

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