Дагы бир жолу салам. Бул STEP_6нын акыркы макаласы, анда биз JRTB-6 тапшырмасына функцияларды кошуу жөнүндө сүйлөшөбүз . Мурунку эки макалада ( 1-бөлүк , 2-бөлүк ) биз сизге керектүү нерселердин бардыгын даярдап койгонбуз. Бул бөлүк процесстин туу чокусу болуп саналат. Бул макалалар сериясын башынан баштап ушул кезге чейин окугандардын баарына - чоң урмат. Бул сонун жумуш табуу үчүн сизде жетиштүү мотивация бар экенин билдирет. Эми ишке киришели.
JRTB-6-ны ишке ашырабыз
Бул жолу биз тапшырманы телеграмма бот тарабынан аткарабыз, анткени маалымат базасын жаңылоо боюнча иштер бүттү, маалымат базасы an objectтери конфигурацияланган жана ишке даяр. Келиңиз, CommandNameге жаңы маани кошолу - LIST_GROUP_SUB:LIST_GROUP_SUB("/listGroupSub");
Келгиле, ListGroupSubCommand буйругун түзөлү :
package com.github.javarushcommunity.jrtb.command;
import com.github.javarushcommunity.jrtb.repository.entity.GroupSub;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import org.telegram.telegrambots.meta.api.objects.Update;
import javax.ws.rs.NotFoundException;
import java.util.stream.Collectors;
import static com.github.javarushcommunity.jrtb.command.CommandUtils.getChatId;
/**
* {@link Command} for getting list of {@link GroupSub}.
*/
public class ListGroupSubCommand implements Command {
private final SendBotMessageService sendBotMessageService;
private final TelegramUserService telegramUserService;
public ListGroupSubCommand(SendBotMessageService sendBotMessageService, TelegramUserService telegramUserService) {
this.sendBotMessageService = sendBotMessageService;
this.telegramUserService = telegramUserService;
}
@Override
public void execute(Update update) {
//todo add exception handling
TelegramUser telegramUser = telegramUserService.findByChatId(getChatId(update))
.orElseThrow(NotFoundException::new);
String message = "Я нашел все подписки на группы: \n\n";
String collectedGroups = telegramUser.getGroupSubs().stream()
.map(it -> "Группа: " + it.getTitle() + " , ID = " + it.getId() + " \n")
.collect(Collectors.joining());
sendBotMessageService.sendMessage(telegramUser.getChatId(), message + collectedGroups);
}
}
Бул жерде бардыгы мүмкүн болушунча жөнөкөй - биз колдонуучуну учурдагы chat_id аркылуу алабыз жана анын бардык топторго жазылуулары анын an objectисинде чогултулат. Биз муну экинчи бөлүктө койдук. Дагы, мен операция учурунда пайда болушу мүмкүн болгон өзгөчөлүктөр менен иштөөнү кошууну унутпаш үчүн //todo коштум. Кийинки кадам CommandContainerди жаңыртуу, ага жаңы буйрукту кошуу:
put(LIST_GROUP_SUB.getCommandName(), new GroupSubListCommand(sendBotMessageService, telegramUserService))
Бул негизинен: азыр сиз көбүрөөк тесттерди жазып, / жардам буйругун жаңыртышыңыз керек (жаңы буйруктарга сүрөттөмө кошуу) жана Telegram аркылуу жаңы функцияларды сынап көрүңүз. ListGroupSubCommand үчүн тест жазалы . Буйруктун логикасы типтүү болбогондуктан, биз мурункудай AbstractCommandTest классына байланбастан тест жазабыз :
package com.github.javarushcommunity.jrtb.command;
import com.github.javarushcommunity.jrtb.repository.entity.GroupSub;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.Update;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import static com.github.javarushcommunity.jrtb.command.CommandName.LIST_GROUP_SUB;
@DisplayName("Unit-level testing for ListGroupSubCommand")
public class ListGroupSubCommandTest {
@Test
public void shouldProperlyShowsListGroupSub() {
//given
TelegramUser telegramUser = new TelegramUser();
telegramUser.setActive(true);
telegramUser.setChatId("1");
List<GroupSub> groupSubList = new ArrayList<>();
groupSubList.add(populateGroupSub(1, "gs1"));
groupSubList.add(populateGroupSub(2, "gs2"));
groupSubList.add(populateGroupSub(3, "gs3"));
groupSubList.add(populateGroupSub(4, "gs4"));
telegramUser.setGroupSubs(groupSubList);
SendBotMessageService sendBotMessageService = Mockito.mock(SendBotMessageService.class);
TelegramUserService telegramUserService = Mockito.mock(TelegramUserService.class);
Mockito.when(telegramUserService.findByChatId(telegramUser.getChatId())).thenReturn(Optional.of(telegramUser));
ListGroupSubCommand command = new ListGroupSubCommand(sendBotMessageService, telegramUserService);
Update update = new Update();
Message message = Mockito.mock(Message.class);
Mockito.when(message.getChatId()).thenReturn(Long.valueOf(telegramUser.getChatId()));
Mockito.when(message.getText()).thenReturn(LIST_GROUP_SUB.getCommandName());
update.setMessage(message);
String collectedGroups = "Я нашел все подписки на группы: \n\n" +
telegramUser.getGroupSubs().stream()
.map(it -> "Группа: " + it.getTitle() + " , ID = " + it.getId() + " \n")
.collect(Collectors.joining());
//when
command.execute(update);
//then
Mockito.verify(sendBotMessageService).sendMessage(telegramUser.getChatId(), collectedGroups);
}
private GroupSub populateGroupSub(Integer id, String title) {
GroupSub gs = new GroupSub();
gs.setId(id);
gs.setTitle(title);
return gs;
}
}
Келгиле, / help буйругун жаңырталы
Биздин учурда, /help буйругу бот менен иштөө үчүн document катары иштейт, андыктан колдонуучу аны колдоно алышы үчүн, аны жаңыртууну унутпашыбыз керек. Биз эки буйрук коштук, андыктан келе турган текстти жаңырталы:public static final String HELP_MESSAGE = String.format("✨Дотупные команды✨\n\n"
+ "Начать\\закончить работу с ботом:\n"
+ "%s - начать работу со мной\n"
+ "%s - приостановить работу со мной\n\n"
+ "Работа с подписками на группы:\n"
+ "%s - подписаться на группу статей\n"
+ "%s - получить список групп, на которые подписан\n\n"
+ "%s - получить помощь в работе со мной\n"
+ "%s - получить мою статистику использования\n",
START.getCommandName(), STOP.getCommandName(), ADD_GROUP_SUB.getCommandName(),
LIST_GROUP_SUB.getCommandName(), HELP.getCommandName(), STAT.getCommandName());
Мен ошондой эле боттун жоопторунун текстин жаңырттым: мен аны колдонуучу менен дайыма аты-жөнү боюнча боло тургандай кылып жасадым, антпесе “сен” да, “сен” да болмок... Эми жок дегенде түзүүгө болот. боттун ишинде кандайдыр бир байланыш.
Жаңыртылган бот сыналууда
Биз өзүбүздүн ботту жергorктүү түрдө ишке киргизип, төмөнкүлөрдү жасайбыз:- Сыноодогу колдонуучу маалымат базасына кошулганына ынануу үчүн /start буйругун аткарабыз .
- Биз / help командасын аткарабыз - биз каалагандай баары жакшы экенин текшеребиз.
- Андан кийин биз / addGroupSub буйругун аткарабыз .
- Топтун идентификаторлорунун сунушталган тизмесинен биз аралашмага бир нече кошобуз.
- Топтор колдонуучуга катталганын текшерүү үчүн /listGroupSub буйругун иштетебиз .
application.properties:
spring.datasource.url=jdbc:mysql://jrtb-db:3306/jrtb_db?characterEncoding=UTF-8
application-test.properties:
spring.datasource.url=jdbc:mysql://localhost:3306/dev_jrtb_db?characterEncoding=UTF-8
docker-compose.yml (добавил последнюю строку):
jrtb-db:
image: mysql:5.7
restart: always
environment:
MYSQL_USER: ${BOT_DB_USERNAME}
MYSQL_PASSWORD: ${BOT_DB_PASSWORD}
MYSQL_DATABASE: 'jrtb_db'
MYSQL_ROOT_PASSWORD: 'root'
ports:
- '3306:3306'
expose:
- '3306'
command: --character-set-server=utf8 --collation-server=utf8_general_ci
docker-compose-test.yml (добавил последнюю строку)
jrtb-db-dev:
image: mysql:5.7
restart: always
environment:
MYSQL_DATABASE: 'dev_jrtb_db'
# So you don't have to use root, but you can if you like
MYSQL_USER: 'dev_jrtb_db_user'
# You can use whatever password you like
MYSQL_PASSWORD: 'dev_jrtb_db_password'
# Password for root access
MYSQL_ROOT_PASSWORD: 'root'
ports:
# <Port exposed> : < MySQL Port running inside container>
- '3306:3306'
expose:
# Opens port 3306 on the container
- '3306'
command: --character-set-server=utf8 --collation-server=utf8_general_ci
Бул жаңыртуулардан кийин, сиз маалымат базасындагы бардык маалыматтарды өчүрүп, кайра башташыңыз керек. Өчүрүү абдан жөнөкөй: сиз төмөнкү буйрукту аткарышыңыз керек: docker-compose -f docker-compose-test.yml, андан кийин бардык маалыматтар жана маалымат базасы жок кылынат. Жана аны жаңыртылган codeдоо менен кайра иштетиңиз: docker-compose -f docker-compose-test.uml up Маалымат базасы даяр. Жаңыртылган тиркемени ишке киргизип, карап көрөлү. Мен аны тез эле карап чыгып, натыйжаны көрсөтөм: Эми биз каалаган нерсеге ээ болдук. Эми бул чындык окшойт.
Аяктоо
Эми бул кадамды аягына чыгара алабыз деп ойлойм. Көп нерсе жасалды, чынында эле көп. Колдонмонун versionсын 0.5.0-SNAPSHOT жана RELEASE_NOTESге жаңырталы .
# Release Notes ## 0.5.0-SNAPSHOT * JRTB-5: топко жазылуу мүмкүнчүлүгү кошулду * JRTB-6: топко жазылуулардын тизмесин алуу үчүн кошумча мүмкүнчүлүк.
Ошондо баары кадимкидей болот: биз бардык өзгөртүүлөр менен жаңы милдеттенме түзөбүз. Негизгиси - отчеттук максаттар үчүн бул кадамдын жүрүшүндө аткарылган эки иштин сыпаттамасын кошуу. Ошентип, бул жерде комментарий:
STEP_6 JRTB-5: JRTB-6 тобуна жазылуу мүмкүнчүлүгү кошулду: топко жазылуунун тизмесин көрүү мүмкүнчүлүгү кошулду.
Натыйжада 47 файл өзгөрдү... Бул чоң өзгөрүү. Функционалдык сыпаттамадан айта албайсыз да. Анын үстүнө, толук тереңдикти түшүнүү үчүн, сиз API үчүн Java кардарын жазуу керек экенин бorшиңиз керек, негизинен бүт тиркемени жаңыртуу. Мына ушундай, serverде иштөө - жумуш көп, бирок кардар тараптан көрүнүү аз...)) Достор, мен сиздерге өзүмдүн жумушума кызыгуу көрсөтүүнүн жолун сунуштайм - githubга жазылыңыз аккаунту , Telegram каналына кошулуңуз жана бир нерсе түшүнүксүз болсо, макала боюнча суроо жазыңыз! Бул STEP_6 үчүн өзгөртүүлөр менен тартуу өтүнүчүнө шилтеме . Окуу үчүн баарына рахмат. Дагы алдыда - жазылууну жок кылуу, профилди өчүрүү жана башкалар жөнүндө сүйлөшөлү. Которушпа))
GO TO FULL VERSION