JavaRush /Блоги Java /Random-TG /Мо ҳама чизҳои марбут ба базаи маълумотро илова мекунем. ...
Roman Beekeeper
Сатҳи

Мо ҳама чизҳои марбут ба базаи маълумотро илова мекунем. (Қисми 2) - "Лоиҳаи Java аз А то Я"

Дар гурӯҳ нашр шудааст
Салом ба ҳама. Ба шумо хотиррасон мекунам: дар қисми аввал мо Flyway-ро илова кардем. Биёед идома диҳем.

Илова кардани пойгоҳи додаҳо ба docker-compose.yml

Марҳилаи навбатӣ насб кардани кор бо пойгоҳи додаҳо дар docker-compose.yml мебошад. Биёед базаро ба файли docker-compose илова кунем:
version: '3.1'

services:
 jrtb-bot:
   depends_on:
     - jrtb-db
   build:
     context: .
   environment:
     BOT_NAME: ${BOT_NAME}
     BOT_TOKEN: ${BOT_TOKEN}
     BOT_DB_USERNAME: ${BOT_DB_USERNAME}
     BOT_DB_PASSWORD: ${BOT_DB_PASSWORD}
   restart: always
 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'
Ман инчунин ин сатрро ба аризаи худ илова кардам:
depends_on:
 - jrtb-db
Ин маънои онро дорад, ки мо пеш аз оғози барнома интизорем, ки пойгоҳи додаҳо оғоз шавад. Баъдан, шумо метавонед илова кардани ду тағирёбандаи дигарро мушоҳида кунед, ки мо бояд бо пойгоҳи додаҳо кор кунем:
${BOT_DB_USERNAME}
${BOT_DB_PASSWORD}
Мо онҳоро дар docker-compose ба мисли боти телеграмма - тавассути тағирёбандаҳои муҳити зист мегирем. Ман ин корро кардам, то ки мо танҳо як ҷое дошта бошем, ки мо арзишҳои номи корбари пойгоҳи додаҳо ва пароли онро муқаррар кунем. Мо онҳоро ба тасвири докери замимаи худ ва ба контейнери докери пойгоҳи додаамон мерасонем. Минбаъд мо бояд файли Docker-ро навсозӣ кунем, то ба SpringBoot-и худ қабули тағирёбандаҳоро барои пойгоҳи додаҳо омӯзем.
FROM adoptopenjdk/openjdk11:ubi
ARG JAR_FILE=target/*.jar
ENV BOT_NAME=test.javarush_community_bot
ENV BOT_TOKEN=1375780501:AAE4A6Rz0BSnIGzeu896OjQnjzsMEG6_uso
ENV BOT_DB_USERNAME=jrtb_db_user
ENV BOT_DB_PASSWORD=jrtb_db_password
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Dspring.datasource.password=${BOT_DB_PASSWORD}", "-Dbot.username=${BOT_NAME}", "-Dbot.token=${BOT_TOKEN}", "-Dspring.datasource.username=${BOT_DB_USERNAME}", "-jar", "app.jar"]
Ҳоло мо тағирёбандаҳои пойгоҳи додаҳоро ба Dockerfile илова мекунем:
ENV BOT_DB_USERNAME=jrtb_db_user
ENV BOT_DB_PASSWORD=jrtb_db_password
Арзишҳои тағирёбанда гуногун хоҳанд буд. Онҳое, ки мо ба Dockerfile мегузарем, арзишҳои пешфарзро талаб мекунанд, бинобар ин ман баъзеро ворид кардам. Мо сатри охиринро бо ду унсур васеъ мекунем, ки бо ёрии онҳо номи корбар ва пароли DB-ро ба оғози барнома мегузорем:
"-Dspring.datasource.password=${BOT_DB_PASSWORD}", "-Dbot.username=${BOT_NAME}"
Сатри охирин дар файли Docker (ки бо ENTRYPOINT оғоз мешавад) бояд бидуни печондан бошад. Агар шумо интиқол диҳед, ин code кор намекунад. Қадами охирин ин навсозии файли start.sh барои интиқол додани тағирёбандаҳо ба пойгоҳи додаҳо мебошад.
#!/bin/bash

# Pull new changes
git pull

# Prepare Jar
mvn clean
mvn package

# Ensure, that docker-compose stopped
docker-compose stop

# Add environment variables
export BOT_NAME=$1
export BOT_TOKEN=$2
export BOT_DB_USERNAME='prod_jrtb_db_user'
export BOT_DB_PASSWORD='Pap9L9VVUkNYj99GCUCC3mJkb'

# Start new deployment
docker-compose up --build -d
Мо аллакай медонем, ки чӣ гуна пеш аз иҷро кардани docker-compose тағирёбандаҳои муҳити атрофро илова кунем. Барои ин ба шумо лозим аст, ки содироти var_name=var_value -ро иҷро кунед. Аз ин рӯ, мо танҳо ду сатр илова мекунем:
export BOT_DB_USERNAME='prod_jrtb_db_user'
export BOT_DB_PASSWORD='Pap9L9VVUkNYj99GCUCC3mJkb'
Дар ин ҷо мо номи корбар ва пароли пойгоҳи додаҳоро муқаррар мекунем. Албатта, ин тағирёбандаҳоро ҳангоми иҷро кардани скрипти bash метавон интиқол дод, чуноне ки мо барои ном ва аломати бот мекунем. Аммо ба назарам ин нодаркор аст. Барои воқеан дастрасӣ ба пойгоҳи додаҳо, шумо бояд IP-и serverеро, ки дар он пойгоҳи додаҳо ҷойгир карда мешавад, бидонед ва дар рӯйхати суроғаҳои IP-и иҷозатдодашудаи дархост бошед. Ба ман бошад, ин аллакай кифоя аст. Асос гузошта шудааст: акнун шумо метавонед корҳоеро иҷро кунед, ки барои таҳиягар фаҳмотаранд - code нависед. Пеш аз он, мо кореро мекардем, ки муҳандисони DevOps мекунанд - эҷод кардани муҳити зист.

Илова кардани қабати репозиторий

Одатан барнома се қабат дорад:
  1. Назоратчиён нуқтаҳои воридшавӣ ба барнома мебошанд.
  2. Хидматҳо дар он ҷое ҳастанд, ки мантиқи тиҷорат кор мекунад. Мо аллакай қисман инро дорем: SendMessageService намояндаи возеҳи мантиқи тиҷорат аст.
  3. Анборҳо ҷои кор бо пойгоҳи додаҳо мебошанд. Дар ҳолати мо, ин боти телеграмма аст.
Акнун мо як қабати сеюмро илова мекунем - анборҳо. Дар ин ҷо мо лоиҳаи экосистемаи баҳорро истифода хоҳем кард - Маълумоти баҳор. Шумо метавонед дар бораи он чӣ дар ин мақола дар бораи Habré хонед . Мо бояд якчанд нуктаҳоро донем ва дарк кунем:
  1. Мо набояд бо JDBC кор кунем: мо мустақиман бо абстраксияҳои баландтар кор хоҳем кард. Яъне, POJO-ҳоро, ки ба ҷадвалҳо дар пойгоҳи додаҳо мувофиқанд, нигоҳ доред. Мо чунин синфҳоро an object номида мешавем , зеро онҳо расман дар Java Persistence API номида мешаванд (ин маҷмӯи маъмули интерфейсҳо барои кор бо пойгоҳи додаҳо тавассути ORM мебошад, яъне абстраксияи кор бо JDBC). Мо синфи an objectе хоҳем дошт, ки мо онро дар базаи маълумот захира мекунем ва онҳо маҳз ба ҷадвале, ки ба мо лозим аст, навишта мешаванд. Ҳангоми ҷустуҷӯ дар пойгоҳи додаҳо мо ҳамон an objectҳоро мегирем.
  2. Spring Data барои истифодаи маҷмӯи интерфейсҳои онҳо пешниҳод мекунад: JpaRepository , CrudRepository , ва ғайра... Интерфейсҳои дигар вуҷуд доранд: рӯйхати пурраро дар ин ҷо пайдо кардан мумкин аст . Зебоӣ дар он аст, ки шумо метавонед усулҳои онҳоро бидуни татбиқи онҳо истифода баред(!). Ғайр аз он, як қолаби муайяне мавҷуд аст, ки тавассути он шумо метавонед дар интерфейс усулҳои нав нависед ва онҳо ба таври худкор амалӣ карда мешаванд.
  3. Бахор тараккиёти моро ба кадри имкон осон мекунад. Барои ин, мо бояд интерфейси худро эҷод кунем ва аз онҳое, ки дар боло тавсиф шудаанд, мерос гирем. Ва то баҳор донад, ки вай бояд ин интерфейсро истифода барад, шарҳи анборро илова кунед.
  4. Агар ба мо лозим ояд, ки усули кор бо пойгоҳи додаҳо вуҷуд надошта бошад, пас ин ҳам мушкил нест - мо онро менависем. Ман ба шумо нишон медиҳам, ки дар он ҷо чӣ кор кардан лозим аст.
Дар ин мақола, мо бо илова кардани тамоми роҳи TelegramUser кор хоҳем кард ва ин қисмро ҳамчун намуна нишон медиҳем. Мо боқимондаро аз рӯи дигар вазифаҳо васеъ мекунем. Яъне, вақте ки мо фармони /start -ро иҷро мекунем, мо ба пойгоҳи додаи корбари худ active = true менависем. Ин маънои онро дорад, ки корбар ботро истифода мебарад. Агар корбар аллакай дар базаи маълумот бошад, мо майдони фаъол = ҳақиқиро нав мекунем. Ҳангоми иҷрои фармони /stop, мо корбарро нест намекунем, балки танҳо майдони фаъолро ба "false" навсозӣ мекунем, то ки агар корбар мехоҳад ботро дубора истифода барад, вай метавонад онро оғоз кунад ва аз ҷое, ки бозистодааст, идома диҳад. Ва ба тавре ки ҳангоми санҷиш мо мебинем, ки чизе рӯй дода истодааст, мо фармони /stat эҷод мекунем: он шумораи корбарони фаъолро нишон медиҳад. Мо дар паҳлӯи бастаҳои бот, фармон, бастаҳои хидматрасонӣ бастаи репозиторий эҷод мекунем. Дар ин баста мо як an objectи дигарро эҷод мекунем . Дар бастаи an object мо синфи TelegramUser эҷод мекунем:
package com.github.javarushcommunity.jrtb.repository.entity;

import lombok.Data;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;

/**
* Telegram User entity.
*/
@Data
@Entity
@Table(name = "tg_user")
public class TelegramUser {

   @Id
   @Column(name = "chat_id")
   private String chatId;

   @Column(name = "active")
   private boolean active;
}
Дар ин ҷо шумо мебинед, ки мо ҳама эзоҳҳоро аз бастаи javax.persistence дорем. Инҳо шарҳҳои умумӣ мебошанд, ки барои ҳама татбиқи ORM истифода мешаванд. Бо нобаёнӣ, Spring Data Jpa Hibernate-ро истифода мебарад, гарчанде ки дигар татбиқҳо метавонанд истифода шаванд. Ин аст рӯйхати эзоҳҳое, ки мо истифода мебарем:
  • Объект - нишон медиҳад, ки ин an object барои кор бо пойгоҳи додаҳо мебошад;
  • Ҷадвал – дар ин ҷо номи ҷадвалро муайян мекунем;
  • Id - эзоҳ мегӯяд, ки кадом соҳа дар ҷадвал Калиди ибтидоӣ хоҳад буд;
  • Сутун - номи майдонро аз ҷадвал муайян кунед.
Минбаъд, мо барои кор бо базаи маълумот интерфейс эҷод мекунем. Одатан, номҳои чунин интерфейсҳо бо истифода аз қолаб - EntiryNameRepository навишта мешаванд. Мо як TelegramuserRepository дорем:
package com.github.javarushcommunity.jrtb.repository;

import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
* {@link Repository} for handling with {@link TelegramUser} entity.
*/
@Repository
public interface TelegramUserRepository extends JpaRepository<TelegramUser, String> {
   List<TelegramUser> findAllByActiveTrue();
}
Дар ин ҷо шумо мебинед, ки чӣ тавр ман усули findAllByActiveTrue() -ро илова кардам , ки ман онро дар ҳеҷ ҷо татбиқ намекунам. Аммо ин ба кори вай халал намерасонад. Маълумоти баҳорӣ мефаҳмад, ки он бояд ҳамаи сабтҳоро аз ҷадвали tg_user гирад, ки майдони фаъоли он = true . Мо хидматеро барои кор бо субъекти TelegramUser илова мекунем (мо инversionи вобастагӣ аз SOLID-ро дар шароите истифода мебарем, ки хидматҳои дигар an objectҳо наметавонанд мустақиман бо репозиторийии шахси дигар иртибот дошта бошанд - танҳо тавассути хидмати ин муассиса). Мо дар баста хидматрасонии TelegramUserService эҷод мекунем, ки ҳоло он якчанд усул дорад: корбарро захира кунед, корбарро бо ID-и худ гиред ва рӯйхати корбарони фаъолро намоиш диҳед. Аввал мо интерфейси TelegramUserService-ро эҷод мекунем:
package com.github.javarushcommunity.jrtb.service;

import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

/**
* {@link Service} for handling {@link TelegramUser} entity.
*/
public interface TelegramUserService {

   /**
    * Save provided {@link TelegramUser} entity.
    *
    * @param  telegramUser provided telegram user.
    */
   void save(TelegramUser telegramUser);

   /**
    * Retrieve all active {@link TelegramUser}.
    *
    * @return the collection of the active {@link TelegramUser} objects.
    */
   List<TelegramUser> retrieveAllActiveUsers();

   /**
    * Find {@link TelegramUser} by chatId.
    *
    * @param chatId provided Chat ID
    * @return {@link TelegramUser} with provided chat ID or null otherwise.
    */
   Optional<TelegramUser> findByChatId(String chatId);
}
Ва, дар асл, татбиқи TelegramUserServiceImpl:
package com.github.javarushcommunity.jrtb.service;

import com.github.javarushcommunity.jrtb.repository.TelegramUserRepository;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

/**
* Implementation of {@link TelegramUserService}.
*/
@Service
public class TelegramUserServiceImpl implements TelegramUserService {

   private final TelegramUserRepository telegramUserRepository;

   @Autowired
   public TelegramUserServiceImpl(TelegramUserRepository telegramUserRepository) {
       this.telegramUserRepository = telegramUserRepository;
   }

   @Override
   public void save(TelegramUser telegramUser) {
       telegramUserRepository.save(telegramUser);
   }

   @Override
   public List<TelegramUser> retrieveAllActiveUsers() {
       return telegramUserRepository.findAllByActiveTrue();
   }

   @Override
   public Optional<TelegramUser> findByChatId(String chatId) {
       return telegramUserRepository.findById(chatId);
   }
}
Дар ин ҷо бояд қайд кард, ки мо тазриқи вобастагӣ (ҷори як мисоли синф) -и an objectи TelegramuserRepository -ро бо истифода аз шарҳи Autowired ва конструктор истифода мебарем. Шумо метавонед ин корро барои тағирёбанда иҷро кунед, аммо ин равишест, ки гурӯҳи Spring Framework ба мо тавсия медиҳад.

Илова кардани омор барои бот

Минбаъд шумо бояд фармонҳои / start ва / stop -ро навсозӣ кунед. Вақте ки фармони /start истифода мешавад, шумо бояд корбари навро дар базаи маълумот захира кунед ва онро ба фаъол = true муқаррар кунед. Ва ҳангоме ки /stop мавҷуд аст, маълумоти корбарро навсозӣ кунед: фаъол = бардурӯғ муқаррар кунед. Биёед синфи StartCommand -ро ислоҳ кунем :
package com.github.javarushcommunity.jrtb.command;

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;

/**
* Start {@link Command}.
*/
public class StartCommand implements Command {

   private final SendBotMessageService sendBotMessageService;
   private final TelegramUserService telegramUserService;

   public final static String START_MESSAGE = "Привет. Я Javarush Telegram Bot. Я помогу тебе быть в курсе последних " +
           "статей тех авторов, котрые тебе интересны. Я еще маленький и только учусь.";

   public StartCommand(SendBotMessageService sendBotMessageService, TelegramUserService telegramUserService) {
       this.sendBotMessageService = sendBotMessageService;
       this.telegramUserService = telegramUserService;
   }

   @Override
   public void execute(Update update) {
       String chatId = update.getMessage().getChatId().toString();

       telegramUserService.findByChatId(chatId).ifPresentOrElse(
               user -> {
                   user.setActive(true);
                   telegramUserService.save(user);
               },
               () -> {
                   TelegramUser telegramUser = new TelegramUser();
                   telegramUser.setActive(true);
                   telegramUser.setChatId(chatId);
                   telegramUserService.save(telegramUser);
               });

       sendBotMessageService.sendMessage(chatId, START_MESSAGE);
   }
}
Дар ин ҷо мо инчунин an objectи TelegramuserService-ро ба конструктор мегузорем, ки бо он мо корбари навро захира мекунем. Ғайр аз он, бо истифода аз лаззатҳои Optional дар Java, мантиқи зерин кор мекунад: агар мо дар базаи маълумот корбар дошта бошем, мо ӯро танҳо фаъол мегардонем, агар не, мо як фаъоли нав эҷод мекунем. Фармони қатъ:
package com.github.javarushcommunity.jrtb.command;

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 java.util.Optional;

/**
* Stop {@link Command}.
*/
public class StopCommand implements Command {

   private final SendBotMessageService sendBotMessageService;
   private final TelegramUserService telegramUserService;

   public static final String STOP_MESSAGE = "Деактивировал все ваши подписки \uD83D\uDE1F.";

   public StopCommand(SendBotMessageService sendBotMessageService, TelegramUserService telegramUserService) {
       this.sendBotMessageService = sendBotMessageService;
       this.telegramUserService = telegramUserService;
   }

   @Override
   public void execute(Update update) {
       sendBotMessageService.sendMessage(update.getMessage().getChatId().toString(), STOP_MESSAGE);
       telegramUserService.findByChatId(update.getMessage().getChatId().toString())
               .ifPresent(it -> {
                   it.setActive(false);
                   telegramUserService.save(it);
               });
   }
}
Мо ҳамин тавр TelegramServiceTest-ро ба StopCommand мегузарем. Мантиқи иловагӣ ин аст: агар мо корбаре бо чунин ID чат дошта бошем, мо онро ғайрифаъол мекунем, яъне фаъол = бардурӯғ муқаррар мекунем. Чӣ тавр шумо инро бо чашмони худ мебинед? Биёед як фармони нави /stat эҷод кунем, ки омори ботро нишон медиҳад. Дар ин марҳила, инҳо омори оддӣ барои ҳамаи корбарон дастрас хоҳанд буд. Дар оянда, мо онро маҳдуд мекунем ва танҳо барои маъмурон дастрасӣ пайдо мекунем. Дар омор як сабт мавҷуд хоҳад буд: шумораи корбарони фаъоли бот. Барои ин, арзиши STAT("/stat") -ро ба CommandName илова кунед. Баъд, синфи StatCommand -ро эҷод кунед :
package com.github.javarushcommunity.jrtb.command;

import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.telegram.telegrambots.meta.api.objects.Update;

/**
* Statistics {@link Command}.
*/
public class StatCommand implements Command {

   private final TelegramUserService telegramUserService;
   private final SendBotMessageService sendBotMessageService;

   public final static String STAT_MESSAGE = "Javarush Telegram Bot использует %s человек.";

   @Autowired
   public StatCommand(SendBotMessageService sendBotMessageService, TelegramUserService telegramUserService) {
       this.sendBotMessageService = sendBotMessageService;
       this.telegramUserService = telegramUserService;
   }

   @Override
   public void execute(Update update) {
       int activeUserCount = telegramUserService.retrieveAllActiveUsers().size();
       sendBotMessageService.sendMessage(update.getMessage().getChatId().toString(), String.format(STAT_MESSAGE, activeUserCount));
   }
}
Дар ин ҷо ҳама чиз оддӣ аст: мо рӯйхати ҳамаи корбарони фаъолро бо истифода аз усули retrieveAllActiveUsers мегирем ва андозаи коллексияро мегирем. Мо инчунин бояд ҳоло синфҳои болоравиро навсозӣ кунем: CommandContainer ва JavarushTelegramBot , то онҳо интиқоли хидмати наверо, ки ба мо лозим аст, ёд гиранд. Контейнери фармон:
package com.github.javarushcommunity.jrtb.command;

import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import com.google.common.collect.ImmutableMap;

import static com.github.javarushcommunity.jrtb.command.CommandName.*;

/**
* Container of the {@link Command}s, which are using for handling telegram commands.
*/
public class CommandContainer {

   private final ImmutableMap<String, Command> commandMap;
   private final Command unknownCommand;

   public CommandContainer(SendBotMessageService sendBotMessageService, TelegramUserService telegramUserService) {

       commandMap = ImmutableMap.<String, Command>builder()
               .put(START.getCommandName(), new StartCommand(sendBotMessageService, telegramUserService))
               .put(STOP.getCommandName(), new StopCommand(sendBotMessageService, telegramUserService))
               .put(HELP.getCommandName(), new HelpCommand(sendBotMessageService))
               .put(NO.getCommandName(), new NoCommand(sendBotMessageService))
               .put(STAT.getCommandName(), new StatCommand(sendBotMessageService, telegramUserService))
               .build();

       unknownCommand = new UnknownCommand(sendBotMessageService);
   }

   public Command retrieveCommand(String commandIdentifier) {
       return commandMap.getOrDefault(commandIdentifier, unknownCommand);
   }

}
Дар ин ҷо мо ба харита фармони нав илова кардем ва онро тавассути созандаи TelegramUserService гузаронидем. Аммо дар худи бот танҳо конструктор тағир меёбад:
@Autowired
public JavarushTelegramBot(TelegramUserService telegramUserService) {
   this.commandContainer = new CommandContainer(new SendBotMessageServiceImpl(this), telegramUserService);
}
Ҳоло мо TelegramUserService-ро ҳамчун аргумент мегузорем ва илова кардани тавзеҳи Autowired. Ин маънои онро дорад, ки мо онро аз Контексти Ариза мегирем. Мо инчунин синфи HelpCommand- ро нав мекунем , то дар тавсиф фармони нави омор пайдо шавад.

Санҷиши дастӣ

Биёед пойгоҳи додаҳоро аз docker-compose-test.yml ва усули асосӣ дар синфи JavarushTelegramBotApplication оғоз кунем. Баъдан мо маҷмӯи фармонҳоро менависем:
  • / stat - мо интизорем, ки агар базаи маълумот холӣ бошад, ин ботро истифода мебарад, ки сифр нафар хоҳад буд;
  • /start - оғоз кардани бот;
  • /stat - ҳоло мо интизорем, ки бот аз ҷониби 1 нафар истифода мешавад;
  • /сто - қатъ кардани бот;
  • /stat - мо интизорем, ки боз 0 нафар аз он истифода хоҳанд кард.
"Лоиҳаи Java аз A то Я": Илова кардани ҳама чизҳои марбут ба пойгоҳи додаҳо.  Қисми 2 - 2Агар натиҷа барои шумо якхела бошад, мо гуфта метавонем, ки функсия дуруст кор кардааст ва бот дуруст кор мекунад. Агар чизе хато кунад, муҳим нест: мо усули асосиро дар реҷаи дебаг бозоғоз мекунем ва ба таври возеҳ тамоми роҳро мегузарем, то хато дар чист.

Мо санҷишҳоро менависем ва навсозӣ мекунем

Азбаски мо конструкторҳоро иваз кардем, мо бояд синфҳои санҷиширо низ навсозӣ кунем. Дар синфи AbstractCommandTest , мо бояд як майдони дигарро илова кунем - синфи TelegramUserService , ки барои се фармон лозим аст:
protected TelegramUserService telegramUserService = Mockito.mock(TelegramUserService.class);
Баъд, биёед усули init() -ро дар CommandContainer навсозӣ кунем :
@BeforeEach
public void init() {
   SendBotMessageService sendBotMessageService = Mockito.mock(SendBotMessageService.class);
   TelegramUserService telegramUserService = Mockito.mock(TelegramUserService.class);
   commandContainer = new CommandContainer(sendBotMessageService, telegramUserService);
}
Дар StartCommand шумо бояд усули getCommand() -ро навсозӣ кунед :
@Override
Command getCommand() {
   return new StartCommand(sendBotMessageService, telegramUserService);
}
Инчунин дар StopCommand:
@Override
Command getCommand() {
   return new StopCommand(sendBotMessageService, telegramUserService);
}
Минбаъд биёед ба озмоишҳои нав назар кунем. Биёед озмоиши маъмулиро барои StatCommand эҷод кунем :
package com.github.javarushcommunity.jrtb.command;

import static com.github.javarushcommunity.jrtb.command.CommandName.STAT;
import static com.github.javarushcommunity.jrtb.command.StatCommand.STAT_MESSAGE;

public class StatCommandTest extends AbstractCommandTest {
   @Override
   String getCommandName() {
       return STAT.getCommandName();
   }

   @Override
   String getCommandMessage() {
       return String.format(STAT_MESSAGE, 0);
   }

   @Override
   Command getCommand() {
       return new StatCommand(sendBotMessageService, telegramUserService);
   }
}
Ин оддӣ аст. Акнун биёед дар бораи он сӯҳбат кунем, ки мо кор бо базаи маълумотро чӣ гуна озмоиш хоҳем кард. Мо ҳама чизеро, ки қаблан анҷом додем, санҷишҳои воҳидҳо буданд. Санҷиши ҳамгироӣ ҳамгироӣ байни қисмҳои зиёди барномаро месанҷад. Масалан, барномаҳо ва пойгоҳи додаҳо. Дар ин ҷо ҳама чиз мураккабтар хоҳад буд, зеро барои санҷиш ба мо базаи ҷойгиршуда лозим аст. Аз ин рӯ, вақте ки мо санҷишҳои худро ба таври маҳаллӣ иҷро мекунем, мо бояд пойгоҳи додаҳоро аз docker-compose-test.yml иҷро кунем. Барои иҷро кардани ин санҷиш, шумо бояд тамоми барномаи SpringBoot-ро иҷро кунед. Синфи санҷиш дорои шарҳи SpringBootTest мебошад , ки барномаро оғоз мекунад. Аммо ин равиш барои мо кор намекунад, зеро вақте ки барнома оғоз мешавад, боти телеграмма низ оғоз мешавад. Аммо дар ин ҷо ихтилоф вуҷуд дорад. Санҷишҳо ҳам ба таври маҳаллӣ дар мошини мо ва ҳам ба таври оммавӣ тавассути Actions GitHub гузаронида мешаванд. Барои он ки санҷишҳо бо оғози тамоми барнома гузаранд, мо бояд онҳоро бо маълумоти дуруст дар боти телеграмма иҷро кунем: яъне аз рӯи ном ва аломати он... Аз ин рӯ, мо ду интихоб дорем:
  1. Пас, ном ва нишони ботро оммавӣ кунед ва умедворед, ки ҳамааш хуб мешавад, касе аз он истифода намекунад ва ба мо халал намерасонад.
  2. Бо роҳи дигар биёед.
Ман варианти дуюмро интихоб кардам. Санҷиши SpringBoot дорои тавзеҳи DataJpaTest мебошад , ки он тавре сохта шудааст, ки ҳангоми санҷиши пойгоҳи додаҳо мо танҳо синфҳои лозимиро истифода мебарем ва дигаронро танҳо мегузорем. Аммо ин ба мо мувофиқ аст, зеро боти телеграмма тамоман кор намекунад. Ин маънои онро дорад, ки ба он ном ва аломати дуруст додан лозим нест!))) Мо озмоиш хоҳем кард, ки дар он мо месанҷем, ки усулҳое, ки Spring Data барои мо татбиқ мекунанд, тавре ки мо интизор будем, кор мекунанд. Дар ин ҷо қайд кардан муҳим аст, ки мо шарҳи @ActiveProfiles("test") -ро барои муайян кардани истифодаи профor санҷишӣ истифода мебарем. Ва ин маҳз он чизест, ки ба мо лозим аст, то мо метавонем хосиятҳои дурусти пойгоҳи додаи худро ҳисоб кунем. Хуб мебуд, ки пеш аз гузаронидани санҷишҳои мо базаи маълумот омода карда шавад. Барои ин масъала чунин равиш вуҷуд дорад: ба санҷиш шарҳи Sql илова кунед ва ба он маҷмӯи номҳои скриптро гузаронед, ки бояд пеш аз оғози санҷиш иҷро карда шаванд:
@Sql(scripts = {"/sql/clearDbs.sql", "/sql/telegram_users.sql"})
Барои мо, онҳо дар роҳи ./src/test/resources/ + роҳе, ки дар эзоҳ нишон дода шудааст, ҷойгир хоҳанд шуд. Ин аст, ки онҳо чӣ гунаанд:
clearDbs.sql:
DELETE FROM tg_user;

telegram_users.sql:
INSERT INTO tg_user VALUES ("123456789", 1);
INSERT INTO tg_user VALUES ("123456788", 1);
INSERT INTO tg_user VALUES ("123456787", 1);
INSERT INTO tg_user VALUES ("123456786", 1);
INSERT INTO tg_user VALUES ("123456785", 1);
INSERT INTO tg_user VALUES ("123456784", 0);
INSERT INTO tg_user VALUES ("123456782", 0);
INSERT INTO tg_user VALUES ("123456781", 0);
Дар натиҷа санҷиши TelegramUserRepositoryIT мо чунин хоҳад буд (чунон ки шумо мебинед, номи санҷиши ҳамгироӣ гуногун хоҳад буд - мо IT-ро илова мекунем, на Тест):
package com.github.javarushcommunity.jrtb.repository;

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 TelegramUserRepository}.
*/
@ActiveProfiles("test")
@DataJpaTest
@AutoConfigureTestDatabase(replace = NONE)
public class TelegramUserRepositoryIT {

   @Autowired
   private TelegramUserRepository telegramUserRepository;

   @Sql(scripts = {"/sql/clearDbs.sql", "/sql/telegram_users.sql"})
   @Test
   public void shouldProperlyFindAllActiveUsers() {
       //when
       List<TelegramUser> users = telegramUserRepository.findAllByActiveTrue();

       //then
       Assertions.assertEquals(5, users.size());
   }

   @Sql(scripts = {"/sql/clearDbs.sql"})
   @Test
   public void shouldProperlySaveTelegramUser() {
       //given
       TelegramUser telegramUser = new TelegramUser();
       telegramUser.setChatId("1234567890");
       telegramUser.setActive(false);
       telegramUserRepository.save(telegramUser);

       //when
       Optional<TelegramUser> saved = telegramUserRepository.findById(telegramUser.getChatId());

       //then
       Assertions.assertTrue(saved.isPresent());
       Assertions.assertEquals(telegramUser, saved.get());
   }
}
Мо санҷишҳоро навиштем, аммо савол ба миён меояд: бо оғози раванди CI мо дар GitHub чӣ мешавад? Он пойгоҳи додаҳо нахоҳад дошт. Ҳоло дар ҳақиқат танҳо як сохтори сурх хоҳад буд. Барои ин, мо амалҳои GitHub дорем, ки дар он мо метавонем оғози сохтани худро танзим кунем. Пеш аз гузаронидани санҷишҳо, шумо бояд як пойгоҳи додаҳоро бо танзимоти зарурӣ илова кунед. Тавре маълум мешавад, дар Интернет мисолҳои зиёд вуҷуд надоранд, бинобар ин ман ба шумо маслиҳат медиҳам, ки онро дар ҷое захира кунед. Биёед файли .github/workflows/maven.yml-ро навсозӣ кунем:
# This workflow will build a Java project with Maven
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven

name: Java CI with Maven

on:
 push:
   branches: [ main ]
 pull_request:
   branches: [ main ]

jobs:
 build:
   runs-on: ubuntu-latest
   steps:
   - uses: actions/checkout@v2
   - name: Set up MySQL
     uses: mirromutth/mysql-action@v1.1
     with:
       mysql version: '5.7'
       mysql database: 'dev_jrtb_db'
       mysql root password: 'root'
       mysql user: 'dev_jrtb_db_user'
       mysql password: 'dev_jrtb_db_password'
   - name: Set up JDK 1.11
     uses: actions/setup-java@v1
     with:
       java-version: 1.11
   - name: Build with Maven
     run: mvn -B package --file pom.xml
Ҳоло як блоки нави Set up MySQL мавҷуд аст . Дар он мо MySQL-ро ба раванди CI-и худ илова мекунем ва ҳамзамон тағирёбандаҳои ба мо лозимиро муайян мекунем. Акнун мо ҳама чизеро, ки мехостем, илова кардем. Марҳилаи охирин ин аст, ки тағиротро тела диҳед ва бубинед, ки сохтмон мегузарад ва сабз мешавад.

Навсозии ҳуҷҷатҳо

Биёед versionи лоиҳаро аз 0.3.0-SNAPSHOT то 0.4.0-SNAPSHOT дар pom.xml навсозӣ кунем ва инчунин ба RELEASE_NOTES илова кунем:
## 0.4.0-SNAPSHOT

*   JRTB-1: added repository layer.
Пас аз ҳамаи ин, мо дархост, тела ва кашидан дархост эҷод мекунем. Ва муҳимтар аз ҳама, сохтмони мо сабз аст!"Лоиҳаи Java аз A то Я": Илова кардани ҳама чизҳои марбут ба пойгоҳи додаҳо.  Қисми 2 - 3

Истинодҳои муфид:

Ҳама тағиротҳоро дар ин ҷо дар дархости кашидани офаридашуда дидан мумкин аст . Ташаккур ба ҳама барои хондан.

Рӯйхати ҳамаи маводҳои силсила дар аввали ин мақола аст.

Шарҳҳо
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION