JavaRush /Java Blog /Random-TW /我們新增與資料庫相關的所有內容。(第 2 部分)-“Java 專案從頭到尾”
Roman Beekeeper
等級 35

我們新增與資料庫相關的所有內容。(第 2 部分)-“Java 專案從頭到尾”

在 Random-TW 群組發布
大家好。讓我提醒您:在第一部分中我們新增了 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 映像和資料庫的 docker 容器。接下來,我們需要更新 Dockerfile 以教導 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 中的值需要預設值,所以我輸入了一些。我們用兩個元素擴展最後一行,借助這兩個元素,我們將資料庫使用者名稱和密碼傳遞給應用程式啟動:
"-Dspring.datasource.password=${BOT_DB_PASSWORD}", "-Dbot.username=${BOT_NAME}"
Dockerfile 中的最後一行(以 ENTRYPOINT 開頭)必須不換行。如果您進行轉賬,此代碼將無法運作。 最後一步是更新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 之前新增環境變數。為此,你只需要執行export var_name=var_value.。因此,我們只增加兩行:
export BOT_DB_USERNAME='prod_jrtb_db_user'
export BOT_DB_PASSWORD='Pap9L9VVUkNYj99GCUCC3mJkb'
這是我們設定資料庫使用者名稱和密碼的地方。當然,在運行 bash 腳本時可以傳遞這些變量,就像我們對機器人的名稱和令牌所做的那樣。但在我看來,這是沒有必要的。要實際存取資料庫,您需要知道將部署資料庫的伺服器的 IP,並且位於請求允許的 IP 位址清單中。對我來說,這已經足夠了。基礎已經奠定:現在您可以做開發人員更容易理解的事情 - 編寫程式碼。在此之前,我們正在做 DevOps 工程師所做的事情——設定環境。

新增儲存庫層

通常,應用程式具有三層:
  1. 控制器是應用程式的入口點。
  2. 服務是業務邏輯發揮作用的地方。我們已經部分了解了這一點:SendMessageService 是業務邏輯的明確代表。
  3. 儲存庫是使用資料庫的地方。在我們的例子中,這是一個電報機器人。
現在我們將新增第三層 - 儲存庫。這裡我們將使用Spring生態系統中的一個專案—Spring Data。您可以在這篇關於 Habré 的文章中了解它的內容。我們需要了解並理解以下幾點:
  1. 我們不必使用 JDBC:我們將直接使用更高的抽象。即儲存與資料庫中的表格對應的POJO。我們將此類類別稱為「實體」 ,因為它們在Java 持久性 API中被正式稱為「實體」(這是透過 ORM 操作資料庫的一組通用接口,即對 JDBC 操作的抽象)。我們將有一個實體類,將其保存在資料庫中,它們將準確地寫入我們需要的表中。在資料庫中搜尋時,我們將收到相同的物件。
  2. Spring Data 提供使用它們的介面集:JpaRepositoryCrudRepository等...還有其他介面:可以在此處找到完整清單。美妙之處在於您可以使用它們的方法而不需要實現它們(!)。此外,還有一個特定的模板,您可以使用它在介面中編寫新方法,並且它們將自動實現。
  3. Spring 盡可能地簡化了我們的開發。為此,我們需要建立自己的介面並繼承上述介面。為了讓 Spring 知道它需要使用這個接口,請加入 Repository 註解。
  4. 如果我們需要編寫一個方法來處理不存在的資料庫,那麼這也不是問題 - 我們會編寫它。我將向您展示在那裡做什麼以及如何做。
在本文中,我們將沿著 TelegramUser 的整個路徑進行添加,並以此分為例進行展示。我們將把剩下的內容擴展到其他任務。也就是說,當我們執行/start指令時,我們會將active = true寫入我們使用者的資料庫中。這意味著用戶正在使用機器人。如果使用者已經在資料庫中,我們將更新欄位 active = true。當執行 /stop 命令時,我們不會刪除用戶,而只會將 active 欄位更新為 false,這樣如果用戶想再次使用機器人,他可以啟動它並從上次中斷的地方繼續。因此,在測試時我們可以看到正在發生的事情,我們將建立一個 /stat 命令:它將顯示活動使用者的數量。我們在機器人、命令、服務包旁邊創建一個儲存庫包。在此套件中,我們建立另一個單一實體。在實體包中我們建立 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,但也可以使用其他實作。以下是我們使用的註釋清單:
  • Entity - 表示這是一個用於操作資料庫的實體;
  • Table-這裡我們定義表格的名稱;
  • 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()方法,我沒有在任何地方實作該方法。但這不會阻止他工作。Spring Data 將理解它需要從 tg_user 表中取得active 欄位 = true的所有記錄。我們新增了一個與 TelegramUser 實體一起使用的服務(在其他實體的服務無法直接與另一個實體的儲存庫通訊的情況下,我們使用 SOLID 的依賴關係反轉 - 只能透過該實體的服務)。我們在套件中建立一個服務 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);
   }
}
這裡要注意的是,我們使用Autowired註解對 TelegramuserRepository 物件進行依賴注入(引入類別實例) ,並在建構函式上進行依賴注入。您可以對變數執行此操作,但這是 Spring Framework 團隊向我們推薦的方法。

添加機器人的統計訊息

接下來您需要更新 /start 和 /stop 命令。當使用/start指令時,需要將新使用者儲存到資料庫中,並設定為active=true。且當有/stop時,更新使用者資料:set active = false。讓我們修復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);
   }
}
這裡我們也將 TelegramuserService 物件傳遞給建構函數,用它來儲存新使用者。此外,利用 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的用戶,我們將其停用,即我們設定active = false。你怎麼能親眼看到這一點?讓我們建立一個新命令 /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方法 來取得所有活動使用者的列表,並取得集合的大小。我們現在還需要更新上升的類別:CommandContainerJavarushTelegramBot,以便它們學會傳輸我們需要的新服務。命令容器:
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 類別中的 main 方法啟動資料庫。接下來我們寫一組命令:
  • /stat - 我們預期如果資料庫為空,則使用此機器人的人數將為零;
  • /start - 啟動機器人;
  • /stat - 現在我們預計該機器人將由 1 人使用;
  • /stop - 停止機器人;
  • /stat - 我們預計將再次有 0 人使用它。
「Java 專案從頭到尾」:新增與資料庫相關的所有內容。 第 2 - 2 部分如果結果與您相同,我們可以說該功能正常工作並且機器人工作正常。如果出現問題,也沒關係:我們在偵錯模式下重新啟動 main 方法,並清楚地遍歷整個路徑以查找錯誤所在。

我們編寫和更新測試

由於我們更改了建構函數,因此我們還需要更新測試類別。在AbstractCommandTest類別中,我們需要再增加一個欄位 - TelegramUserService類,三個命令都需要它:
protected TelegramUserService telegramUserService = Mockito.mock(TelegramUserService.class);
接下來,我們更新CommandContainer 中的init()方法:
@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註釋,它將啟動應用程式。但這種方法對我們不起作用,因為當應用程式啟動時,電報機器人也會啟動。但這裡有一個矛盾。測試將在我們的機器上本地運行,並透過 GitHub Actions 公開運行。為了使測試在整個應用程式啟動時通過,我們必須使用電報機器人上的有效數據來運行它們:即透過其名稱和令牌......因此,我們有兩個選擇:
  1. 因此,將機器人的名稱和令牌公開,並希望一切順利,沒有人會使用它並幹擾我們。
  2. 想出另一種辦法。
我選擇了第二個選項。SpringBoot 測試有DataJpaTest註解,它的建立是為了在測試資料庫時,我們只使用我們需要的類,而忽略其他類別。但這適合我們,因為電報機器人根本不會啟動。這意味著不需要向它傳遞有效的名稱和令牌!)))我們將進行一個測試,在其中我們將檢查 Spring Data 為我們實現的方法是否按我們的預期工作。這裡要注意的是,我們使用@ActiveProfiles("test")註解來指定測試設定檔的使用。這正是我們所需要的,以便我們可以計算資料庫的正確屬性。在運行測試之前準備好資料庫會很好。對於這個問題有這樣一種做法:在測試中加入一個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());
   }
}
我們編寫了測試,但問題出現了:在 GitHub 上啟動 CI 流程會發生什麼?它不會有資料庫。現在實際上只有一個紅色版本。為此,我們有 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 流程中,同時定義我們需要的變數。現在我們已經添加了我們想要的一切。最後一個階段是推動變更並確保建置能夠通過並變為綠色。

更新文件

讓我們在 pom.xml 中將專案版本從 0.3.0-SNAPSHOT 更新為 0.4.0-SNAPSHOT,並新增至 RELEASE_NOTES:
## 0.4.0-SNAPSHOT

*   JRTB-1: added repository layer.
所有這些之後,我們建立一個提交、推送和拉取請求。最重要的是,我們的建造是綠色的!「Java 專案從頭到尾」:新增與資料庫相關的所有內容。 第 2 - 3 部分

有用的連結:

所有變更都可以在建立的拉取請求中看到。感謝大家的閱讀。

此系列所有資料的清單位於本文開頭。

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