สวัสดีทุกคน! เรายังคงทำงานที่เราเริ่มเมื่อสัปดาห์ที่แล้วต่อไป
เราใช้ JRTB-5
ตอนนี้เราต้องเพิ่มคำสั่งเพื่อให้เราสามารถสมัครรับบทความบางกลุ่มจาก JavaRush ได้ ทำอย่างไร? เราจะทำตามสถานการณ์ที่ง่ายที่สุดที่ฉันคิดขึ้นมา เนื่องจากเราเข้าถึงได้ด้วย ID กลุ่ม เราจึงต้องการให้ผู้ใช้ถ่ายโอนข้อมูลนั้น ในการดำเนินการนี้ผู้ใช้จะต้องป้อนคำสั่ง/addGroupSub GROUP_ID ซึ่งจะทำงานในวิธีใดวิธีหนึ่งจากสองวิธี: หากมีเพียงคำสั่งเท่านั้นที่มา: /addGroupSubรายการของกลุ่มทั้งหมดและ ID ของพวกเขาจะถูกส่งเพื่อตอบสนอง จากนั้นผู้ใช้จะสามารถเลือก ID กลุ่มที่ต้องการและสร้างคำขอเวอร์ชันที่สองในคำสั่งนี้: /addGroupSub GROUP_ID - จากนั้นผู้ใช้รายนี้จะมีบันทึกของกลุ่มนี้ ฉันคิดว่าเราสามารถทำได้ดีกว่านี้ในอนาคต เป้าหมายของเราคือการแสดงการพัฒนา ไม่ใช่ประสบการณ์การใช้งานที่ยอดเยี่ยม (ฉันละอายใจที่จะพูด แต่ฉันไม่รู้ว่าคำในภาษารัสเซียจะหมายถึงสิ่งนี้) ในการเพิ่มฟังก์ชันการทำงานที่ถูกต้องผ่านแอปพลิเคชันทั้งหมด (ในกรณีของเราจากไคลเอ็นต์บอตโทรเลขไปยังฐานข้อมูล) คุณต้องเริ่มต้นที่จุดสิ้นสุด เราจะทำสิ่งนี้จากด้านฐานข้อมูลการเพิ่มการโยกย้ายใหม่ไปยังฐานข้อมูล
สิ่งแรกที่ต้องทำคือเพิ่มการย้ายฐานข้อมูลใหม่และความสามารถในการบันทึกข้อมูลการสมัครสมาชิกกลุ่มผู้ใช้ใน JR หากต้องการจดจำว่าควรเป็นอย่างไร ให้กลับไปที่บทความ “ การวางแผนโครงการ: วัดเจ็ดครั้ง ” ในรูปที่สองมีไดอะแกรมโดยประมาณของฐานข้อมูล เราจำเป็นต้องเพิ่มตารางเพื่อเก็บข้อมูลกลุ่ม:- ID กลุ่มใน JavaRush จะเป็น ID ของเราด้วย เราเชื่อถือและเชื่อว่า ID เหล่านี้ไม่ซ้ำกัน
- ชื่อเรื่อง - ในภาพของเราคือชื่อ - ชื่อที่ไม่เป็นทางการของกลุ่ม นั่นคือสิ่งที่เราเห็นบนเว็บไซต์ JavaRush
- Last_article_id - และนี่คือสาขาที่น่าสนใจ โดยจะเก็บ ID สุดท้ายของบทความในกลุ่มนี้ซึ่งบอทได้ส่งให้สมาชิกแล้ว เมื่อใช้ฟิลด์นี้ กลไกในการค้นหาบทความใหม่จะทำงานได้ สมาชิกใหม่จะไม่ได้รับบทความที่เผยแพร่ก่อนที่ผู้ใช้จะสมัครรับข้อมูล: เฉพาะบทความที่เผยแพร่หลังจากสมัครสมาชิกกลุ่มเท่านั้น
V00002__created_groupsub_many_to_many.sql:
-- add PRIMARY KEY FOR tg_user
ALTER TABLE tg_user ADD PRIMARY KEY (chat_id);
-- ensure that the tables with these names are removed before creating a new one.
DROP TABLE IF EXISTS group_sub;
DROP TABLE IF EXISTS group_x_user;
CREATE TABLE group_sub (
id INT,
title VARCHAR(100),
last_article_id INT,
PRIMARY KEY (id)
);
CREATE TABLE group_x_user (
group_sub_id INT NOT NULL,
user_id VARCHAR(100) NOT NULL,
FOREIGN KEY (user_id) REFERENCES tg_user(chat_id),
FOREIGN KEY (group_sub_id) REFERENCES group_sub(id),
UNIQUE(user_id, group_sub_id)
);
สิ่งสำคัญคือต้องทราบว่าก่อนอื่นฉันเปลี่ยนตารางเก่า - ฉันเพิ่มคีย์หลักลงไป ตอนนั้นฉันพลาดสิ่งนี้ไป แต่ตอนนี้ MySQL ไม่ได้ให้โอกาสฉันเพิ่มคีย์ต่างประเทศสำหรับตาราง gorup_x_user และฉันได้อัปเดตฐานข้อมูลในฐานะส่วนหนึ่งของการย้ายข้อมูลนี้ โปรดทราบประเด็นสำคัญ การเปลี่ยนฐานข้อมูลควรทำในลักษณะนี้ - ทุกสิ่งที่จำเป็นจะอยู่ในการย้ายข้อมูลใหม่ แต่ไม่ใช่โดยการอัปเดตการย้ายข้อมูลที่เผยแพร่แล้ว ใช่ ในกรณีของเรา จะไม่มีอะไรเกิดขึ้น เนื่องจากนี่เป็นโปรเจ็กต์ทดสอบ และเรารู้ว่ามีการปรับใช้ในที่เดียวเท่านั้น แต่นี่อาจเป็นแนวทางที่ผิด แต่เราต้องการให้ทุกอย่างถูกต้อง ถัดมาเป็นการลบตารางก่อนที่จะสร้างตารางขึ้นมา ทำไมเป็นเช่นนี้? เพื่อว่าหากบังเอิญมีตารางที่มีชื่อดังกล่าวในฐานข้อมูล การโยกย้ายจะไม่ล้มเหลวและจะทำงานได้ตรงตามที่คาดไว้ จากนั้นเราก็เพิ่มสองตาราง ทุกอย่างเป็นไปตามที่เราต้องการ ตอนนี้เราต้องเปิดแอปพลิเคชันของเรา หากทุกอย่างเริ่มต้นและไม่เสียหาย การย้ายจะถูกบันทึก และเพื่อตรวจสอบอีกครั้ง เราจะไปที่ฐานข้อมูลเพื่อให้แน่ใจว่า: ก) ตารางดังกล่าวปรากฏขึ้น; b) มีรายการใหม่ในตารางทางเทคนิคของทางบิน นี่เป็นการเสร็จสิ้นการย้ายข้อมูล มาดูที่เก็บข้อมูลกันดีกว่า
การเพิ่มชั้นพื้นที่เก็บข้อมูล
ขอบคุณ Spring Boot Data ทุกอย่างง่ายมากที่นี่: เราจำเป็นต้องเพิ่มเอนทิตี GroupSub อัปเดต TelegramUser เล็กน้อย และเพิ่ม GroupSubRepository ที่เกือบจะว่างเปล่า: เราเพิ่มเอนทิตี GroupSub ลงในแพ็คเกจเดียวกันกับ TelegramUser:package com.github.javarushcommunity.jrtb.repository.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
import static java.util.Objects.isNull;
@Data
@Entity
@Table(name = "group_sub")
@EqualsAndHashCode
public class GroupSub {
@Id
private Integer id;
@Column(name = "title")
private String title;
@Column(name = "last_article_id")
private Integer lastArticleId;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name = "group_x_user",
joinColumns = @JoinColumn(name = "group_sub_id"),
inverseJoinColumns = @JoinColumn(name = "user_id")
)
private List<TelegramUser> users;
public void addUser(TelegramUser telegramUser) {
if (isNull(users)) {
users = new ArrayList<>();
}
users.add(telegramUser);
}
}
สิ่งหนึ่งที่น่าสังเกตคือเรามีฟิลด์ผู้ใช้เพิ่มเติมที่จะมีคอลเลกชันของผู้ใช้ทั้งหมดที่สมัครเป็นสมาชิกกลุ่ม และคำอธิบายประกอบสองรายการ - ManyToMany และ JoinTable - เป็นสิ่งที่เราต้องการสำหรับสิ่งนี้ จำเป็นต้องเพิ่มฟิลด์เดียวกันสำหรับ TelegramUser:
@ManyToMany(mappedBy = "users", fetch = FetchType.EAGER)
private List<GroupSub> groupSubs;
ฟิลด์นี้ใช้การรวมที่เขียนในเอนทิตี GroupSub และในความเป็นจริงแล้ว คลาสพื้นที่เก็บข้อมูลของเราสำหรับ GroupSub คือGroupSubRepository :
package com.github.javarushcommunity.jrtb.repository;
import com.github.javarushcommunity.jrtb.repository.entity.GroupSub;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
/**
* {@link Repository} for {@link GroupSub} entity.
*/
@Repository
public interface GroupSubRepository extends JpaRepository<GroupSub, Integer> {
}
ในขั้นตอนนี้ เราไม่ต้องการวิธีการเพิ่มเติม: วิธีการเหล่านั้นที่นำมาใช้ใน JpaRepository ancestor ก็เพียงพอแล้วสำหรับเรา มาเขียนการทดสอบใน TelegramUserRepositoryIT ที่จะตรวจสอบว่าการทำงานแบบกลุ่มต่อกลุ่มของเราเป็นอย่างไร แนวคิดของการทดสอบคือเราจะเพิ่มการสมัครสมาชิก 5 กลุ่มต่อผู้ใช้หนึ่งรายในฐานข้อมูลผ่านสคริปต์ sql รับผู้ใช้รายนี้ด้วย ID ของเขาและตรวจสอบว่าเราได้รับกลุ่มเหล่านั้นทุกประการและมีค่าเหมือนกันทุกประการ ทำอย่างไร? คุณสามารถฝังตัวนับลงในข้อมูล ซึ่งเราจะตรวจสอบและตรวจสอบได้ นี่คือสคริปต์ fiveGroupSubsForUser.sql:
INSERT INTO tg_user VALUES (1, 1);
INSERT INTO group_sub VALUES
(1, 'g1', 1),
(2, 'g2', 2),
(3, 'g3', 3),
(4, 'g4', 4),
(5, 'g5', 5);
INSERT INTO group_x_user VALUES
(1, 1),
(2, 1),
(3, 1),
(4, 1),
(5, 1);
และการทดสอบนั้นเอง:
@Sql(scripts = {"/sql/clearDbs.sql", "/sql/fiveGroupSubsForUser.sql"})
@Test
public void shouldProperlyGetAllGroupSubsForUser() {
//when
Optional<TelegramUser> userFromDB = telegramUserRepository.findById("1");
//then
Assertions.assertTrue(userFromDB.isPresent());
List<GroupSub> groupSubs = userFromDB.get().getGroupSubs();
for (int i = 0; i < groupSubs.size(); i++) {
Assertions.assertEquals(String.format("g%s", (i + 1)), groupSubs.get(i).getTitle());
Assertions.assertEquals(i + 1, groupSubs.get(i).getId());
Assertions.assertEquals(i + 1, groupSubs.get(i).getLastArticleId());
}
}
ตอนนี้เรามาเพิ่มการทดสอบที่มีความหมายเดียวกันสำหรับเอนทิตี GroupSub เมื่อต้องการทำเช่นนี้ เรามาสร้างคลาสทดสอบgroupSubRepositoryITในแพ็คเกจเดียวกันกับgroupSubRepositoryIT :
package com.github.javarushcommunity.jrtb.repository;
import com.github.javarushcommunity.jrtb.repository.entity.GroupSub;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.jdbc.Sql;
import java.util.List;
import java.util.Optional;
import static org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace.NONE;
/**
* Integration-level testing for {@link GroupSubRepository}.
*/
@ActiveProfiles("test")
@DataJpaTest
@AutoConfigureTestDatabase(replace = NONE)
public class GroupSubRepositoryIT {
@Autowired
private GroupSubRepository groupSubRepository;
@Sql(scripts = {"/sql/clearDbs.sql", "/sql/fiveUsersForGroupSub.sql"})
@Test
public void shouldProperlyGetAllUsersForGroupSub() {
//when
Optional<GroupSub> groupSubFromDB = groupSubRepository.findById(1);
//then
Assertions.assertTrue(groupSubFromDB.isPresent());
Assertions.assertEquals(1, groupSubFromDB.get().getId());
List<TelegramUser> users = groupSubFromDB.get().getUsers();
for(int i=0; i<users.size(); i++) {
Assertions.assertEquals(String.valueOf(i + 1), users.get(i).getChatId());
Assertions.assertTrue(users.get(i).isActive());
}
}
}
และสคริปต์ fiveUsersForGroupSub.sql ที่หายไป:
INSERT INTO tg_user VALUES
(1, 1),
(2, 1),
(3, 1),
(4, 1),
(5, 1);
INSERT INTO group_sub VALUES (1, 'g1', 1);
INSERT INTO group_x_user VALUES
(1, 1),
(1, 2),
(1, 3),
(1, 4),
(1, 5);
ณ จุดนี้ ส่วนหนึ่งของงานที่มีที่เก็บก็ถือว่าเสร็จสมบูรณ์แล้ว ตอนนี้เรามาเขียนชั้นบริการกันดีกว่า
เราเขียน GroupSubService
ในขั้นตอนนี้ เพื่อทำงานกับกลุ่มการสมัครสมาชิก เราเพียงต้องสามารถบันทึกได้ ดังนั้นจึงไม่มีปัญหา: เราสร้างบริการ GroupSubService และการใช้งาน GroupSubServiceImpl ในแพ็คเกจที่ประกอบด้วยบริการอื่น ๆ - บริการ:package com.github.javarushcommunity.jrtb.service;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupDiscussionInfo;
import com.github.javarushcommunity.jrtb.repository.entity.GroupSub;
/**
* Service for manipulating with {@link GroupSub}.
*/
public interface GroupSubService {
GroupSub save(String chatId, GroupDiscussionInfo groupDiscussionInfo);
}
และการนำไปปฏิบัติ:
package com.github.javarushcommunity.jrtb.service;
import com.github.javarushcommunity.jrtb.javarushclient.dto.GroupDiscussionInfo;
import com.github.javarushcommunity.jrtb.repository.GroupSubRepository;
import com.github.javarushcommunity.jrtb.repository.entity.GroupSub;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.ws.rs.NotFoundException;
import java.util.Optional;
@Service
public class GroupSubServiceImpl implements GroupSubService {
private final GroupSubRepository groupSubRepository;
private final TelegramUserService telegramUserService;
@Autowired
public GroupSubServiceImpl(GroupSubRepository groupSubRepository, TelegramUserService telegramUserService) {
this.groupSubRepository = groupSubRepository;
this.telegramUserService = telegramUserService;
}
@Override
public GroupSub save(String chatId, GroupDiscussionInfo groupDiscussionInfo) {
TelegramUser telegramUser = telegramUserService.findByChatId(chatId).orElseThrow(NotFoundException::new);
//TODO add exception handling
GroupSub groupSub;
Optional<GroupSub> groupSubFromDB = groupSubRepository.findById(groupDiscussionInfo.getId());
if(groupSubFromDB.isPresent()) {
groupSub = groupSubFromDB.get();
Optional<TelegramUser> first = groupSub.getUsers().stream()
.filter(it -> it.getChatId().equalsIgnoreCase(chatId))
.findFirst();
if(first.isEmpty()) {
groupSub.addUser(telegramUser);
}
} else {
groupSub = new GroupSub();
groupSub.addUser(telegramUser);
groupSub.setId(groupDiscussionInfo.getId());
groupSub.setTitle(groupDiscussionInfo.getTitle());
}
return groupSubRepository.save(groupSub);
}
}
เพื่อให้ Spring Data ทำงานได้อย่างถูกต้องและสร้างบันทึกแบบกลุ่มต่อกลุ่ม เราจำเป็นต้องรับผู้ใช้จากฐานข้อมูลของเราสำหรับกลุ่มการสมัครสมาชิกที่เรากำลังสร้างและเพิ่มลงในออบเจ็กต์ GroupSub ดังนั้นเมื่อเราถ่ายโอนการสมัครสมาชิกนี้เพื่อการบันทึก การเชื่อมต่อจะถูกสร้างขึ้นผ่านตาราง group_x_user ด้วย อาจมีสถานการณ์เมื่อมีการสร้างกลุ่มการสมัครสมาชิกดังกล่าวแล้ว และคุณเพียงแค่ต้องเพิ่มผู้ใช้รายอื่นเข้าไป ในการดำเนินการนี้ ขั้นแรกเราจะได้รับ ID กลุ่มจากฐานข้อมูล และหากมีบันทึก เราจะดำเนินการกับมัน หากไม่มี เราจะสร้างขึ้นใหม่ สิ่งสำคัญคือต้องทราบว่าในการทำงานร่วมกับ TelegramUser เราใช้ TelegramUserService เพื่อปฏิบัติตามหลักการ SOLID สุดท้าย ในขณะนี้ หากเราไม่พบบันทึกตาม ID ฉันเพียงแต่ส่งข้อยกเว้นออกไป ขณะนี้ยังไม่มีการดำเนินการใดๆ เราจะดำเนินการนี้ในขั้นตอนสุดท้ายก่อน MVP มาเขียนการทดสอบหน่วยสองรายการสำหรับคลาสGroupSubServiceTest เราต้องการอันไหน? ฉันต้องการให้แน่ใจว่าวิธีการบันทึกจะถูกเรียกใน GroupSubRepository และเอนทิตีที่มีผู้ใช้เพียงคนเดียวจะถูกส่งไปยัง GroupSub ซึ่งเป็นอันที่จะส่งคืน TelegramUserService ให้เราโดยใช้ ID ที่ให้มา และตัวเลือกที่สอง เมื่อกลุ่มที่มี ID เดียวกันอยู่ในฐานข้อมูลแล้ว และกลุ่มนี้มีผู้ใช้รายหนึ่งอยู่แล้ว และคุณต้องตรวจสอบว่าจะเพิ่มผู้ใช้รายอื่นในกลุ่มนี้ และออบเจ็กต์นี้จะถูกบันทึกไว้ นี่คือการดำเนินการ:
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 ด้วย ด้วยวิธีนี้ พวกเขามักจะสร้างวิธีการที่จะดำเนินการก่อนการทดสอบแต่ละครั้ง และเป็นไปได้ที่จะใส่ตรรกะทั่วไปลงในการทดสอบทั้งหมด ในกรณีของเรา เราจำเป็นต้องล็อค TelegramUserService ในลักษณะเดียวกันสำหรับการทดสอบทั้งหมดของคลาสนี้ ดังนั้นจึงสมเหตุสมผลที่จะถ่ายโอนตรรกะนี้ไปยังวิธีการทั่วไป มีการออกแบบ mokito สองแบบที่นี่:
-
Mockito.when(o1.m1(a1)).thenReturn(o2) - ในนั้นเราบอกว่าเมื่อมีการเรียกใช้ เมธอด m1 บนอ็อบเจ็กต์ o1ด้วยอาร์กิวเมนต์a1เมธอดจะส่งคืนอ็อบเจ็กต์o2 นี่เป็นฟังก์ชันที่สำคัญที่สุดของ mockito - เพื่อบังคับให้วัตถุจำลองส่งคืนสิ่งที่เราต้องการ
-
Mockito.verify (o1).m1(a1) - ซึ่งตรวจสอบว่าวิธีการm1 ถูกเรียกบนวัตถุ o1ด้วยอาร์กิวเมนต์a1 แน่นอนว่าเป็นไปได้ที่จะใช้อ็อบเจ็กต์ที่ส่งคืนของวิธีการบันทึก แต่ฉันตัดสินใจทำให้มันซับซ้อนขึ้นเล็กน้อยโดยแสดงวิธีอื่นที่เป็นไปได้ เมื่อไหร่จะมีประโยชน์? ในกรณีที่วิธีการของคลาสจำลองกลับเป็นโมฆะ จากนั้นหากไม่มี Mockito.verify จะไม่มีงาน)))
สร้างคำสั่ง /addGroupSub
ที่นี่เราจำเป็นต้องดำเนินการตรรกะต่อไปนี้: หากเราได้รับเพียงคำสั่งโดยไม่มีบริบทใด ๆ เราจะช่วยเหลือผู้ใช้และมอบรายชื่อกลุ่มทั้งหมดพร้อม ID ของพวกเขาเพื่อให้เขาสามารถส่งข้อมูลที่จำเป็นไปยังบอทได้ และหากผู้ใช้ส่งคำสั่งไปยังบอทด้วยคำอื่น ให้ค้นหากลุ่มที่มี ID นั้นหรือเขียนว่าไม่มีกลุ่มดังกล่าว มาเพิ่มค่าใหม่ใน ename ของเรา - 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));
}
}
คลาสนี้ใช้ เมธอด isNumericจากไลบรารี apache-commons ดังนั้นมาเพิ่มมันลงในหน่วยความจำของเรา:
<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 ใน command map ของเรา:
.put(ADD_GROUP_SUB.getCommandName(), new AddGroupSubCommand(sendBotMessageService, javaRushGroupClient, groupSubService))
และทุกอย่างสำหรับทีมนี้ ฉันต้องการทดสอบฟังก์ชันนี้ แต่จนถึงตอนนี้ฉันสามารถดูได้เฉพาะในฐานข้อมูลเท่านั้น ในส่วนที่สาม ฉันจะเพิ่มการเปลี่ยนแปลงจาก JRTB-6 เพื่อให้เราดูรายชื่อกลุ่มที่ผู้ใช้สมัครเป็นสมาชิกได้ ตอนนี้เป็นการดีที่จะตรวจสอบทั้งหมดนี้ ในการดำเนินการนี้ เราจะดำเนินการทั้งหมดใน Telegram และตรวจสอบในฐานข้อมูล เนื่องจากเราสอบข้อเขียนแล้ว ทุกอย่างก็น่าจะเรียบร้อยดี บทความนี้ค่อนข้างยาว ดังนั้นเราจะเขียนการทดสอบสำหรับ AddGroupSubCommand ในภายหลัง และเพิ่ม TODO ลงในโค้ดเพื่อไม่ให้ลืม
GO TO FULL VERSION