Spring Initializr 文件

本節簡要概述了 Spring Initializr 參考文件:將其視為文件其餘部分的地圖。某些部分針對特定受眾,因此本參考指南並非旨在按線性方式閱讀。

Spring Initializr 提供了一個可擴充套件的 API,用於生成基於 JVM 的專案,並檢查用於生成專案的元資料,例如列出可用的依賴項和版本。

該文件大致分為三個部分:

  • 簡介:本節介紹了該庫以及如何與服務互動以生成專案。

  • 配置指南:本節介紹瞭如何使用 jars 作為您自己應用程式中的庫來建立自己的 Spring Initializr 例項。

  • API 指南:本節介紹了用於專案生成的 API。該 API 可以獨立使用,也可以嵌入到其他工具中(例如,它在主要的 IDE 中使用,如 Spring Tool Suite、IntelliJ IDEA Ultimate、Netbeans 和 VSCode)。

您可以使用 Spring Initializr 輕鬆建立自己的例項,方法是使用 jar 作為您自己應用程式中的庫。涉及的程式碼量最少,並且該服務具有非常豐富的配置結構,允許您不僅定義各種專案屬性的值,還定義依賴項列表以及要應用於它們的約束。如果這聽起來很有趣,那麼配置指南提供了您需要的所有詳細資訊。您可能只想修改 Spring Initializr 的現有例項,例如新增新的依賴項型別或更新現有依賴項的版本。對於這些以及其他簡單常見的用例,請檢視“操作方法”指南

Spring Initializr 還提供了一個可擴充套件的 API,用於生成基於 JVM 的專案,並檢查用於生成專案的元資料,例如列出可用的依賴項和版本。該 API 可以獨立使用,也可以嵌入到其他工具中(例如,它在主要的 IDE 中使用,如 Spring Tool Suite、IntelliJ IDEA Ultimate、Netbeans 和 VSCode)。這些功能在API 指南中介紹。

1. 關於文件

Spring Initializr 參考指南以 HTML 形式提供。最新版本可在 docs.spring.io/initializr/docs/current/reference/html 獲取。

您可以為自己使用和分發此文件的副本,前提是您不對這些副本收取任何費用,並且每份副本(無論是印刷版還是電子版)都包含此版權宣告。

2. 獲取幫助

Spring Initializr 遇到問題?我們樂意幫助!

Spring Initializr 的所有內容,包括文件,都是開源的!如果您發現文件有問題;或者如果您只是想改進它們,請參與進來

簡介

這是對 Spring Initializr 功能的簡單介紹。您將瞭解與 Spring Initializr 服務互動的各種方式,並更好地瞭解您可以利用它做些什麼。

該服務允許您快速生成基於 JVM 的專案。您可以自定義要生成的專案:構建系統和打包、語言、打包、座標、平臺版本以及最後要新增到專案的依賴項。

3. 專案元資料

Spring Initializr 暴露了許多端點,可用於生成基於 JVM 的專案。您可以透過提供各種核心概念的元資料來輕鬆建立自己的例項

根據元資料和貢獻者列表,專案生成引擎可用於生成實際專案資產。生成的結果可能是一個包含專案的目錄或任何其他內容。

4. Web 端點

該庫可以在 Web 應用程式中使用,以暴露許多用於處理專案生成的端點。服務的主要入口點是其元資料端點,位於上下文的根目錄。它被各種客戶端用於確定可用選項並(如果可能)將其呈現給使用者。

元資料端點還列出了可以生成的專案型別以及服務如何觸發它們。

5. 支援的客戶端

開箱即用,自定義例項使用 cURLHTTPie 處理命令列請求。Spring Initializr 也受各種 IDE 支援,請查閱您喜歡的 IDE 的文件以獲取更多詳細資訊。

Spring Initializr 不提供 Web UI 來與服務互動。

配置指南

您可以使用 Spring Initializr 建立自己的服務,該服務可以生成 JVM 專案。本節描述瞭如何建立自己的服務並根據您的需求對其進行調整,以及如何配置現有服務。

6. 專案生成概述

建立自己的服務之前,讓我們先了解一下專案生成的核心概念以及該庫的結構如何支援它們。

Initializr 分為幾個模組:

  • initializr-actuator:可選模組,提供專案生成的附加資訊和統計資料。

  • initializr-bom:提供物料清單,以便更輕鬆地管理專案中的依賴項。

  • initializr-docs:文件。

  • initializr-generator:核心專案生成庫。

  • initializr-generator-spring:可選模組,定義典型 Spring Boot 專案的約定。可以重用或替換為您自己的約定。

  • initializr-generator-test:專案生成的測試基礎結構。

  • initializr-metadata:專案各個方面的元資料基礎結構。

  • initializr-service-sample:展示了一個基本的自定義例項。

  • initializr-version-resolver:可選模組,用於從任意 POM 中提取版本號。

  • initializr-web:供第三方客戶端使用的 Web 端點。

為了理解專案生成背後的概念,讓我們更詳細地瞭解 initializr-generatorinitializr-generator-spring

6.1. Initializr 生成器

initializr-generator 模組包含生成基於 JVM 的專案所需的底層基礎結構。

6.1.1. 專案生成器

ProjectGenerator 類是專案生成的主要入口點。ProjectGenerator 接受一個 ProjectDescription,它定義了要生成的特定專案,以及一個 ProjectAssetGenerator 的實現,該實現負責根據可用候選項生成資產。

一個專案由 ProjectDescription 定義,它包含以下屬性:

  • 基本座標,如 groupIdartifactIdnamedescription

  • BuildSystemPackaging

  • JVM Language

  • 按 ID 索引的請求依賴項

  • 專案使用的平臺 Version。這可用於根據所選生成調整可用依賴項。

  • application 的名稱

  • 根包名

  • 專案的基本目錄(如果與根目錄不同)

專案生成發生在專用的應用程式上下文 (ProjectGenerationContext) 中,這意味著對於每個生成的專案,該上下文僅包含與該特定專案相關的配置和元件。ProjectGenerationContext 的候選元件在 @ProjectGenerationConfiguration 註解的配置類中定義。如果這些配置類註冊在 META-INF/spring.factories 中,它們將自動匯入,如以下示例所示:

io.spring.initializr.generator.project.ProjectGenerationConfiguration=\
com.example.acme.build.BuildProjectGenerationConfiguration,\
com.example.acme.code.SourceCodeProjectGenerationConfiguration

新增到 ProjectGenerationContext 的元件通常透過條件來提供。使用條件可以避免暴露必須檢查是否需要執行某些操作的 bean,並使宣告更加慣用。考慮以下示例:

@Bean
@ConditionalOnBuildSystem(GradleBuildSystem.ID)
@ConditionalOnPackaging(WarPackaging.ID)
public BuildCustomizer<GradleBuild> warPluginContributor() {
    return (build) -> build.plugins().add("war");
}

這會註冊一個元件,只有當要生成的專案使用“Gradle”BuildSystem 和“war”Packaging 時,它才能自定義 Gradle 構建。有關更多條件,請檢視 io.spring.initializr.generator.condition 包。您可以透過繼承 ProjectGenerationCondition 輕鬆建立自定義條件。

您只能在已載入到 ProjectGenerationConfiguration 上的 bean 上使用此類條件,因為它們需要具體的 ProjectDescription bean 才能正常執行。

專案生成還可能依賴於不特定於特定專案配置的基礎設施,並且通常在主 ApplicationContext 中配置,以避免每次新請求到來時都重新註冊。一個常見的用例是將主 ApplicationContext 設定為 ProjectGenerationContext 的父級,如以下示例所示:

public ProjectGenerator createProjectGenerator(ApplicationContext appContext) {
    return new ProjectGenerator((context) -> {
        context.setParent(appContext);
        context.registerBean(SampleContributor.class, SampleContributor::new);
    });
}

這將建立一個新的 ProjectGenerator,它可以使用應用程式的任何 bean,註冊 META-INF/spring.factories 中找到的所有貢獻者,並且還以程式設計方式註冊一個額外的 ProjectContributor

ProjectContributor 是最高級別的介面,可以實現它來為專案貢獻資產。上面註冊的 SampleContributor 在專案結構的根目錄生成一個 hello.txt 檔案,如下所示:

public class SampleContributor implements ProjectContributor {

    @Override
    public void contribute(Path projectRoot) throws IOException {
        Path file = Files.createFile(projectRoot.resolve("hello.txt"));
        try (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(file))) {
            writer.println("Test");
        }
    }

}

6.1.2. 專案生成生命週期

ProjectGenerator 被指示生成專案時,指定的 ProjectDescription 可以使用可用的 ProjectDescriptionCustomizer bean 進行自定義,並且可以使用 Spring 的 Ordered 介面進行排序。ProjectDescriptionDiff bean 可用於希望知道原始 ProjectDescription 的屬性是否被修改的擴充套件。

一旦根據可用的 ProjectDescriptionCustomizers 自定義了描述,生成器就會使用 ProjectAssetGenerator 來生成專案資產。initializr-generator 模組提供了此介面的預設實現 (DefaultProjectAssetGenerator),它使用可用的 ProjectContributor bean 生成目錄結構。

雖然預設的 ProjectAssetGenerator 使用檔案系統並呼叫一組特定的元件,但可以使用相同的 ProjectGenerator 例項,並使用完全專注於其他事物的自定義實現。

6.1.3. 專案抽象

該模組還包含專案各個方面的抽象以及一些便捷的實現:

  • 具有 Maven 和 Gradle 實現的構建系統抽象。

  • 具有 Java、Groovy 和 Kotlin 實現的語言抽象,包括每種實現的一個 SourceCodeWriter

  • 具有 jarwar 實現的打包抽象。

新增這些新實現需要建立 BuildSystemFactoryLanguageFactoryPackagingFactory,並將它們分別註冊到 META-INF/spring.factories 中,註冊路徑分別為 io.spring.initializr.generator.buildsystem.BuildSystemFactoryio.spring.initializr.generator.language.LanguageFactoryio.spring.initializr.generator.packaging.PackagingFactory

一個 JVM 專案通常包含專案的構建配置。initializr-generator 模組提供了 Build 模型,並提供了 MavenGradle 的實現。該模型可以根據約定進行操作。該庫還提供了 MavenBuildWriterGradleBuildWriter,可以將 Build 模型轉換為構建檔案。

下一節關於initializr-generator-spring模組將展示如何在使用自定義器寫入構建檔案之前操作 Build

6.2. Spring Boot 的約定

這是一個可選模組,定義了我們認為對任何 Spring Boot 專案都有用的約定。如果您的服務旨在生成 Spring Boot 專案,則可以在專案中包含此 jar。

專案生成器部分,我們研究瞭如何使用 ProjectContributor 為專案貢獻資產。該模組包含 ProjectContributor 的具體實現以及配置它們的 @ProjectGenerationConfiguration。例如,有一個 MavenBuildProjectContributor,它貢獻 Maven 構建的檔案,如 pom.xml。此貢獻者在 ProjectGenerationConfiguration 中註冊為 bean,該配置取決於構建系統是 Maven。

該模組還引入了 BuildCustomizer 的概念。BuildCustomizer 用於自定義專案的 Build 並按順序執行。例如,如果您的服務要求您向構建新增某個外掛,您可以提供一個新增該外掛的 BuildCustomizer,並且將根據其上指定的順序呼叫自定義器。

6.2.1. 要求

此模組的貢獻者期望 ProjectGenerationContext 中提供以下 bean:

  • 要使用的 InitializrMetadata 例項

  • 可選地,一個 MetadataBuildItemResolver,可以根據元資料中的 ID 解析各種構建項(例如依賴項和 BOM)。

如果您使用父上下文,建議在那裡配置這些,因為您不應該在每次生成新專案時都重新註冊它們。

  • 表示要使用的縮排策略的 IndentingWriterFactory

  • classpath:/templates 作為根位置的 MustacheTemplateRenderer。考慮使用快取策略註冊此類 bean,以避免每次都解析模板。

6.2.2. 支援的 Facet

支援以下 Facet:

  • web:用於驅動包含 ID 為 web 的依賴項(如果不存在具有該 Facet 的依賴項,則預設為 spring-boot-starter-web)。

  • jpa:用於標記此專案使用 JPA。與 Kotlin 結合使用時,這會確保配置適當的外掛。

  • json:用於標記此專案依賴於 Jackson。與 Kotlin 結合使用時,這會確保新增 Kotlin 特定的 Jackson 模組以實現更好的互操作性。

7. 建立自己的例項

本節描述如何建立自定義服務。

第一步是為您的例項建立一個新專案,並在構建中新增以下內容:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>io.spring.initializr</groupId>
        <artifactId>initializr-web</artifactId>
    </dependency>
    <dependency>
        <groupId>io.spring.initializr</groupId>
        <artifactId>initializr-generator-spring</artifactId>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.spring.initializr</groupId>
            <artifactId>initializr-bom</artifactId>
            <version>0.22.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

或者如果您使用 Gradle:

implementation("org.springframework.boot:spring-boot-starter-web")
implementation("io.spring.initializr:initializr-web")
implementation("io.spring.initializr:initializr-generator-spring")

dependencyManagement {
  imports {
    mavenBom "io.spring.initializr:initializr-bom:0.22.0"
  }
}
假設自定義例項將用於使用 initializr-generator-spring 模組提供的約定生成基於 Spring Boot 的專案。

啟動應用程式後,您可以訪問 localhost:8080。您將獲得一個描述服務功能的 JSON 文件。選擇的功能將沒有值。在本節的其餘部分,我們將配置這些基本設定。

大多數設定都是透過 application.properties 使用 initializr 名稱空間配置的。由於配置是高度分層的,我們建議使用 YAML 格式,這種結構更具可讀性。如果您同意,請在 src/main/resources 中建立一個 application.yml

7.1. 配置基本設定

大多數選定的功能都是透過簡單的基於列表的結構配置的,其中每個條目都有一個 id、一個 name 以及該條目是否為預設值。如果未提供 name,則使用 id

讓我們配置我們想要支援的語言和 JVM 代:

initializr:
  javaVersions:
    - id: 11
      default: false
    - id: 1.8
      default: true
  languages:
    - name: Java
      id: java
      default: true
    - name: Kotlin
      id: kotlin
      default: false

如果您重新啟動應用程式並重新整理 localhost:8080,語言功能現在將具有上面定義的選項和預設值。

那裡定義的語言識別符號必須有一個對應的 Language 實現。javakotlingroovy 可以開箱即用,因為這些語言的實現在核心庫中可用。

可用的打包方式也可以這樣配置:

initializr:
  packagings:
    - name: Jar
      id: jar
      default: true
    - name: War
      id: war
      default: false
Jar 和 War 打包型別是開箱即用的。對於其他打包格式,您需要實現 Packaging 抽象並提供一個與之對應的 PackagingFactory。

7.2. 配置純文字設定

純文字功能包括 groupIdartifactIdnamedescriptionversionpackageName。如果未配置任何內容,每個功能都有一個預設值。預設值可以被覆蓋,如下所示:

initializr:
  group-id:
    value: org.acme
  artifact-id:
    value: my-app

7.3. 配置可用平臺版本

您可以透過與配置其他功能相同的方式配置可用平臺版本。

該概念指的是 bootVersions,因為它早於平臺版本的概念。
initializr:
  bootVersions:
    - id: 2.4.0-SNAPSHOT
      name: 2.4.0 (SNAPSHOT)
      default: false
    - id: 2.3.3.BUILD-SNAPSHOT
      name: 2.3.3 (SNAPSHOT)
      default: false
    - id: 2.3.2.RELEASE
      name: 2.3.2
      default: true

上述配置提供了三個版本,預設使用 2.3.2。但實際上,您可能希望升級可用的平臺版本,而無需每次都重新部署應用程式。實現您自己的 InitializrMetadataUpdateStrategy bean 允許您在執行時更新元資料。

如果您檢視 Spring Boot 的專案主頁,會顯示最新版本。SpringIoInitializrMetadataUpdateStrategy 是該策略的一個實現,它獲取最新的 Spring Boot 版本並更新元資料,以確保使用這些約定的執行例項始終獲得最新的可用版本。

如果您在代理後面,或者需要自定義後臺使用的 RestTemplate,您可以在配置中定義一個 RestTemplateCustomizer bean。有關更多詳細資訊,請查閱文件

如果您選擇使用 SpringIoInitializrMetadataUpdateStrategy,則必須配置快取以避免過於頻繁地請求該服務。

7.4. 配置可用專案型別

可用的專案型別主要定義生成的專案結構及其構建系統。一旦選擇了一個專案型別,就會呼叫相關操作來生成專案。

預設情況下,Spring Initializr 暴露以下資源(均透過 HTTP GET 訪問):

  • /pom.xml 生成 Maven pom.xml

  • /build.gradle 生成 Gradle 構建

  • /starter.zip 生成一個完整的專案結構並歸檔為 zip

  • /starter.tgz 生成一個完整的專案結構並歸檔為 tgz

構建系統必須使用 build 標籤定義,提供要使用的 BuildSystem 的名稱(例如 mavengradle)。

可以提供額外的標籤來進一步限定條目。如果構建系統支援多種方言,則可以使用 dialect 標籤指定所選方言。

還提供了一個 format 標籤來定義專案的格式(例如,project 表示完整專案,build 表示僅構建檔案)。預設情況下,HTML UI 會過濾所有可用型別,只顯示具有 format 標籤且值為 project 的型別。

您當然可以實現額外的端點來生成您需要的任何專案結構,但目前,我們只將我們的例項配置為生成 Gradle 或 Maven 專案:

initializr:
  types:
    - name: Maven Project
      id: maven-project
      description: Generate a Maven based project archive
      tags:
        build: maven
        format: project
      default: true
      action: /starter.zip
    - name: Gradle Project
      id: gradle-project
      description: Generate a Gradle based project archive
      tags:
        build: gradle
        format: project
      default: false
      action: /starter.zip
如果您打算針對您的服務構建自定義客戶端,您可以新增任意數量的標籤,並以對您的使用者有意義的方式在客戶端中處理它們。

例如,Spring Boot CLI 使用它們作為完整型別 ID 的快捷方式。因此,無需像下面這樣建立 Gradle 專案:

$ spring init --type=gradle-project my-project.zip

您可以簡單地定義一個更方便的構建引數:

$ spring init --build=gradle my-project.zip

透過該配置,您應該能夠生成您的第一個專案,恭喜!現在讓我們新增依賴項,以便您可以開始搜尋它們。

7.5. 配置依賴項

最基本的 dependency 由以下部分組成:

  • 在客戶端中用於引用它的 id

  • 依賴項的完整 Maven 座標(groupIdartifactId

  • 一個顯示 name(用於 UI 和搜尋結果)

  • 可以(並且應該)新增 description 以提供有關依賴項的更多資訊

Spring Initializr 自動認為沒有 Maven 座標的依賴項定義了一個官方的 Spring Boot Starter。在這種情況下,id 用於推斷 artifactId

例如,以下配置了 spring-boot-starter-web Starter:

initializr:
  dependencies:
    - name: Web
      content:
        - name: Web
          id: web
          description: Full-stack web development with Tomcat and Spring MVC

每個依賴項都包含在一個“組”中,該組收集共享公共表面區域或任何其他分組形式的依賴項。在上面的示例中,一個“Web”組包含我們唯一的依賴項。組還可以為各種設定提供預設值,有關更多詳細資訊,請參閱專用操作方法

在上面的 spring-boot-starter-web 示例中,我們假設依賴項由平臺管理,因此無需為其提供 version 屬性。您肯定需要定義平臺未提供的其他依賴項,我們強烈建議您使用物料清單 (BOM)

如果沒有 BOM,您可以直接指定版本:

initializr:
  dependencies:
    - name: Tech
      content:
        - name: Acme
          id: acme
          groupId: com.example.acme
          artifactId: acme
          version: 1.2.0.RELEASE
          description: A solid description for this dependency

如果您新增此配置並搜尋“acme”(或“solid”),您將找到此額外條目;使用它生成一個 Maven 專案應該會將以下內容新增到 pom 中:

<dependency>
    <groupId>com.example.acme</groupId>
    <artifactId>acme</artifactId>
    <version>1.2.0.RELEASE</version>
</dependency>

本節的其餘部分將詳細介紹其他配置選項。

7.5.1. 相容性範圍

預設情況下,依賴項無論您選擇哪個平臺版本都可用。如果您需要將依賴項限制在某個平臺生成中,您可以為其定義新增 compatibilityRange 屬性,該屬性定義了一個版本範圍。版本範圍是與它相容的平臺版本範圍。這些版本**不**應用於依賴項本身,而是用於在為生成的專案選擇不同平臺版本時過濾掉依賴項或修改它。

一個版本由四個部分組成:主要修訂版、次要修訂版、補丁修訂版和可選的限定符。Spring Initializr 支援兩種版本格式:

  • V1 是原始格式,其中限定符與版本由點分隔。它還使用定義明確的限定符用於快照 (BUILD-SNAPSHOT) 和通用可用性 (RELEASE)。

  • V2 是一種改進的格式,符合 SemVer 規範,因此使用破折號分隔限定符。GA 沒有限定符。

說到限定符,它們的排序如下:

  • M 用於里程碑(例如,2.0.0.M1 是即將釋出的 2.0.0 的第一個里程碑):可以看作是“beta”版本。

  • RC 用於釋出候選版本(例如,2.0.0-RC2 是即將釋出的 2.0.0 的第二個釋出候選版本)。

  • BUILD-SNAPSHOT 用於開發構建(2.1.0.BUILD-SNAPSHOT 表示即將釋出的 2.1.0 的最新可用開發構建)。對於 V2 格式,它只是 SNAPSHOT,即 2.1.0-SNAPSHOT

  • RELEASE 用於通用可用性(例如,2.0.0.RELEASE 是 2.0.0 正式版)。

快照在該方案中有點特殊,因為它們始終代表發行版的“最新狀態”。M1 代表給定主要、次要和補丁修訂版的最舊版本,因此在提及該行中的“第一個”發行版時可以安全使用。

版本範圍有下限和上限,如果邊界是包含的,則用方括號([])表示,否則是排他的,用括號(())表示。例如 [1.1.6.RELEASE,1.3.0.M1) 表示從 1.1.6.RELEASE 到但不包括 1.3.0.M1(具體來說不包括 1.3.x 行及之後)的所有版本。

版本範圍可以是單個值,例如 1.2.0.RELEASE,它表示“此版本或更高版本”。它是一個包含的下限,具有隱含的無限上限。

如果您需要在給定行中指定“最新版本”,可以使用 x 而不是硬編碼的版本。例如,1.4.x.BUILD-SNAPSHOT 是 1.4.x 行的最新快照構建。例如,如果您想將依賴項限制在從 1.1.0.RELEASE 到 1.3.x 行的最新穩定版本,您可以使用 [1.1.0.RELEASE,1.3.x.RELEASE]

快照自然是給定行中最新版本,因此如果您希望將依賴項僅匹配到平臺的最新快照,則可以使用版本範圍 1.5.x.BUILD-SNAPSHOT(假設 1.5 是最新版本)。

請記住在 YAML 配置檔案中用雙引號將版本範圍的值括起來。

有關更多示例和慣用法,請參見下面連結版本部分。另請參見如何配置平臺版本格式

7.5.2. 倉庫

如果依賴項在 Maven Central(或您配置的任何預設倉庫)上不可用,您還可以新增對倉庫的引用。倉庫在頂級(env 下)宣告,並透過配置中的鍵為其指定一個 ID:

initializr:
  env:
    repositories:
      my-api-repo-1:
        name: repo1
        url: https://example.com/repo1

定義後,就可以在依賴項中引用該倉庫:

initializr:
  dependencies:
    - name: Other
      content:
        - name: Foo
          groupId: org.acme
          artifactId: foo
          version: 1.3.5
          repository: my-api-repo-1

通常最好為每個依賴項提供一個 BOM,並將倉庫附加到 BOM 中。

repo.spring.io 上的快照和里程碑倉庫分別透過 spring-snapshotsspring-milestones 識別符號自動可用。

7.6. 配置物料清單 (BOM)

物料清單 (BOM) 是一個特殊的 pom.xml,部署到 Maven 倉庫,用於控制一組相關工件的依賴管理。在 Spring Boot 生態系統中,我們通常在 BOM 的 artifact id 上使用 -dependencies 字尾。在其他專案中我們看到 -bom。建議所有依賴項都包含在某種 BOM 中,因為它們為依賴項的使用者提供了很好的高階功能。同樣重要的是,專案中使用的 2 個 BOM 不要包含相同依賴項的衝突版本,因此最佳實踐是在新增新 BOM 之前檢視 Spring Initializr 中的現有 BOM,並確保您沒有新增衝突。

在 Spring Initializr 中,BOM 在 env 級別宣告,並透過配置鍵為其指定一個 ID。例如:

initializr:
  env:
    boms:
      my-api-bom:
        groupId: org.acme
        artifactId: my-api-dependencies
        version: 1.0.0.RELEASE
        repositories: my-api-repo-1

如果 BOM 需要一個特殊的、非預設的倉庫,那麼可以在此處引用它,而無需再次顯式列出每個依賴項的倉庫。依賴項或依賴項組可以透過引用 ID 來宣告它需要使用一個或多個 BOM:

initializr:
  dependencies:
    - name: Other
      content:
        - name: My API
          id : my-api
          groupId: org.acme
          artifactId: my-api
          bom: my-api-bom

7.6.1. 根據平臺版本對映座標

除了依賴項或 BOM 的相容性範圍之外,您還可以使用版本對映在更細粒度的級別配置版本關係。依賴項或 BOM 具有“對映”列表,每個對映都包含一個版本範圍,以及一組一個或多個依賴項屬性,用於覆蓋這些平臺版本。例如,您可以使用對映來切換依賴項的版本,或(更好)BOM,或更改其 artifact id(如果專案更改了其打包方式)。

這是一個帶有對映的 BOM 示例:

initializr:
  env:
    boms:
      cloud-bom:
        groupId: com.example.foo
        artifactId: acme-foo-dependencies
        mappings:
          - compatibilityRange: "[1.2.3.RELEASE,1.3.0.RELEASE)"
            groupId: com.example.bar
            artifactId: acme-foo-bom
            version: Arcturus.SR6
          - compatibilityRange: "[1.3.0.RELEASE,1.4.0.RELEASE)"
            version: Botein.SR7
          - compatibilityRange: "[1.4.0.RELEASE,1.5.x.RELEASE)"
            version: Castor.SR6
          - compatibilityRange: "[1.5.0.RELEASE,1.5.x.BUILD-SNAPSHOT)"
            version: Diadem.RC1
            repositories: spring-milestones
          - compatibilityRange: "1.5.x.BUILD-SNAPSHOT"
            version: Diadem.BUILD-SNAPSHOT
            repositories: spring-snapshots,spring-milestones

這裡的主要用例是將平臺版本對映到 Foo 專案的首選或受支援版本。您還可以看到,對於里程碑和快照 BOM,聲明瞭額外的倉庫,因為這些工件不在預設倉庫中。最初,BOM 標識為 com.example.bar:acme-foo-bom,並從 Botein 開始重新命名為 com.example.foo:acme-foo-dependencies

我們還在版本範圍中使用了 x 技巧,以避免每次有新的平臺 1.5 錯誤修復版本可用時都更新範圍。

有關更多示例,請參閱下面連結版本部分。

7.6.2. 別名

依賴項有一個 ID(例如“web-services”),但可能需要提供一個新 ID,同時仍然能夠為使用已棄用 ID 的客戶端提供請求。為此,可以為該依賴項定義一個別名:

initializr:
  dependencies:
    - name: Other
      content:
        - name: Web Services
          id: web-services
          aliases:
            - ws

現在可以使用 dependencies=wsdependencies=web-services 生成同一個專案。

7.6.3. Facet

“facet”是依賴項上的一個標籤,用於驅動生成的專案中的程式碼修改。例如,如果打包型別是 warinitializr-generator-spring 會檢查是否存在帶有 web facet 的依賴項。如果不存在帶有 web facet 的依賴項,則會包含 ID 為 web 的依賴項(如果此類依賴項不可用,則預設為 spring-boot-starter-web)。

依賴項的“facets”屬性的值是一個字串列表。

連結可用於提供描述性超連結資料,以指導使用者瞭解有關依賴項的更多資訊。依賴項具有“links”屬性,它是一個 Link 列表。每個連結都有一個 rel 標籤來標識它,一個 href 和一個可選的(但推薦的)description

目前正式支援以下 rel 值:

  • guide:連結指向描述如何使用相關依賴項的指南。它可以是教程、操作方法或通常是 spring.io/guides 上提供的指南。

  • reference:連結指向開發人員指南的一部分,通常是任何記錄如何使用依賴項的頁面。

如果其實際值可以根據環境而變化,則 URL 可以是模板化的。URL 引數用花括號指定,例如 example.com/doc/{bootVersion}/section 定義了一個 bootVersion 引數。

目前支援以下屬性:

  • bootVersion:當前活動的平臺版本(由於與元資料格式的向後相容性,命名為 bootVersion)。

以下是向 acme 依賴項新增兩個連結的示例:

initializr:
  dependencies:
    - name: Tech
      content:
        - name: Acme
          id: acme
          groupId: com.example.acme
          artifactId: acme
          version: 1.2.0.RELEASE
          description: A solid description for this dependency
          links:
            - rel: guide
              href: https://com.example/guides/acme/
              description: Getting started with Acme
            - rel: reference
              href: https://docs.example.com/acme/html

8. 使用 Web 端點生成專案

要發現特定例項的可用選項,只需“curl”它。假設您的機器上正在預設埠上執行一個例項,請呼叫以下命令:

$ curl https://:8080

或者,如果您更喜歡 HTTPie,您可以按如下方式發現可用選項:

$ http https://:8080

結果是服務功能的文字表示,分為三個部分:

首先,一個描述可用專案型別的表格。

然後,一個描述可用引數的表格。

最後,定義了依賴項列表。每個條目提供您要選擇依賴項時必須使用的識別符號、描述和相容性範圍(如果有)。

除了服務的功能之外,您還會發現一些示例,可幫助您瞭解如何生成專案。這些示例顯然是根據您正在使用的客戶端量身定製的。

假設您想基於平臺版本 2.3.5.RELEASE 生成一個“my-project.zip”專案,並使用 webdevtools 依賴項(請記住,這兩個 ID 顯示在服務的功能中):

$ curl -G https://:8080/starter.zip -d dependencies=web,devtools \
           -d bootVersion=2.3.5.RELEASE -o my-project.zip

如果您解壓 my-project.zip,您會注意到與 Web UI 發生的情況有一些不同之處:

  • 專案將解壓到當前目錄中(Web UI 會自動新增一個與專案名稱相同的基本目錄)。

  • 專案的名稱不是 my-project-o 引數對專案名稱沒有影響)。

也可以使用 http 命令生成完全相同的專案:

$ http https://:8080/starter.zip dependencies==web,devtools \
           bootVersion==2.3.5.RELEASE -d
HTTPie 讀取與瀏覽器相同的提示,因此它會將 demo.zip 檔案儲存在當前目錄中,並具有上述討論的相同差異。

9. ‘How-to’ 指南

本節提供了一些常見“我該如何做……?”型別問題的答案,這些問題在配置 Spring Initializr 時經常出現。

9.1. 新增新依賴項

要新增新的依賴項,首先確定您要新增的依賴項的 Maven 座標(groupId:artifactId:version),然後檢查它適用於哪些平臺版本。如果多個版本適用於不同的平臺版本,那也沒關係。

  • 如果有已釋出的 BOM 管理您的依賴項版本,則首先在 env 部分新增該 BOM(請參閱配置物料清單)。

  • 然後配置依賴項,如果可能,將其放入現有組中,否則建立一個新組。

  • 如果有 BOM,則省略版本。

  • 如果此依賴項需要相容性版本範圍(或最小/最大),請將其新增為連結版本

9.2. 覆蓋依賴項的版本

有時,通常管理您的依賴項版本的 BOM 與最新版本衝突。或者,這可能只適用於某個範圍的 Spring Boot 版本。或者,根本沒有 BOM,或者不值得為單個依賴項建立一個 BOM。在這些情況下,您可以在頂級或在版本對映中手動指定依賴項的版本。在頂級,它看起來像這樣(依賴項中只有一個 version 屬性):

initializr:
  dependencies:
    - name: Tech
      content:
        - name: Acme
          id: acme
          groupId: com.example.acme
          artifactId: acme
          version: 1.2.0.RELEASE
          description: A solid description for this dependency

如果您的依賴項需要特定版本的平臺,或者不同版本的平臺需要不同版本的依賴項,則有幾種機制可以配置。

最簡單的方法是在依賴項宣告中放置 compatibilityRange。這是一個平臺版本範圍,而不是您的依賴項的版本。例如:

initializr:
  dependencies:
    - name: Stuff
      content:
        - name: Foo
          id: foo
          ...
          compatibilityRange: 1.2.0.M1
        - name: Bar
          id: bar
          ...
          compatibilityRange: "[1.5.0.RC1,2.0.0.M1)"

在此示例中,Foo 從平臺 1.2.0 開始可用,Bar 從平臺版本 1.5.0.RC1 開始可用,直到(但不包括)2.0.0.M1

如果您的依賴項的不同版本適用於不同版本的平臺,那麼您就需要 mappings 屬性。對映是 compatibilityRange 和依賴項的一些或所有其他屬性的組合,它會覆蓋頂層定義的值。例如:

initializr:
  dependencies:
    - name: Stuff
      content:
        - name: Foo
          id: foo
          groupId: org.acme.foo
          artifactId: foo-spring-boot-starter
          compatibilityRange: 1.3.0.RELEASE
          bom: cloud-task-bom
          mappings:
            - compatibilityRange: "[1.3.0.RELEASE,1.3.x.RELEASE]"
              artifactId: foo-starter
            - compatibilityRange: "1.4.0.RELEASE"

在此示例中,foo 的工件已更改為 foo-spring-boot-starter,因為與平臺 1.4.0 相容。此對映指示如果選擇了平臺 1.3.x,則 artifactId 應設定為 foo-starter

對映也可以應用於 BOM 宣告。例如:

initializr:
  env:
    boms:
      my-api-bom:
        groupId: org.acme
        artifactId: my-api-bom
        additionalBoms: ['my-api-dependencies-bom']
        mappings:
          - compatibilityRange: "[1.0.0.RELEASE,1.1.6.RELEASE)"
            version: 1.0.0.RELEASE
            repositories: my-api-repo-1
          - compatibilityRange: "1.2.1.RELEASE"
            version: 2.0.0.RELEASE
            repositories: my-api-repo-2

在此示例中,平臺版本到 1.1.6 的版本選擇 BOM 的 1.0.0 版本,並設定不同的倉庫。平臺版本從 1.2.1 開始選擇 BOM 的 2.0.0 版本以及另一個倉庫。

9.4. 配置快照倉庫

如果預設倉庫(通常是 Maven Central)不包含工件,則依賴項或 BOM 可能需要使用特定的倉庫。通常,宣告它的最佳位置是在 BOM 配置中,但如果沒有 BOM,您可以將其放在依賴項本身中。您還可以使用平臺版本對映來覆蓋依賴項或 BOM 的預設倉庫。

9.5. 配置自定義父 POM

對於 Maven 專案,您可以按如下方式配置自定義父 POM:

initializr:
  env:
    maven:
      parent:
        groupId: com.example
        artifactId: my-parent
        version: 1.0.0
        relativePath: ../pom.xml
        includeSpringBootBom : true

如果未指定 relativePath,則從倉庫解析 pom。

includeSpringBootBom 預設為 false。設定為 true 時,spring-boot-dependencies bom 將新增到 dependencyManagement 部分,並使用專案使用的 Spring Boot 版本。

9.6. 確保常規依賴項引入基本 Starter

如果一個依賴項不能獨立存在(特別是如果它不依賴於現有的 Spring Boot starter),您可以將其標記為“非 starter”:

initializr:
  dependencies:
    - name: Stuff
      content:
        - name: Lib
          id: lib
          groupId: com.acme
          artifactId: lib
          starter: false

當生成的專案只有設定了此標誌的依賴項時,也會新增基本的 Spring Boot starter。

9.7. 在組中共享通用依賴項設定

依賴項組是使用者介面實現的一個提示,用於在使用者選擇依賴項時將它們分組在一起。它也是在依賴項之間共享設定的一種便捷方式,因為每個依賴項都繼承了所有設定。組中最常見的設定是 groupIdcompatibilityRangebom

initializr:
  dependencies:
    - name: Stuff
      bom: stuff-bom
      compatibilityRange: "[1.3.0.RELEASE,2.0.0.M1)"
      content:
...

這些依賴項預設情況下僅適用於平臺版本從 1.3.0.RELEASE2.0.0.M1(不包括)的版本,並將引入 stuff-bom BOM。

9.8. 配置 Kotlin 版本對映

預設情況下,要使用的 Kotlin 版本是從元資料推斷的。以下示例顯示瞭如何根據平臺版本對映兩個 Kotlin 版本。

initializr:
  env:
    kotlin:
      mappings:
        - compatibilityRange: "[2.0.0.RELEASE,2.4.0-M1)"
          version: 1.2
        - compatibilityRange: "2.4.0-M1"
          version: 1.3

對於更高階的解析,請考慮實現 KotlinVersionResolver bean。

9.9. 配置平臺版本格式

Spring Initializr 支援兩種格式:V1 是元資料直到 2.1 定義的原始格式。V2 是從元資料 2.2 開始與 V1 一起提供的 SemVer 格式。為了提供向後相容的內容,應配置每種格式的版本範圍,以便相應地進行轉換。

假設一個例項僅支援 2.0.0 及更高版本,並且平臺版本使用原始格式直到 2.4.0(不包括)。從 2.4.0 開始,使用改進的 SemVer 格式。以下配置例項以自動適應版本格式:

initializr:
  env:
    platform:
      compatibility-range: "2.0.0.RELEASE"
      v1-format-compatibility-range: "[2.0.0.RELEASE,2.4.0-M1)"
      v2-format-compatibility-range: "2.4.0-M1"

10. 高階配置

10.1. 快取配置

如果您使用該服務,您會注意到日誌中有許多帶有訊息 Fetching boot metadata from api.spring.io/projects/spring-boot/releases 的條目。為了避免過於頻繁地檢查最新的 Spring Boot 版本,您應該在服務上啟用快取。

如果您願意使用 JCache (JSR-107) 實現,Spring Initializr 會為請求的快取提供自動配置。預設情況下,服務元資料快取配置了過期策略,允許條目在快取中保留 10 分鐘。

快取是透過自動配置的 JCacheManagerCustomizer 建立的,其順序為 0,並且僅當它們尚不存在時才建立。您可以貢獻相同型別的 bean,並使用較低的 @Order 來覆蓋某些配置以滿足您的特定需求。

新增 javax.cache:cache-api 和您喜歡的 JCache 實現,然後只需透過將 @EnableCaching 新增到您的 @SpringBootApplication 中來啟用快取。例如,您可以透過新增以下內容來使用 ehcache

<dependency>
    <groupId>javax.cache</groupId>
    <artifactId>cache-api</artifactId>
</dependency>
<dependency>
    <groupId>org.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <classifier>jakarta</classifier>
</dependency>

或者如果您使用 Gradle:

implementation("javax.cache:cache-api")
implementation("org.ehcache:ehcache::jakarta")

您會注意到日誌條目出現的頻率大大降低。如果您不想使用 JSR-107,則應自行配置快取。以下是應用程式使用的快取(每個快取都需要一些配置才能使其正常工作):

表 1. 快取配置
快取名稱 描述

initializr.metadata

快取服務的完整元資料。當元資料過期時,它會再次完全解析(其中可能包括確定最新平臺版本的網路呼叫)。相應地調整過期設定。

initializr.dependency-metadata

快取特定於依賴項的元資料。

initializr.templates

快取用於生成專案的模板。

10.2. 繫結到自定義專案請求

只有在元資料中定義的屬性才能繫結到 ProjectRequest 並最終在 ProjectDescription 中可用。但是,自定義例項可以選擇提供額外的屬性。請注意,官方客戶端(即 IDE)不支援這些屬性。

第一步是使用您的附加屬性定義一個自定義 ProjectRequest,並建立一個繫結到它的自定義 ProjectGenerationController

public class CustomProjectGenerationController extends ProjectGenerationController<CustomProjectRequest> {

    public CustomProjectGenerationController(InitializrMetadataProvider metadataProvider,
            ProjectGenerationInvoker<CustomProjectRequest> projectGenerationInvoker) {
        super(metadataProvider, projectGenerationInvoker);
    }

    @Override
    public CustomProjectRequest projectRequest(Map<String, String> headers) {
        CustomProjectRequest request = new CustomProjectRequest();
        request.getParameters().putAll(headers);
        request.initialize(getMetadata());
        return request;
    }

}

如果您繼承自 WebProjectRequest,則可以如上所示從元資料自動應用預設值,但您也可以選擇忽略它。

下一步是確保這些附加屬性在 ProjectGenerationContext 中可用。慣用的方法是建立您自己的擴充套件 ProjectDescription 的介面並暴露您的自定義屬性。為了確保您的 ProjectDescription 檢視在 ProjectGenerationContext 中可用,應該定義一個自定義 ProjectRequestToDescriptionConverter,並且可以重用 DefaultProjectRequestToDescriptionConverter 來應用標準欄位的通用規則。

最後,您應該將所有內容連線起來:

@Bean
public CustomProjectGenerationController projectGenerationController(InitializrMetadataProvider metadataProvider,
        ApplicationContext applicationContext) {
    ProjectGenerationInvoker<CustomProjectRequest> projectGenerationInvoker = new ProjectGenerationInvoker<>(
            applicationContext, new CustomProjectRequestToDescriptionConverter());
    return new CustomProjectGenerationController(metadataProvider, projectGenerationInvoker);
}

API 指南

11. 元資料格式

本節描述了 Initializr 暴露的元資料的 HAL/JSON 結構。第三方客戶端可以使用此類元資料來提供選項列表和預設設定,這些選項和設定可用於請求建立專案。

建議第三方客戶端為傳送到服務的**每個**請求設定 User-Agent 頭。一個好的使用者代理結構是 clientId/clientVersion(即,對於“foo”客戶端和版本 1.2.0,為 foo/1.2.0)。

11.1. 服務功能

任何第三方客戶端都可以透過使用以下 Accept 標頭對根 URL 發出 GET 來檢索服務的功能:application/vnd.initializr.v2.2+json。請注意,元資料將來可能會以非向後相容的方式演變,因此新增此標頭可確保服務返回您期望的元資料格式。

支援以下版本:

  • v2 初始版本,僅支援 V1 版本格式。

  • v2.1 支援相容性範圍和依賴項鍊接。

  • v2.2(當前)支援 V1 和 V2 版本格式。

這是在 start.example.com 執行的服務的示例輸出:

請求
GET / HTTP/1.1
Accept: application/vnd.initializr.v2.2+json
Host: start.example.com
響應
HTTP/1.1 200 OK
ETag: "02842ebd1bdc7f2250fd7e76c2840951"
Content-Type: application/vnd.initializr.v2.2+json
Vary: Accept
Cache-Control: max-age=7200
Content-Length: 4842

{
  "_links" : {
    "maven-build" : {
      "href" : "http://start.example.com/pom.xml?type=maven-build{&dependencies,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}",
      "templated" : true
    },
    "maven-project" : {
      "href" : "http://start.example.com/starter.zip?type=maven-project{&dependencies,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}",
      "templated" : true
    },
    "gradle-build" : {
      "href" : "http://start.example.com/build.gradle?type=gradle-build{&dependencies,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}",
      "templated" : true
    },
    "gradle-project" : {
      "href" : "http://start.example.com/starter.zip?type=gradle-project{&dependencies,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}",
      "templated" : true
    },
    "dependencies" : {
      "href" : "http://start.example.com/dependencies{?bootVersion}",
      "templated" : true
    }
  },
  "dependencies" : {
    "type" : "hierarchical-multi-select",
    "values" : [ {
      "name" : "Core",
      "values" : [ {
        "id" : "web",
        "name" : "Web",
        "description" : "Web dependency description",
        "_links" : {
          "guide" : {
            "href" : "https://example.com/guide",
            "title" : "Building a RESTful Web Service"
          },
          "reference" : {
            "href" : "https://example.com/doc"
          }
        }
      }, {
        "id" : "security",
        "name" : "Security"
      }, {
        "id" : "data-jpa",
        "name" : "Data JPA"
      } ]
    }, {
      "name" : "Other",
      "values" : [ {
        "id" : "org.acme:foo",
        "name" : "Foo",
        "_links" : {
          "guide" : [ {
            "href" : "https://example.com/guide1"
          }, {
            "href" : "https://example.com/guide2",
            "title" : "Some guide for foo"
          } ],
          "reference" : {
            "href" : "https://example.com/{bootVersion}/doc",
            "templated" : true
          }
        }
      }, {
        "id" : "org.acme:bar",
        "name" : "Bar"
      }, {
        "id" : "org.acme:biz",
        "name" : "Biz",
        "versionRange" : "2.6.0-SNAPSHOT"
      }, {
        "id" : "org.acme:bur",
        "name" : "Bur",
        "versionRange" : "[2.4.4,2.5.0-SNAPSHOT)"
      }, {
        "id" : "my-api",
        "name" : "My API"
      } ]
    } ]
  },
  "type" : {
    "type" : "action",
    "default" : "maven-project",
    "values" : [ {
      "id" : "maven-build",
      "name" : "Maven POM",
      "action" : "/pom.xml",
      "tags" : {
        "build" : "maven",
        "format" : "build"
      }
    }, {
      "id" : "maven-project",
      "name" : "Maven Project",
      "action" : "/starter.zip",
      "tags" : {
        "build" : "maven",
        "format" : "project"
      }
    }, {
      "id" : "gradle-build",
      "name" : "Gradle Config",
      "action" : "/build.gradle",
      "tags" : {
        "build" : "gradle",
        "format" : "build"
      }
    }, {
      "id" : "gradle-project",
      "name" : "Gradle Project",
      "action" : "/starter.zip",
      "tags" : {
        "build" : "gradle",
        "format" : "project"
      }
    } ]
  },
  "packaging" : {
    "type" : "single-select",
    "default" : "jar",
    "values" : [ {
      "id" : "jar",
      "name" : "Jar"
    }, {
      "id" : "war",
      "name" : "War"
    } ]
  },
  "javaVersion" : {
    "type" : "single-select",
    "default" : "1.8",
    "values" : [ {
      "id" : "1.6",
      "name" : "1.6"
    }, {
      "id" : "1.7",
      "name" : "1.7"
    }, {
      "id" : "1.8",
      "name" : "1.8"
    } ]
  },
  "language" : {
    "type" : "single-select",
    "default" : "java",
    "values" : [ {
      "id" : "groovy",
      "name" : "Groovy"
    }, {
      "id" : "java",
      "name" : "Java"
    }, {
      "id" : "kotlin",
      "name" : "Kotlin"
    } ]
  },
  "bootVersion" : {
    "type" : "single-select",
    "default" : "2.4.4",
    "values" : [ {
      "id" : "2.5.0-SNAPSHOT",
      "name" : "Latest SNAPSHOT"
    }, {
      "id" : "2.4.4",
      "name" : "2.4.4"
    }, {
      "id" : "2.3.10.RELEASE",
      "name" : "2.3.10"
    } ]
  },
  "groupId" : {
    "type" : "text",
    "default" : "com.example"
  },
  "artifactId" : {
    "type" : "text",
    "default" : "demo"
  },
  "version" : {
    "type" : "text",
    "default" : "0.0.1-SNAPSHOT"
  },
  "name" : {
    "type" : "text",
    "default" : "demo"
  },
  "description" : {
    "type" : "text",
    "default" : "Demo project for Spring Boot"
  },
  "packageName" : {
    "type" : "text",
    "default" : "com.example.demo"
  }
}

當前的功能如下:

  • 專案依賴項:這些實際上是“Starter”或我們可能想新增到專案的任何依賴項。

  • 專案型別:這些定義了可以在此服務上呼叫的操作以及它將產生什麼的描述(例如,一個包含預配置 Maven 專案的 zip 檔案)。每種型別可能有一個或多個標籤,進一步定義它生成什麼。

  • 打包:要生成的專案型別。這僅僅給負責生成專案的元件一個提示(例如,生成一個可執行的“jar”專案)。

  • Java 版本:支援的 Java 版本。

  • 語言:要使用的語言(例如 Java)。

  • Boot 版本:要使用的平臺版本。

  • 其他基本資訊,例如:groupIdartifactIdversionnamedescriptionpackageName

每個頂級屬性(即功能)都具有標準格式:

  • 一個 type 屬性,定義屬性的語義(見下文)。

  • 一個 default 屬性,定義預設值或預設值的引用。

  • 一個 values 屬性,定義可接受的值集(如果有)。這可以是分層的(values 中包含 values)。values 陣列中的每個專案都可以有一個 idnamedescription)。

支援以下屬性 type

  • text:定義一個簡單的文字值,沒有選項。

  • single-select:定義一個簡單的值,從指定選項中選擇。

  • hierarchical-multi-select:定義一組分層值(值中包含值),能夠選擇多個值。

  • action:一種特殊型別,定義了用於定義要使用的操作的屬性。

每個操作都定義為符合 HAL 規範的 URL。例如,maven-project 型別模板化 URL 定義如下:

型別連結示例
{
  "href" : "http://start.example.com/starter.zip?type=maven-project{&dependencies,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}",
  "templated" : true
}

您可以使用 Spring HATEOAS,特別是 UriTemplate 助手從模板變數生成 URI。請注意,變數與元資料文件中頂級屬性的名稱匹配。如果您無法解析此類 URI,則每個型別的 action 屬性會為您提供要在伺服器上呼叫的根操作。這需要您進行更多手動處理。

11.1.1. 專案依賴項

依賴項通常是“啟動器”模組的座標,但它也可以是常規依賴項。典型的依賴項結構如下所示:

{
  "name": "Display name",
  "id": "org.acme.project:project-starter-foo",
  "description": "What starter foo does"
}

名稱用作顯示名稱,在遠端客戶端使用的任何 UI 中顯示。ID 可以是任何內容,因為實際的依賴項定義是透過配置定義的。如果未定義 ID,則使用依賴項的 groupIdartifactId 構建預設 ID。特別注意,版本**從不**用作自動 ID 的一部分。

每個依賴項都屬於一個組。組的目的是收集相似的依賴項並對其進行排序。以下是一個包含 core 組的值,用於說明該功能:

依賴組示例
{
  "name" : "Core",
  "values" : [ {
    "id" : "web",
    "name" : "Web",
    "description" : "Web dependency description",
    "_links" : {
      "guide" : {
        "href" : "https://example.com/guide",
        "title" : "Building a RESTful Web Service"
      },
      "reference" : {
        "href" : "https://example.com/doc"
      }
    }
  }, {
    "id" : "security",
    "name" : "Security"
  }, {
    "id" : "data-jpa",
    "name" : "Data JPA"
  } ]
}

每個依賴項都可以有“連結”(符合 HAL 規範的格式)。連結按“關係”分組,為連結提供語義。連結還可以有一個“標題”,其 URI 可以是模板化的。目前,唯一有效的引數是 bootVersion

官方關係如下:

  • guide:連結到解釋如何開始的教程或指南。

  • reference:連結到參考指南(文件)的一部分。

11.1.2. 專案型別

type 元素定義了可以生成哪種專案以及如何生成。例如,如果服務公開了生成 Maven 專案的能力,它將如下所示:

專案型別示例
{
  "id" : "maven-build",
  "name" : "Maven POM",
  "action" : "/pom.xml",
  "tags" : {
    "build" : "maven",
    "format" : "build"
  }
}

您不應依賴於根據該資訊定義的輸出格式。始終使用定義 Content-TypeContent-Disposition 標頭的響應標頭。

請注意,每個 ID 都有一個相關的 HAL 相容連結,可用於根據模板變數生成正確的 URI。頂級 type 與任何其他屬性一樣,都有一個 default 屬性,作為在相關 UI 元件中選擇預設值的提示。

如果無法使用 HAL 相容的 URL,則 action 屬性定義了客戶端應聯絡的端點以實際生成該型別的專案。

tags 物件用於對專案型別進行分類並向第三方客戶端提供“提示”。例如,“build”標籤定義了專案將使用的構建系統,“format”標籤定義了生成內容的格式(即,此處是完整專案與構建檔案。請注意,回覆的 Content-type 標頭提供了額外的元資料)。

11.1.3. 打包

packaging 元素定義了應該生成的專案型別。

打包示例
{
  "id" : "jar",
  "name" : "Jar"
}

此元素顯而易見的值是 jarwar

11.1.4. Java 版本

javaVersion 元素提供了專案可能的 Java 版本列表:

Java 示例
{
  "id" : "1.6",
  "name" : "1.6"
}

11.1.5. 語言

language 元素提供了專案可能的語言列表:

語言示例
{
  "id" : "groovy",
  "name" : "Groovy"
}

11.1.6. 平臺版本

bootVersion 元素提供了可用平臺版本列表:

平臺版本示例
{
  "id" : "2.5.0-SNAPSHOT",
  "name" : "Latest SNAPSHOT"
}

11.2. 預設值

每個頂級元素都有一個 default 屬性,應將其用作在相關 UI 元件中提供預設值的提示。

12. 使用存根

Spring Initializr 專案釋出了其專案中測試的所有 JSON 響應的 WireMock 存根。如果您正在為 Spring Initializr 服務編寫客戶端,您可以使用這些存根來測試您的程式碼。您可以使用原始 Wiremock API,或透過 Spring Cloud Contract 的一些功能來使用它們。

WireMock 是一個嵌入式 Web 伺服器,它分析傳入請求並根據匹配某些規則(例如特定標頭值)選擇存根響應。因此,如果您向它傳送一個與其某個存根匹配的請求,它將向您傳送一個響應,就像它是一個真實的 Initializr 服務一樣,您可以使用它來對您的客戶端進行全棧整合測試。

12.1. 將 WireMock 與 Spring Boot 結合使用

12.1.1. 從類路徑載入存根

在您的專案中消費存根的一種便捷方式是新增測試依賴項:

<dependency>
    <groupId>io.spring.initializr</groupId>
    <artifactId>initializr-web</artifactId>
    <classifier>stubs</classifier>
    <version>0.22.0</version>
    <scope>test</scope>
</dependency>

然後從類路徑中拉取存根。在 Spring Boot 應用程式中,使用 Spring Cloud Contract,您可以啟動 WireMock 伺服器並註冊所有存根,如以下基於 JUnit 5 的示例所示:

@SpringBootTest
@AutoConfigureWireMock(port = 0,
    stubs="classpath:META-INF/io.spring.initializr/initializr-web/0.22.0")
class ClientApplicationTests {

    @Value("${wiremock.server.port}")
    private int port;

    ...

}

Wiremock 功能隨 Spring Cloud Contract Wiremock 提供。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-contract-wiremock</artifactId>
    <scope>test</scope>
</dependency>
此依賴項由 spring-cloud-contract-dependencies BOM 管理。

12.1.2. 使用 Stub Runner

或者,您可以配置存根執行程式來查詢工件,使用不同的 Spring Cloud Contract 依賴項:spring-cloud-starter-contract-stub-runner。以下示例將自動下載(如果需要)Spring Initializr 存根的定義版本(因此您無需將存根宣告為依賴項):

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-contract-stubrunner</artifactId>
    <scope>test</scope>
</dependency>

測試應使用 @AutoConfigureStubRunner 代替,如以下基於 JUnit 5 的示例所示:

@SpringBootTest(webEnvironment = WebEnvironment.NONE)
@AutoConfigureStubRunner(
    ids = "io.spring.initializr:initializr-web:0.22.0",
    repositoryRoot = "https://repo.spring.io/0")
class ClientApplicationTests {

    @Autowired
    private StubFinder stubFinder;


    ...

}

以下是一個基於 JUnit 5 的測試示例,它檢索服務的元資料。斷言在這裡並不重要,但它說明了您如何將其整合到自定義客戶端的測試套件中:

@SpringBootTest(webEnvironment = WebEnvironment.NONE)
@AutoConfigureStubRunner(ids = "io.spring.initializr:initializr-web:${project.version}", stubsMode = StubsMode.LOCAL)
class ClientApplicationTests {

    @Autowired
    private StubFinder stubFinder;

    @Autowired
    private RestTemplate restTemplate;

    @Test
    void testCurrentMetadata() {
        RequestEntity<Void> request = RequestEntity.get(createUri("/"))
            .accept(MediaType.valueOf("application/vnd.initializr.v2.1+json"))
            .build();

        ResponseEntity<String> response = this.restTemplate.exchange(request, String.class);
        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
        // other assertions here
    }

    private URI createUri(String path) {
        String url = this.stubFinder.findStubUrl("initializr-web").toString();
        return URI.create(url + path);
    }

    @TestConfiguration
    static class Config {

        @Bean
        RestTemplate restTemplate(RestTemplateBuilder builder) {
            return builder.build();
        }

    }

}

然後,當您傳送標頭 Accept:application/vnd.initializr.v2.2+json 時(如推薦),伺服器會返回 JSON 元資料(metadataWithCurrentAcceptHeader.json)的存根。

12.2. 存根的名稱和路徑

存根以一種形式(在“**/mappings”下)放在 jar 檔案中,可以被 WireMock 消費,只需設定其檔案源。單個存根的名稱與在 Spring Initializr 專案中生成它們的測試用例的方法名稱相同。例如,MainControllerIntegrationTests 中有一個測試用例“metadataWithV2AcceptHeader”,它斷言當 accept 標頭為 application/vnd.initializr.v2.1+json 時的響應。響應記錄在存根中,如果客戶端中使用的標頭和請求引數與 Spring Initializr 測試用例中使用的相同,它將與 WireMock 匹配。方法名稱通常總結了這些值。

存根執行程式和上面示例中的 @AutoConfigureWireMock 將所有存根載入到 WireMock 中,因此您不一定需要知道存根的名稱。但是,您也可以逐個註冊存根,在這種情況下,掃描存根 jar 並將檔名與測試方法進行比較會有所幫助。例如,如果您檢視存根 jar,您會看到一個名為 metadataWithV2AcceptHeader.json 的檔案,並且在 initializr-web 專案中,有一個名為 metadataWithV2AcceptHeader 的測試方法生成了它。

© . This site is unofficial and not affiliated with VMware.