JavaRush /Java Blog /Random-ID /Kami menambahkan kemampuan untuk berlangganan sekelompok ...

Kami menambahkan kemampuan untuk berlangganan sekelompok artikel. (Bagian 2) - "Proyek Java dari A sampai Z"

Dipublikasikan di grup Random-ID
Halo semua! Kami terus mengerjakan tugas yang kami mulai minggu lalu ."Proyek Java dari A hingga Z": Menambahkan kemampuan untuk berlangganan sekelompok artikel.  Bagian 2 - 1

Kami menerapkan JRTB-5

Sekarang kita perlu menambahkan perintah agar kita dapat berlangganan beberapa grup artikel dari JavaRush. Bagaimana cara melakukannya? Kami akan mengikuti skenario paling sederhana yang saya buat. Karena kami memiliki akses berdasarkan ID grup, kami memerlukan pengguna untuk mentransfernya. Untuk melakukan ini, pengguna akan memasukkan perintah /addGroupSub GROUP_ID, yang akan bekerja dengan salah satu dari dua cara: jika hanya perintah itu sendiri yang muncul: /addGroupSub , daftar semua grup dan ID mereka dikirim sebagai respons. Kemudian pengguna akan dapat memilih ID grup yang dia perlukan dan membuat permintaan versi kedua dalam perintah ini: /addGroupSub GROUP_ID - dan kemudian akan ada catatan grup ini dengan pengguna ini. Saya pikir kami bisa melakukan yang lebih baik di masa depan. Tujuan kami adalah untuk menunjukkan perkembangannya, dan bukan pengalaman pengguna yang sangat keren (saya malu mengatakannya, tapi saya tidak tahu istilah dalam bahasa Rusia yang berarti demikian). Untuk menambahkan fungsionalitas dengan benar ke seluruh aplikasi (dalam kasus kami, dari klien bot telegram ke database), Anda harus memulai dari akhir. Kami akan melakukan ini dari sisi database.

Menambahkan migrasi baru ke database

Hal pertama yang harus dilakukan adalah menambahkan migrasi database baru dan kemampuan untuk menyimpan data langganan grup pengguna di JR. Untuk mengingat bagaimana seharusnya, kembalilah ke artikel “ Perencanaan proyek: ukur tujuh kali .” Di foto kedua ada diagram perkiraan database. Kita perlu menambahkan tabel untuk menyimpan informasi grup:
  • ID grup di JavaRush juga akan menjadi ID kami. Kami memercayai mereka dan yakin bahwa ID ini unik;
  • judul - di gambar kami ada nama - nama informal grup; itulah yang kita lihat di situs JavaRush;
  • last_article_id - dan ini adalah bidang yang menarik. Ini akan menyimpan ID terakhir artikel di grup ini, yang telah dikirimkan bot ke pelanggannya. Dengan menggunakan kolom ini, mekanisme pencarian artikel baru akan berfungsi. Pelanggan baru tidak akan menerima artikel yang diterbitkan sebelum pengguna berlangganan: hanya artikel yang diterbitkan setelah berlangganan grup.
Kita juga akan memiliki hubungan banyak ke banyak antara tabel grup dan pengguna, karena setiap pengguna dapat memiliki banyak langganan grup (satu-ke-banyak), dan setiap langganan grup dapat memiliki banyak pengguna (satu-ke-banyak, hanya di sisi lain). Ternyata ini akan menjadi banyak-ke-banyak bagi kita. Bagi yang memiliki pertanyaan, tinjau artikel di database. Ya, saya berencana segera membuat postingan di saluran Telegram, di mana saya akan mengumpulkan semua artikel di database. Seperti inilah tampilan migrasi database kedua kita.
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)
);
Penting untuk dicatat bahwa pertama-tama saya mengubah tabel lama - saya menambahkan kunci utama ke dalamnya. Saya entah bagaimana melewatkan ini pada saat itu, tetapi sekarang MySQL tidak memberi saya kesempatan untuk menambahkan KUNCI ASING untuk tabel gorup_x_user, dan sebagai bagian dari migrasi ini saya memperbarui database. Harap perhatikan aspek penting. Mengubah database harus dilakukan persis seperti ini - semua yang diperlukan ada dalam migrasi baru, tetapi tidak dengan memperbarui migrasi yang sudah dirilis. Ya, dalam kasus kami tidak akan terjadi apa-apa, karena ini adalah proyek uji coba dan kami tahu bahwa proyek ini diterapkan hanya di satu tempat, tetapi ini akan menjadi pendekatan yang salah. Tapi kami ingin semuanya baik-baik saja. Berikutnya adalah menghapus tabel sebelum membuatnya. Kenapa ini? Sehingga jika kebetulan ada tabel dengan nama seperti itu di database, migrasi tidak akan gagal dan akan berfungsi seperti yang diharapkan. Dan kemudian kami menambahkan dua tabel. Semuanya seperti yang kami inginkan. Sekarang kita perlu meluncurkan aplikasi kita. Jika semuanya dimulai dan tidak terputus, maka migrasi dicatat. Dan untuk memeriksa ulang ini, kita masuk ke database untuk memastikan bahwa: a) tabel tersebut telah muncul; b) terdapat entri baru pada tabel teknis jalur terbang. Ini menyelesaikan pekerjaan migrasi, mari beralih ke repositori.

Menambahkan lapisan repositori

Berkat Spring Boot Data, semuanya menjadi sangat sederhana di sini: kita perlu menambahkan entitas GroupSub, sedikit memperbarui TelegramUser dan menambahkan GroupSubRepository yang hampir kosong: Kami menambahkan entitas GroupSub ke paket yang sama dengan 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);
   }
}
Satu hal yang perlu diperhatikan adalah kami memiliki kolom pengguna tambahan yang akan berisi kumpulan semua pengguna yang berlangganan grup. Dan dua anotasi - ManyToMany dan JoinTable - adalah apa yang kita perlukan untuk ini. Bidang yang sama perlu ditambahkan untuk TelegramUser:
@ManyToMany(mappedBy = "users", fetch = FetchType.EAGER)
private List<GroupSub> groupSubs;
Bidang ini menggunakan gabungan yang ditulis dalam entitas GroupSub. Dan faktanya, kelas repositori kami untuk GroupSub adalah 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> {
}
Pada tahap ini, kita tidak memerlukan metode tambahan: metode yang diterapkan di nenek moyang JpaRepository sudah cukup bagi kita. Mari kita tulis tes di TelegramUserRepositoryIT yang akan memeriksa apakah many-to-many kita berfungsi. Ide pengujiannya adalah kami akan menambahkan 5 grup langganan per pengguna ke database melalui skrip sql, mendapatkan pengguna ini dengan ID-nya dan memeriksa apakah kami menerima grup tersebut dengan tepat dan dengan nilai yang persis sama. Bagaimana cara melakukannya? Anda dapat menyematkan penghitung ke dalam data, yang kemudian dapat kami periksa dan periksa. Berikut ini skrip 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);
Dan tesnya sendiri:
@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());
   }
}
Sekarang mari kita tambahkan tes dengan arti yang sama untuk entitas GroupSub. Untuk melakukannya, mari buat kelas pengujian groupSubRepositoryIT dalam paket yang sama dengan 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());
       }
   }
}
Dan skrip fiveUsersForGroupSub.sql hilang:
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);
Pada titik ini, sebagian pekerjaan dengan repositori dapat dianggap selesai. Sekarang mari kita menulis lapisan layanan.

Kami menulis GroupSubService

Pada tahap ini, untuk bekerja dengan grup langganan, kita hanya perlu menyimpannya, jadi tidak ada masalah: kita membuat layanan GroupSubService dan implementasi GroupSubServiceImpl dalam paket yang berisi layanan - layanan lain:
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);
}
Dan implementasinya:
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);
   }
}
Agar Spring Data berfungsi dengan benar dan catatan banyak-ke-banyak dapat dibuat, kita perlu mendapatkan pengguna dari database untuk grup langganan yang kita buat dan menambahkannya ke objek GroupSub. Jadi, saat kita mentransfer langganan ini untuk disimpan, koneksi juga akan dibuat melalui tabel group_x_user. Mungkin ada situasi ketika grup langganan tersebut telah dibuat dan Anda hanya perlu menambahkan pengguna lain ke dalamnya. Untuk melakukan ini, pertama-tama kita mendapatkan ID grup dari database, dan jika ada catatan, kami mengerjakannya, jika tidak, kami membuat yang baru. Penting untuk dicatat bahwa untuk bekerja dengan TelegramUser kami menggunakan TelegramUserService untuk mengikuti prinsip SOLID yang terakhir. Saat ini, jika kami tidak menemukan catatan berdasarkan ID, saya hanya memberikan pengecualian. Itu tidak diproses dengan cara apa pun sekarang: kami akan melakukan ini di bagian paling akhir, sebelum MVP. Mari kita tulis dua pengujian unit untuk kelas GroupSubServiceTest . Yang mana yang kita butuhkan? Saya ingin memastikan bahwa metode penyimpanan akan dipanggil di GroupSubRepository dan entitas dengan satu pengguna akan diteruskan ke GroupSub - entitas yang akan mengembalikan TelegramUserService kepada kami menggunakan ID yang diberikan. Dan opsi kedua, ketika grup dengan ID yang sama sudah ada di database dan grup ini sudah memiliki satu pengguna, dan Anda perlu memeriksa apakah pengguna lain akan ditambahkan ke grup ini dan objek ini akan disimpan. Berikut implementasinya:
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);
   }

}
Saya juga menambahkan metode init() dengan anotasi BeforeEach. Dengan cara ini, mereka biasanya membuat metode yang akan dieksekusi sebelum setiap pengujian dijalankan, dan dimungkinkan untuk memasukkan logika umum ke dalamnya untuk semua pengujian. Dalam kasus kita, kita perlu mengunci TelegramUserService dengan cara yang sama untuk semua pengujian kelas ini, jadi masuk akal untuk mentransfer logika ini ke metode umum. Ada dua desain mokito yang digunakan di sini:
  • Mockito.when(o1.m1(a1)).thenReturn(o2) - di dalamnya kita mengatakan bahwa ketika metode m1 dipanggil pada objek o1 dengan argumen a1 , metode tersebut akan mengembalikan objek o2 . Ini hampir merupakan fungsi mockito yang paling penting - untuk memaksa objek tiruan mengembalikan apa yang kita butuhkan;

  • Mockito.verify(o1).m1(a1) - yang memverifikasi bahwa metode m1 dipanggil pada objek o1 dengan argumen a1 . Tentu saja dimungkinkan untuk menggunakan objek yang dikembalikan dari metode simpan, tetapi saya memutuskan untuk membuatnya sedikit lebih rumit dengan menunjukkan metode lain yang mungkin. Kapan itu bisa berguna? Dalam kasus di mana metode kelas tiruan menghasilkan kekosongan. Maka tanpa Mockito.verify tidak akan ada pekerjaan)))

Kami terus berpegang pada gagasan bahwa tes perlu ditulis, dan banyak tes yang perlu ditulis. Tahap selanjutnya adalah bekerja sama dengan tim bot telegram.

Buat perintah /addGroupSub

Di sini kita perlu melakukan logika berikut: jika kita hanya menerima perintah, tanpa konteks apa pun, kita membantu pengguna dan memberinya daftar semua grup dengan ID mereka sehingga ia dapat meneruskan informasi yang diperlukan ke bot. Dan jika pengguna mengirimkan perintah ke bot dengan beberapa kata lain, temukan grup dengan ID tersebut atau tulis bahwa tidak ada grup tersebut. Mari tambahkan nilai baru di ename kita - CommandName:
ADD_GROUP_SUB("/addgroupsub")
Mari beralih lebih jauh dari database ke bot telegram - buat kelas AddGroupSubCommand di paket perintah:
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));
   }
}
Kelas ini menggunakan metode isNumeric dari perpustakaan Apache-commons, jadi mari tambahkan ke memori kita:
<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-lang3</artifactId>
  <version>${apache.commons.version}</version>
</dependency>
Dan di blok properti:
<apache.commons.version>3.11</apache.commons.version>
Semua logika ini ada di kelas. Bacalah dengan cermat. Jika Anda memiliki pertanyaan/saran, tulis di komentar. Setelah ini, kita perlu menambahkan perintah ke CommandContainer di peta perintah kita:
.put(ADD_GROUP_SUB.getCommandName(), new AddGroupSubCommand(sendBotMessageService, javaRushGroupClient, groupSubService))
Dan segalanya untuk tim ini. Saya ingin menguji fungsionalitas ini, tetapi sejauh ini saya hanya dapat melihatnya di database. Di bagian ketiga, saya akan menambahkan perubahan dari JRTB-6 sehingga kita dapat melihat daftar grup tempat pengguna berlangganan. Sekarang ada baiknya untuk memeriksa semua ini. Untuk melakukan ini, kami akan melakukan semua tindakan di Telegram dan memeriksa database. Karena kami telah menulis tes, semuanya akan baik-baik saja. Artikelnya sudah cukup panjang, jadi nanti kita akan menulis tes untuk AddGroupSubCommand, dan menambahkan TODO di kodenya agar tidak lupa.

kesimpulan

Pada artikel ini, kita melihat pekerjaan menambahkan fungsionalitas melalui seluruh aplikasi, mulai dari database dan diakhiri dengan bekerja dengan klien yang menggunakan bot. Biasanya tugas-tugas seperti itu membantu untuk memahami proyek dan memahami esensinya. Pahami cara kerjanya. Saat ini topiknya tidak mudah, jadi jangan malu-malu: tulis pertanyaan Anda di komentar, dan saya akan mencoba menjawabnya. Apakah Anda menyukai proyek ini? Beri bintang di Github : dengan cara ini akan terlihat jelas bahwa mereka tertarik dengan proyek tersebut, dan saya akan senang. Seperti kata pepatah, seorang master selalu senang jika karyanya diapresiasi. Kode akan berisi ketiga bagian STEP_6 dan akan tersedia sebelum artikel ini. Bagaimana cara mengetahuinya? Mudah - bergabunglah dengan saluran telegram , tempat saya mempublikasikan semua informasi tentang artikel saya tentang bot telegram. Terima kasih sudah membaca! Bagian 3 sudah ada di sini .

Daftar semua materi dalam seri ini ada di awal artikel ini.

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