かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

Gradle で Multi-project を作成する ( その6 )( Multi-project は settings.gradle に include を書くだけでもよいのでは? )

概要

記事一覧はこちらです。

Gradle で Multi-project を作成する ( その5 )( lib+webappx2編、Spring Boot ベースの Web アプリケーション(スタブ)のプロジェクトを作成する ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • 先に進める前に、Gradle の Multi-project は Gradle の project を1つのディレクトリの下に集めて、親ディレクトリに setting.gradle を作成して、その中に include 文を書けばそれで Multi-project として扱われるのではないだろうか。。。と思ったので試してみます。

参照したサイト・書籍

目次

  1. 2つ Multi-project を作成した上での考察。。。include だけでもいいのでは?
  2. gradle-multiprj-includeonly ディレクトリを作成する
  3. Gradle Wrapper のファイル一式をコピーする
  4. gradlew init コマンドを実行する
  5. IntelliJ IDEA で gradle-multiprj-includeonly プロジェクトを開く
  6. IntelliJ IDEA で sample-lib プロジェクトを新規作成する
  7. setting.gradle に include 'sample-lib' を追加する
  8. sample-lib プロジェクトに StrNumUtils クラスを追加する
  9. IntelliJ IDEA で sample-webapp プロジェクトを新規作成する
  10. setting.gradle に include 'sample-webapp' を追加する
  11. sample-webapp プロジェクトに SampleController クラスを追加する
  12. 動作確認
  13. まとめ

手順

2つ Multi-project を作成した上での考察。。。include だけでもいいのでは?

ここまで2つ Multi-project を作成してみましたが、そこまで凝る必要がなければ setting.gradle に include 文を記述するだけで十分な気がするんですよね。。。

たぶんこんな感じで作っても Multi-project になる気がします。

  • ルートディレクトリの直下に build.gradle を作成してサブプロジェクトの共通の設定を書けば確かに便利だが、実はルートディレクトリ直下には build.gradle はなくてもよい(サブプロジェクト毎に別々に build.gradle があるだけでOK)。
  • ルートディレクトリの下に作成したサブプロジェクトの中のディレクトリ・ファイルはそのままでもよい(何も削除する必要はない)。
  • ルートディレクトリ直下の setting.gradle に include '<サブプロジェクト名>' を記述すれば Multi-project になる。

試してみます。以下のような作り方でも Multi-project になるはずです。

  1. プロジェクトのルートディレクトリを作成する。
  2. Gradle Wrapper のファイル一式をコピーする。
  3. gradlew init コマンドを実行する。
  4. IntelliJ IDEA でプロジェクトを開く。
  5. 後は以下の作業の繰り返し。
    1. IntelliJ IDEA で Gradle プロジェクトか、Spring Boot のプロジェクト(Gradle 版)を作成する。
    2. ルートディレクトリ直下の setting.gradle に include '<サブプロジェクト名>' を記述する。
    3. Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新する。

gradle-multiprj-includeonly ディレクトリを作成する

D:\project-springboot\ksbysample-boot-miscellaneous の下に gradle-multiprj-includeonly ディレクトリを作成します。

f:id:ksby:20190423224300p:plain

Gradle Wrapper のファイル一式をコピーする

gradle-multiprj-lib-webapp2 プロジェクトから Gradle Wrapper のファイル一式をコピーします。

f:id:ksby:20190423224611p:plain

gradlew init コマンドを実行する

コマンドラインから gradlew init コマンドを実行します。

f:id:ksby:20190423224821p:plain

gradle-multiprj-includeonly ディレクトリ内に setting.gradle、build.gradle が作成されて、

f:id:ksby:20190423224912p:plain

setting.gradle には以下の内容が記述されています。コメントの部分は削除します。

/*
 * This file was generated by the Gradle 'init' task.
 *
 * The settings file is used to specify which projects to include in your build.
 *
 * Detailed information about configuring a multi-project build in Gradle can be found
 * in the user manual at https://docs.gradle.org/5.4/userguide/multi_project_builds.html
 */

rootProject.name = 'gradle-multiprj-includeonly'

build.gradle は以下の内容が記述されています。今回このファイルは何も変更しません。

/*
 * This file was generated by the Gradle 'init' task.
 *
 * This is a general purpose Gradle build.
 * Learn how to create Gradle builds at https://guides.gradle.org/creating-new-gradle-builds/
 */

IntelliJ IDEA で gradle-multiprj-includeonly プロジェクトを開く

IntelliJ IDEA で gradle-multiprj-includeonly プロジェクトを開きます。Project Tool Window と Gradle Tool Window は以下のように表示されます。

f:id:ksby:20190423225829p:plain f:id:ksby:20190423225925p:plain

IntelliJ IDEA で sample-lib プロジェクトを新規作成する

gradle-multiprj-includeonly ディレクトリの下に sample-lib プロジェクトを新規作成します。Gradle プロジェクトとして作成します。

f:id:ksby:20190423230209p:plain f:id:ksby:20190423230330p:plain

ディレクトリ・ファイルは以下のようになります。今回はこのディレクトリの中は何も削除しません(Gradle Wrapper も残したままです)。

f:id:ksby:20190423230522p:plain

setting.gradle に include 'sample-lib' を追加する

setting.gradle に include 'sample-lib' を追加します。

rootProject.name = 'gradle-multiprj-includeonly'
include 'sample-lib'

Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新すると、Gradle Tool Window に sample-lib プロジェクトが表示されます。

f:id:ksby:20190423231307p:plain

sample-lib プロジェクトに StrNumUtils クラスを追加する

sample-lib/src/main/java の下に ksbysample.lib.samplelib パッケージを作成した後、StrNumUtils.java を新規作成して以下の内容を記述します。

package ksbysample.lib.samplelib;

public class StrNumUtils {

    public static String plus(String v1, String v2) {
        return String.valueOf(Integer.parseInt(v1) + Integer.parseInt(v2));
    }

}

IntelliJ IDEA で sample-webapp プロジェクトを新規作成する

gradle-multiprj-includeonly ディレクトリの下に sample-webapp プロジェクトを新規作成します。Spring Initializr で作成します。

f:id:ksby:20190424001107p:plain f:id:ksby:20190424001246p:plain f:id:ksby:20190424001356p:plain f:id:ksby:20190424001725p:plain

ディレクトリ・ファイルは以下のようになります。このディレクトリの中は何も削除しません。

f:id:ksby:20190424002027p:plain

setting.gradle に include 'sample-webapp' を追加する

setting.gradle に include 'sample-webapp' を追加します。

rootProject.name = 'gradle-multiprj-includeonly'
include 'sample-lib'
include 'sample-webapp'

Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新すると、Gradle Tool Window に sample-webapp プロジェクトが表示されます。

f:id:ksby:20190424002334p:plain

sample-webapp プロジェクトに SampleController クラスを追加する

sample-webapp プロジェクトの build.gradle に sample-lib プロジェクトへの依存関係を追加します。

plugins {
    id 'org.springframework.boot' version '2.1.4.RELEASE'
    id 'java'
}

apply plugin: 'io.spring.dependency-management'

group = 'ksby.ksbysample-boot-miscellaneous'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    runtimeOnly 'org.springframework.boot:spring-boot-devtools'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'

    implementation project(":sample-lib")
}
  • dependencies block に implementation project(":sample-lib") を追加します。

変更後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。

sample-webapp/src/main/java/ksbysample/webapp/samplewebapp/SampleController.java を新規作成して以下の内容を記述します。

package ksbysample.webapp.samplewebapp;

import ksbysample.lib.samplelib.StrNumUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/sample")
public class SampleController {

    @RequestMapping
    @ResponseBody
    public String index() {
        return StrNumUtils.plus("1", "2");
    }

}

動作確認

最初に clean タスク実行 → Rebuild Project 実行 → build タスク実行を行うと、BUILD SUCCESSFUL のメッセージが出力されることを確認します。

f:id:ksby:20190424074417p:plain

Run/Debug Configuration に SampleWebappApplication が自動で登録されているので、ここから Tomcat を起動して、

f:id:ksby:20190424074557p:plain f:id:ksby:20190424074735p:plain

http://localhost:8080/sample にアクセスすると 3 と表示されます。

f:id:ksby:20190424074836p:plain

Project Tool Window で見ると以下のディレクトリ構成になっており、sample-lib-1.0-SNAPSHOT.jar、sample-webapp-0.0.1-SNAPSHOT.jar が生成されています。

f:id:ksby:20190424075014p:plain f:id:ksby:20190424075137p:plain

コマンドプロンプトから java -jar sample-webapp-0.0.1-SNAPSHOT.jar コマンドで Tomcat を起動してから、

f:id:ksby:20190424075452p:plain

http://localhost:8080/sample にアクセスしても 3 と表示されます。

f:id:ksby:20190424075540p:plain

まとめ

setting.gradle に include 文を書くだけでも Multi-project とみなされますね。プロジェクトが1つでも最初から Multi-project のディレクトリ・ファイル構成で作っておいて、開発途中にちょっとしたスタブが欲しい時にはサブプロジェクトを作成して setting.gradle に include を追加して対応する、というのもありなのかもしれません。

履歴

2019/04/24
初版発行。

Gradle で Multi-project を作成する ( その5 )( lib+webappx2編、Spring Boot ベースの Web アプリケーション(スタブ)のプロジェクトを作成する )

概要

記事一覧はこちらです。

Gradle で Multi-project を作成する ( その4 )( lib+webappx2編、Multi-project の設定ファイルと Spring Boot ベースの Web アプリケーション(メイン)のプロジェクトを作成する ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • Gradle で Spring を使用しないライブラリ+Spring Boot ベースの Web アプリケーション x 2(メインとスタブ)の Multi-project を作成します。
    • sample-stubapp プロジェクト(こちらが sample-lib の StrNumUtils クラスを呼び出します)を作成した後、sample-webapp の SampleController クラスを本実装して Multi-project を完成させます。

参照したサイト・書籍

  1. Spring @WebMvcTest with Spock Framework
    https://allegro.tech/2018/04/Spring-WebMvcTest-with-Spock.html

  2. Spring Boot RestTemplate POST JSON Example
    https://howtodoinjava.com/spring-boot2/resttemplate-post-json-example/

目次

  1. Spring Boot ベースの Web アプリケーション(スタブ)のプロジェクトを作成する
    1. IntelliJ IDEA で sample-stubapp プロジェクトを作成する
    2. sample-stubapp プロジェクトから不要なファイルを削除する
    3. sample-stubapp プロジェクトの build.gradle を変更する
    4. gradle-multiprj-lib-webapp2 プロジェクトの build.gradle を変更する
    5. settings.gradle に sample-stubapp プロジェクトの include 文を追加する
    6. application.properties に server.port=9080 を追加する
    7. StubWebapiController クラスを新規作成する
  2. sample-webapp の SampleController クラスを本実装する
  3. clean タスク実行 → Rebuild Project 実行 → build タスク実行を行う
  4. Run Dashboard から sample-webapp、sample-stubapp を起動して動作確認する
  5. sample-webapp、sample-stubapp を jar ファイルから起動して動作確認する
  6. まとめ

手順

Spring Boot ベースの Web アプリケーション(スタブ)のプロジェクトを作成する

IntelliJ IDEA で sample-stubapp プロジェクトを作成する

IntelliJ IDEA から Spring Initializr を利用して Spring Boot ベースの Web アプリケーションのプロジェクトを作成します。

f:id:ksby:20190421192134p:plain f:id:ksby:20190421192259p:plain f:id:ksby:20190421192417p:plain f:id:ksby:20190421192450p:plain ※DevTools と Web の2つをチェックします。

f:id:ksby:20190421192551p:plain f:id:ksby:20190421192629p:plain

作成後 IntelliJ IDEA のウィンドウが開きますが、何もせずに閉じます。

sample-stubapp プロジェクトから不要なファイルを削除する

D:\project-springboot\ksbysample-boot-miscellaneous\gradle-multiprj-lib-webapp2\sample-stubapp\ の下には以下のディレクトリ・ファイルがありますが、

f:id:ksby:20190421192923p:plain

src ディレクトリと build.gradle 以外を削除します。削除すると以下の状態になります。

f:id:ksby:20190421193047p:plain

sample-stubapp プロジェクトの build.gradle を変更する

sample-stubapp プロジェクトの build.gradle を以下の内容に変更します。必要な設定は gradle-multiprj-lib-webapp2 の build.gradle に記述したので、このファイルには sample-lib への依存関係だけ記述します。

dependencies {
    implementation project(":sample-lib")
}

gradle-multiprj-lib-webapp2 プロジェクトの build.gradle を変更する

gradle-multiprj-lib-webapp2 プロジェクトの build.gradle を以下のように変更します。

..........

configure(subprojects.findAll { it.name ==~ /^(sample-webapp|sample-stubapp)$/ }) {
    ..........
}
  • it.name ==~ /^(sample-webapp)$/it.name ==~ /^(sample-webapp|sample-stubapp)$/ に変更します。

settings.gradle に sample-stubapp プロジェクトの include 文を追加する

D:\project-springboot\ksbysample-boot-miscellaneous\gradle-multiprj-lib-webapp2 の下の settings.gradle に include 'sample-stubapp' を追加します。

rootProject.name = 'gradle-multiprj-lib-webapp2'
include 'sample-lib'
include 'sample-webapp'
include 'sample-stubapp'

追加後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新すると sample-stubapp が追加されます。

f:id:ksby:20190421194121p:plain

また IntelliJ IDEA の画面右下に「Run Dashboard」のダイアログが表示されます。「Show run configurations Run Dashboard」リンクをクリックすると Run Dashboard Tool Window が表示されます。

f:id:ksby:20190421202534p:plain f:id:ksby:20190421202743p:plain

※ちなみに Run Dashboard Tool Window は Run/Debug Configurations で Spring Boot に2つ以上設定を追加すれば表示させることができます。

f:id:ksby:20190421203153p:plain

clean タスク実行 → Rebuild Project 実行 → build タスク実行を行うと、BUILD SUCCESSFUL のメッセージが出力されました。

f:id:ksby:20190421204259p:plain f:id:ksby:20190421204421p:plain

Project Tool Window を見ると以下のディレクトリ構成になっています。sample-stubapp/build/libs の下に sample-stubapp-1.0.0-RELEASE.jar が生成されています。

f:id:ksby:20190421204810p:plain

application.properties に server.port=9080 を追加する

sample-stubapp/src/main/resources/application.properties に server.port=9080 を追加します。

server.port=9080

StubWebapiController クラスを新規作成する

以下の仕様の StubWebapiController クラスを作成します。

  • URL は /plus にする。
  • HTTP メソッドは POST のみ有効にする。
  • データは JSON で渡す。{ "v1": "<数値文字列>", "v2": "<数値文字列>" } のフォーマットする。
  • レスポンスは { "result": "<数値文字列>" } のフォーマットで返す。
  • エラー処理は考慮しない。

sample-stubapp/src/main/java/ksbysample/webapp/samplestubapp の下に PlusForm、PlusResponse、StubWebapiController クラスを新規作成し、以下の内容を記述します。

■PlusForm

package ksbysample.webapp.samplestubapp;

public class PlusForm {

    private String v1;

    private String v2;

    public String getV1() {
        return v1;
    }

    public void setV1(String v1) {
        this.v1 = v1;
    }

    public String getV2() {
        return v2;
    }

    public void setV2(String v2) {
        this.v2 = v2;
    }

}

■PlusResponse

package ksbysample.webapp.samplestubapp;

public class PlusResponse {

    private String result;

    PlusResponse() {
    }

    PlusResponse(String result) {
        this.result = result;
    }

    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
    }

}

■StubWebapiController

package ksbysample.webapp.samplestubapp;

import ksbysample.lib.samplelib.StrNumUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class StubWebapiController {

    @PostMapping("/plus")
    public PlusResponse plus(@RequestBody PlusForm plusForm) {
        String result = StrNumUtils.plus(plusForm.getV1(), plusForm.getV2());
        PlusResponse plusResponse = new PlusResponse(result);
        return plusResponse;
    }

}

テストを作成します。今回は Spock で作成します。

f:id:ksby:20190421210227p:plain f:id:ksby:20190421210259p:plain

sample-stubapp/src/test/groovy/ksbysample/webapp/samplestubapp/StubWebapiControllerTest.groovy が新規作成されますので、以下の内容を記述します。

package ksbysample.webapp.samplestubapp

import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.http.MediaType
import org.springframework.test.web.servlet.MockMvc
import spock.lang.Specification
import spock.lang.Unroll

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*

@SpringBootTest
@AutoConfigureMockMvc
class StubWebapiControllerTest extends Specification {

    @Autowired
    private MockMvc mvc

    @Unroll
    def "plus WebAPI のテスト(#v1, #v2 --> #result)"() {
        expect:
        mvc.perform(post("/plus")
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .content("""
                                    {
                                      "v1": ${v1},
                                      "v2": ${v2}
                                    }
                                """))
                .andExpect(status().isOk())
                .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
                .andExpect(jsonPath('$.result').value(result))

        where:
        v1    | v2  || result
        "1"   | "2" || "3"
        "999" | "1" || "1000"
    }

}

テストを実行すると成功しました。画面左側で WARNING が出ているのは IntelliJ IDEA の JUnit の Run/Debug Configuration に JDK 11 のオプションを 設定していないためです。

f:id:ksby:20190421221830p:plain

sample-stubapp/src/test/java/ksbysample/webapp/samplestubapp/SampleStubappApplicationTests.java は不要なので削除します。

sample-webapp の SampleController クラスを本実装する

sample-webapp/src/main/java/ksbysample/webapp/samplewebapp/SampleWebappApplication.java を以下のように変更します。

package ksbysample.webapp.samplewebapp;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class SampleWebappApplication {

    private final RestTemplateBuilder restTemplateBuilder;

    public SampleWebappApplication(RestTemplateBuilder restTemplateBuilder) {
        this.restTemplateBuilder = restTemplateBuilder;
    }

    public static void main(String[] args) {
        SpringApplication.run(SampleWebappApplication.class, args);
    }

    @Bean
    public RestTemplate restTemplate() {
        return this.restTemplateBuilder
                .rootUri("http://localhost:9080")
                .build();
    }

}
  • private final RestTemplateBuilder restTemplateBuilder; とコンストラクタインジェクションの処理を追加します。
  • @Bean public RestTemplate restTemplate() { ... } を追加します。

sample-stubapp/src/main/java/ksbysample/webapp/samplestubapp の下の PlusForm、PlusResponse クラスを sample-webapp/src/main/java/ksbysample/webapp/samplewebapp の下にコピーします。

sample-webapp/src/main/java/ksbysample.webapp.samplewebapp.SampleController.java を以下の内容に変更します。

package ksbysample.webapp.samplewebapp;

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;

@Controller
@RequestMapping("/sample")
public class SampleController {

    private final RestTemplate restTemplate;

    public SampleController(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @RequestMapping
    @ResponseBody
    public String index() {
        PlusForm plusForm = new PlusForm();
        plusForm.setV1("1");
        plusForm.setV2("2");

        HttpHeaders httpHeaders = new HttpHeaders();
        HttpEntity<PlusForm> request = new HttpEntity<>(plusForm, httpHeaders);

        ResponseEntity<PlusResponse> response =
                restTemplate.postForEntity("/plus", request, PlusResponse.class);

        return response.getBody().getResult();
    }

}

テストを作成します。こちらも Spock で作成します。

f:id:ksby:20190421233800p:plain f:id:ksby:20190421233830p:plain

sample-webapp/src/test/groovy/ksbysample/webapp/samplewebapp/SampleControllerTest.groovy が新規作成されますので、以下の内容を記述します。

package ksbysample.webapp.samplewebapp

import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.http.HttpMethod
import org.springframework.http.MediaType
import org.springframework.test.annotation.DirtiesContext
import org.springframework.test.web.client.MockRestServiceServer
import org.springframework.test.web.servlet.MockMvc
import org.springframework.web.client.RestTemplate
import spock.lang.Specification

import static org.springframework.test.web.client.match.MockRestRequestMatchers.method
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status

@SpringBootTest
@AutoConfigureMockMvc
@DirtiesContext
class SampleControllerTest extends Specification {

    @Autowired
    private MockMvc mvc

    @Autowired
    RestTemplate restTemplate

    def "/sample にアクセスすると 3 と表示される"() {
        setup:
        MockRestServiceServer mockServer = MockRestServiceServer.bindTo(restTemplate).build()
        mockServer.expect(requestTo("http://localhost:9080/plus"))
                .andExpect(method(HttpMethod.POST))
                .andRespond(withSuccess('{"result": "3"}', MediaType.APPLICATION_JSON_UTF8))

        expect:
        mvc.perform(get("/sample"))
                .andExpect(status().isOk())
                .andExpect(content().string("3"))
    }

}

テストを実行すると成功しました。

f:id:ksby:20190422000502p:plain

sample-webapp/src/test/java/ksbysample/webapp/samplewebapp/SampleWebappApplicationTests.java は不要なので削除します。

clean タスク実行 → Rebuild Project 実行 → build タスク実行を行う

全ての実装が完了したので build タスクが正常に終了するか確認します。clean タスク実行 → Rebuild Project 実行 → build タスク実行を行うと、BUILD SUCCESSFUL のメッセージが出力されました。

f:id:ksby:20190422001946p:plain f:id:ksby:20190422002051p:plain

Run Dashboard から sample-webapp、sample-stubapp を起動して動作確認する

Run Dashboard から sample-webapp、sample-stubapp を起動します。Run Dashboard から起動すると使用されているポート番号が表示されるのが分かりやすくていいですね。

f:id:ksby:20190422002338p:plain f:id:ksby:20190422002450p:plain

ブラウザから http://localhost:8080/sample にアクセスすると画面上に "3" の文字が表示されました。

f:id:ksby:20190422002645p:plain

確認後、sample-webapp、sample-stubapp を停止します。

sample-webapp、sample-stubapp を jar ファイルから起動して動作確認する

今度は生成された jar ファイルから起動して確認してみます。コマンドプロンプトから jar ファイルが生成されている build/libs ディレクトリに移動した後、java -jar sample-webapp-1.0.0-RELEASE.jarjava -jar sample-stubapp-1.0.0-RELEASE.jar コマンドを実行します。

f:id:ksby:20190422003050p:plain

ブラウザから http://localhost:8080/sample にアクセスすると画面上に "3" の文字が表示されました。

f:id:ksby:20190422003131p:plain

確認後、sample-webapp、sample-stubapp を停止します。

まとめ

  • サブプロジェクトに Spring Boot ベースの Web アプリケーションを2つ以上作成する場合、共通の設定はプロジェクトのルートディレクトリの build.gradle にまとめられます。
  • Spring Boot ベースのサブプロジェクトと Spring Boot ベースではないサブプロジェクトが混在していて、Spring Boot ベースのサブプロジェクトの設定だけを プロジェクトのルートディレクトリの build.gradle にまとめる場合には configure(subprojects.findAll { it.name ==~ /^(sample-webapp|sample-stubapp)$/ }) { ... } のように記述して設定を適用するサブプロジェクトを指定できます。
  • IntelliJ IDEA の Run Dashboard を表示させる方法がよく分かっていなかったのですが、Run/Debug Configurations で Spring Boot の下に2つ以上設定を追加すれば自動で現れることが分かりました。
  • 簡単なサンプルを書いていたつもりでしたが、テストまで書くと意外に辛いですね。。。 書き方が分からなくて調べながらやっていて結構時間がかかりました。

履歴

2019/04/22
初版発行。

Gradle で Multi-project を作成する ( その4 )( lib+webappx2編、Multi-project の設定ファイルと Spring Boot ベースの Web アプリケーション(メイン)のプロジェクトを作成する )

概要

記事一覧はこちらです。

Gradle で Multi-project を作成する ( その3 )( lib+cmdapp編、Spring Boot ベースのコマンドラインアプリケーションのプロジェクトを作成する ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • Gradle で Spring を使用しないライブラリ+Spring Boot ベースの Web アプリケーション x 2(メインとスタブ)の Multi-project を作成します。
    • 2回に分けて書きます。
    • Spring を使用しないライブラリは lib+cmdapp 編で作成した sample-lib プロジェクトをそのままコピーして利用します。
    • Spring Boot ベースの Web アプリケーション x 2(メインとスタブ)は新規に作成します。

参照したサイト・書籍

目次

  1. 方針
  2. gradle-multiprj-lib-webapp2 ディレクトリを作成する
  3. gradle-multiprj-lib-cmdapp プロジェクトからファイルをコピーする
  4. IntelliJ IDEA で gradle-multiprj-lib-webapp2 プロジェクトをオープンする
  5. clean タスク実行 → Rebuild Project 実行 → build タスク実行を行う
  6. Spring Boot ベースの Web アプリケーション(メイン)のプロジェクトを作成する
    1. IntelliJ IDEA で sample-webapp プロジェクトを作成する
    2. sample-webapp プロジェクトから不要なファイルを削除する
    3. settings.gradle に sample-webapp プロジェクトの include 文を追加する
    4. gradle-multiprj-lib-webapp2 プロジェクトの build.gradle にサブプロジェクトの Web アプリケーション共通の設定を追加し、sample-webapp プロジェクトの build.gradle を削除する
    5. SampleController クラスを新規作成して仮実装する
  7. 続く。。。

手順

方針

gradle-multiprj-lib-webapp2
├ sample-lib    <-- Spring を使用しないライブラリの Project
├ sample-stubapp    <-- Spring Boot ベースの Web アプリケーション(スタブ)の Project
└ sample-webapp    <-- Spring Boot ベースの Web アプリケーション(メイン)の Project
  • Spring Boot ベースの Web アプリケーション x 2(メインとスタブ)の Project では Profile は作成しません。
  • テスティングフレームワークは全ての Project で JUnit 5 と Spock を使用できるようにします。
  • checkstyle, spotbugs, pmd, error-prone は今回は導入しません。
  • Spring Boot ベースの Web アプリケーション(メイン)では 8080番ポートを、Spring Boot ベースの Web アプリケーション(スタブ)では 9080番ポートを使用します。
  • Web アプリケーションが2つあるので、
    • build.gradle の共通の設定は各サブプロジェクトの build.gradle ではなく gradle-multiprj-lib-webapp2 の build.gradle に記述します。
    • IntelliJ IDEA の Run Dashboard から Spring Boot ベースの Web アプリケーション x 2(メインとスタブ)を起動できるようにします。

gradle-multiprj-lib-webapp2 ディレクトリを作成する

ksby/ksbysample-boot-miscellaneous の repository を checkout している D:\project-springboot\ksbysample-boot-miscellaneous の下に gradle-multiprj-lib-webapp2 ディレクトリを作成します。

f:id:ksby:20190421091351p:plain

gradle-multiprj-lib-cmdapp プロジェクトからファイルをコピーする

D:\project-springboot\ksbysample-boot-miscellaneous\gradle-multiprj-lib-cmdapp\ から以下のファイルをコピーします。

settings.gradle は以下の内容に変更します。

rootProject.name = 'gradle-multiprj-lib-webapp2'
include 'sample-lib'

コピー後、コマンドプロンプトから gradlew wrapper コマンドを実行します。

f:id:ksby:20190421092716p:plain

D:\project-springboot\ksbysample-boot-miscellaneous\gradle-multiprj-lib-webapp2\ の下には以下のディレクトリ・ファイルがある状態になります。

f:id:ksby:20190421092840p:plain

IntelliJ IDEA で gradle-multiprj-lib-webapp2 プロジェクトをオープンする

gradle-multiprj-lib-webapp2 プロジェクトをオープンします。

f:id:ksby:20190421093232p:plain

オープン後 Project Tool Window は以下のようになり、

f:id:ksby:20190421093449p:plain

Gradle Tool Window は以下のようになります。

f:id:ksby:20190421094634p:plain

gradle-multiprj-lib-cmdapp プロジェクトの時は gradle-multiprj-lib-cmdapp(root) と表示されていたのですが、今回は Tasks と表示されていますね。。。 Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新しても変わりませんでした。

gradle-multiprj-lib-cmdapp プロジェクトをオープンしてみるとこちらも Tasks に変わっていました。どうも IntelliJ IDEA を 2019.1 にバージョンアップしたのが原因のようです。

f:id:ksby:20190421095118p:plain

※Project SDK は default の設定で JDK 11 を使うように設定済なので、今回は変更の手順は書きません。

clean タスク実行 → Rebuild Project 実行 → build タスク実行を行う

ここまでで build タスクが正常に終了するか確認します。clean タスク実行 → Rebuild Project 実行 → build タスク実行を行うと、BUILD SUCCESSFUL のメッセージが出力されました。

f:id:ksby:20190421095554p:plain

sample-lib/build/libs の下に sample-lib-1.0.0-RELEASE.jar も生成されており、問題ないようです。

f:id:ksby:20190421100521p:plain

Spring Boot ベースの Web アプリケーション(メイン)のプロジェクトを作成する

IntelliJ IDEA で sample-webapp プロジェクトを作成する

IntelliJ IDEA から Spring Initializr を利用して Spring Boot ベースの Web アプリケーションのプロジェクトを作成します。

f:id:ksby:20190421105255p:plain f:id:ksby:20190421154449p:plain f:id:ksby:20190421105540p:plain f:id:ksby:20190421105611p:plain ※DevTools と Web の2つをチェックします。

f:id:ksby:20190421105709p:plain f:id:ksby:20190421105820p:plain

作成後 IntelliJ IDEA のウィンドウが開きますが、何もせずに閉じます。

sample-webapp プロジェクトから不要なファイルを削除する

D:\project-springboot\ksbysample-boot-miscellaneous\gradle-multiprj-lib-webapp2\sample-webapp\ の下には以下のディレクトリ・ファイルがありますが、

f:id:ksby:20190421111036p:plain

src ディレクトリと build.gradle 以外を削除します。削除すると以下の状態になります。

f:id:ksby:20190421111404p:plain

settings.gradle に sample-webapp プロジェクトの include 文を追加する

D:\project-springboot\ksbysample-boot-miscellaneous\gradle-multiprj-lib-webapp2 の下の settings.gradle に include 'sample-webapp' を追加します。

rootProject.name = 'gradle-multiprj-lib-webapp2'
include 'sample-lib'
include 'sample-webapp'

追加後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新すると sample-webappIntelliJ IDEA 209.1 から左側に : が付かなくなったようです)が追加されます。

f:id:ksby:20190421150647p:plain

また sample-webapp 起動用の Run/Debug Configuration も自動で追加されます。

f:id:ksby:20190421162742p:plain

gradle-multiprj-lib-webapp2 プロジェクトの build.gradle にサブプロジェクトの Web アプリケーション共通の設定を追加し、sample-webapp プロジェクトの build.gradle を削除する

gradle-multiprj-lib-webapp2 プロジェクトの build.gradle を以下のように変更します。今回は Spring Boot ベースの Web アプリケーションを2つ作成するので、共通の設定は各サブプロジェクトの build.gradle に記述するのではなく gradle-multiprj-lib-webapp2 の build.gradle に記述するようにします。

buildscript {
    repositories {
        mavenCentral()
        maven { url "https://plugins.gradle.org/m2/" }
        maven { url "https://repo.spring.io/release/" }
    }
    dependencies {
        classpath "io.spring.gradle:dependency-management-plugin:1.0.7.RELEASE"
        classpath "org.springframework.boot:spring-boot-gradle-plugin:2.1.4.RELEASE"
    }
}

allprojects {
    repositories {
        mavenCentral()
    }
}

subprojects {
    group "ksby.ksbysample-boot-miscellaneous"
    version "1.0.0-RELEASE"

    apply plugin: "java"
    apply plugin: "groovy"
    apply plugin: "io.spring.dependency-management"

    sourceCompatibility = JavaVersion.VERSION_11
    targetCompatibility = JavaVersion.VERSION_11

    [compileJava, compileTestGroovy, compileTestJava]*.options*.encoding = "UTF-8"
    [compileJava, compileTestGroovy, compileTestJava]*.options*.compilerArgs = ["-Xlint:all,-options,-processing,-path"]

    dependencyManagement {
        imports {
            mavenBom("org.junit:junit-bom:5.4.2")
        }
    }

    dependencies {
        def assertjVersion = "3.12.2"
        def spockVersion = "1.3-groovy-2.5"

        // for Spock
        testImplementation("org.spockframework:spock-core:${spockVersion}")
        testImplementation("org.spockframework:spock-spring:${spockVersion}")

        // for JUnit 5 + AssertJ
        // junit-jupiter で junit-jupiter-api, junit-jupiter-params, junit-jupiter-engine の3つが依存関係に追加される
        testCompile("org.junit.jupiter:junit-jupiter")
        testRuntime("org.junit.platform:junit-platform-launcher")
        testImplementation("org.assertj:assertj-core:${assertjVersion}")
    }

    def jvmArgsDefault = [
            "-ea",
            "-Dfile.encoding=UTF-8",
            "-Dsun.nio.cs.map=x-windows-iso2022jp/ISO-2022-JP"
    ]
    def jvmArgsAddOpens = [
            "--add-opens=java.base/java.io=ALL-UNNAMED",
            "--add-opens=java.base/java.lang=ALL-UNNAMED",
            "--add-opens=java.base/java.lang.invoke=ALL-UNNAMED",
            "--add-opens=java.base/java.lang.ref=ALL-UNNAMED",
            "--add-opens=java.base/java.lang.reflect=ALL-UNNAMED",
            "--add-opens=java.base/java.net=ALL-UNNAMED",
            "--add-opens=java.base/java.security=ALL-UNNAMED",
            "--add-opens=java.base/java.util=ALL-UNNAMED"
    ]
    def printTestCount = { desc, result ->
        if (!desc.parent) { // will match the outermost suite
            println "Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)"
        }
    }

    task testJUnit4AndSpock(type: Test) {
        jvmArgs = jvmArgsDefault +
                jvmArgsAddOpens

        testLogging {
            afterSuite printTestCount
        }
    }
    test.dependsOn testJUnit4AndSpock
    test {
        jvmArgs = jvmArgsDefault +
                jvmArgsAddOpens

        // for JUnit 5
        useJUnitPlatform()

        testLogging {
            afterSuite printTestCount
        }
    }
}

configure(subprojects.findAll { it.name ==~ /^(sample-webapp)$/ }) {
    apply plugin: "org.springframework.boot"

    dependencyManagement {
        imports {
            mavenBom(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)
        }
    }

    dependencies {
        implementation("org.springframework.boot:spring-boot-starter-web")
        runtimeOnly("org.springframework.boot:spring-boot-devtools")
        testImplementation("org.springframework.boot:spring-boot-starter-test")
    }
}
  • buildscript の以下の点を変更します。
    • repositories に maven { url "https://repo.spring.io/release/" } を追加します。
    • dependencies に classpath "org.springframework.boot:spring-boot-gradle-plugin:2.1.4.RELEASE" を追加します。
  • configure(subprojects.findAll { it.name ==~ /^(sample-webapp)$/ }) { ... } の設定を追加します。

sample-webapp プロジェクトの build.gradle に残す設定はないのでファイルを削除します。

変更後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。

clean タスク実行 → Rebuild Project 実行 → build タスク実行を行うと、BUILD SUCCESSFUL のメッセージが出力されました。

f:id:ksby:20190421163648p:plain

Project Tool Window を見ると以下のディレクトリ構成になっています。sample-webapp/build/libs の下に sample-webapp-1.0.0-RELEASE.jar が生成されています。

f:id:ksby:20190421165042p:plain

SampleController クラスを新規作成して仮実装する

Controller クラスが1つもないので /sample にアクセスしたら "sample-webapp" の文字を返す SampleController クラスを作成します。現時点では仮実装で、sample-stubapp を作成したら、sample-stubapp 内に実装する WebAPI を呼び出すように変更します。

sample-webapp/src/main/java/ksbysample/webapp/samplewebapp/SampleController.java を新規作成し、以下の内容を記述します。

package ksbysample.webapp.samplewebapp;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/sample")
public class SampleController {

    @RequestMapping
    @ResponseBody
    public String index() {
        return "sample-webapp";
    }

}

Rebuild Project してエラーが出ないことを確認した後、sample-webapp の Tomcat を起動します。

f:id:ksby:20190421170027p:plain f:id:ksby:20190421170133p:plain

http://localhost:8080/sample にアクセスして "sample-webapp" の文字が出力されることを確認します。

f:id:ksby:20190421170325p:plain

確認後 Tomcat を停止します。

続く。。。

次回は sample-stubapp プロジェクト(こちらが sample-lib の StrNumUtils クラスを呼び出します)を作成した後、sample-webapp の SampleController クラスを本実装して Multi-project を完成させます。

履歴

2019/04/21
初版発行。

AdoptOpenJDK を 11.0.2+9 → 11.0.3+7 へ、IntelliJ IDEA を 2018.3.6 → 2019.1.1 へバージョンアップ

AdoptOpenJDK を 11.0.2+9 → 11.0.3+7 へバージョンアップする

※ksbysample-webapp-lending プロジェクトを開いた状態でバージョンアップしています。

  1. https://adoptopenjdk.net/?variant=openjdk11&jvmVariant=hotspot を見ると 11.0.3+7 がダウンロードできるようになっていましたので、11.0.3+7 へバージョンアップします。

    f:id:ksby:20190420203120p:plain

  2. OpenJDK11U-jdk_x64_windows_hotspot_11.0.3_7.msi をダウンロードして D:\Java\jdk1.8.0_202 へインストールした後、環境変数 JAVA_HOME のパスを D:\Java\jdk-11.0.3+7 へ変更します。

    コマンドプロンプトから java -version を実行し、11.0.3 に変更されていることを確認します。

    f:id:ksby:20190420204951p:plain

  3. IntelliJ IDEA を再起動した後、プロジェクトで使用する JDK を 11.0.3+7 へ変更します。

  4. 開いているプロジェクトを閉じて「Welcome to IntelliJ IDEA」ダイアログを表示します。

  5. ダイアログ下部の「Configure」-「Project Defaults」-「Project Structure」を選択します。

    f:id:ksby:20190420205826p:plain

  6. 「Default Project Structure」ダイアログが表示されます。画面左側で「Project Settings」-「Project」を選択後、画面右側の「Project SDK」の「New...」ボタンをクリックし、表示されるメニューから「JDK」を選択します。

    f:id:ksby:20190420210014p:plain

  7. 「Select Home Directory for JDK」ダイアログが表示されます。D:\Java\jdk-11.0.3+7 を選択した後、「OK」ボタンをクリックします。

    f:id:ksby:20190420210123p:plain

  8. 「Default Project Structure」ダイアログに戻るので、今度は「Project SDK」の「Edit」ボタンをクリックします。

    f:id:ksby:20190420210241p:plain

  9. 画面左側で「Platform Settings」-「SDKs」が選択された状態になるので、画面右上の入力フィールドで "11" → "11.0.3+7" へ変更します。

    f:id:ksby:20190420210435p:plain

  10. 次に中央のリストから「11.0.2+9」を選択した後、リストの上の「-」ボタンをクリックして削除します。

    f:id:ksby:20190420210645p:plain

  11. 「OK」ボタンをクリックして「Default Project Structure」ダイアログを閉じます。

  12. 「Welcome to IntelliJ IDEA」ダイアログに戻ったら、ksbysample-webapp-lending プロジェクトを開きます。

  13. IntelliJ IDEA のメイン画面が開いたら、メニューから「File」-「Project Structure...」を選択します。

  14. 「Project Structure」ダイアログが表示されます。以下の画像の状態になっているので、

    f:id:ksby:20190420210927p:plain

    「Project SDK」を選択し直します。「Project SDK」を「11.0.3+7」に変更すると「Project language level」も自動で「SDK default (11 - Local variable syntax for lambda pa」が選択されました。

    f:id:ksby:20190420211210p:plain

  15. 「OK」ボタンをクリックして「Project Structure」ダイアログを閉じます。

  16. メイン画面に戻ると画面右下に「Indexing...」の表示が出るので、終了するまで待ちます。

    f:id:ksby:20190420211312p:plain

  17. Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。

  18. clean タスク実行 → Rebuild Project 実行 → build タスクを実行して、"BUILD SUCCESSFUL" のメッセージが出力されることを確認します。

    f:id:ksby:20190420212245p:plain

  19. Project Tool Window で src/test/groovy/ksbysample、src/test/java/ksbysample でコンテキストメニューを表示して「Run 'Tests in 'ksbysample'' with Coverage」を選択し、テストが全て成功することを確認します。

    f:id:ksby:20190420213038p:plain f:id:ksby:20190420213501p:plain

  20. 特に問題は発生しませんでした。11.0.3+7 で開発を進めます。

IntelliJ IDEA を 2018.3.6 → 2019.1.1 へバージョンアップする

IntelliJ IDEA の 2019.1.1 がリリースされているのでバージョンアップします。

※ksbysample-webapp-lending プロジェクトを開いた状態でバージョンアップしています。

  1. IntelliJ IDEA のメインメニューから「Help」-「Check for Updates...」を選択します。

  2. IDE and Plugin Updates」ダイアログが表示されます。左下に「Update and Restart」ボタンが表示されていますので、「Update and Restart」ボタンをクリックします。

    f:id:ksby:20190420223100p:plain

  3. Plugin の update も表示されました。このまま「Update and Restart」ボタンをクリックします。

    f:id:ksby:20190420223214p:plain

  4. Patch がダウンロードされて IntelliJ IDEA が再起動します。

  5. メジャーバージョンアップなので起動時に「Import IntelliJ IDEA Settings From...」ダイアログが表示されます。「Previous version」を選択した状態で「OK」ボタンをクリックします。

    f:id:ksby:20190420224212p:plain

  6. IntelliJ IDEA が起動すると画面下部に「Indexing…」のメッセージが表示されますので、終了するまで待機します。

    f:id:ksby:20190420224826p:plain

  7. IntelliJ IDEA のメインメニューから「Help」-「About」を選択し、2019.1.1 へバージョンアップされていることを確認します。

  8. Gradle Tool Window を見ると今回のバージョンからまた何も表示されなくなっていました。

    f:id:ksby:20190420225049p:plain

    左上にある「Refresh all Gradle projects」ボタンをクリックして更新すると、いつものツリーが表示されました。

    f:id:ksby:20190420225209p:plain

  9. clean タスク実行 → Rebuild Project 実行 → build タスクを実行して、"BUILD SUCCESSFUL" のメッセージが出力されることを確認します。

    f:id:ksby:20190420231747p:plain

  10. Project Tool Window で src/test/groovy/ksbysample、src/test/java/ksbysample でコンテキストメニューを表示して「Run 'Tests in 'ksbysample'' with Coverage」を選択し、テストが全て成功することを確認します。

    f:id:ksby:20190420232213p:plain f:id:ksby:20190420232631p:plain

  11. 最後に C:\Users\root.IntelliJIdea2018.3 を削除します。

Gradle で Multi-project を作成する ( その3 )( lib+cmdapp編、Spring Boot ベースのコマンドラインアプリケーションのプロジェクトを作成する )

概要

記事一覧はこちらです。

Gradle で Multi-project を作成する ( その2 )( lib+cmdapp編、Multi-project の設定ファイルと Spring を使用しないライブラリのプロジェクトを作成する ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • Gradle で Spring を使用しないライブラリ+Spring Boot ベースのコマンドラインアプリケーションの Multi-project を作成します。
    • 今回は Spring Boot ベースのコマンドラインアプリケーションのプロジェクトを作成して Multi-project を完成させます。

参照したサイト・書籍

目次

  1. Spring Boot ベースのコマンドラインアプリケーションのプロジェクトを作成する
    1. IntelliJ IDEA で sample-cmdapp プロジェクトを作成する
    2. .gitignore に設定を追加する
    3. sample-cmdapp プロジェクトから不要なファイルを削除する
    4. settings.gradle に sample-cmdapp プロジェクトの include 文を追加する
    5. sample-cmdapp プロジェクトの build.gradle から不要な記述を削除し、sample-lib プロジェクトへの依存関係を追加する
    6. SampleCmdappApplication クラスに CommandLineRunner インターフェースを実装する
  2. clean タスク実行 → Rebuild Project 実行 → build タスク実行を行う
  3. java -jar sample-cmdapp-1.0.0-RELEASE.jar コマンドを実行してみる
  4. まとめ

手順

Spring Boot ベースのコマンドラインアプリケーションのプロジェクトを作成する

IntelliJ IDEA で sample-cmdapp プロジェクトを作成する

IntelliJ IDEA から Spring Initializr を利用して Spring Boot ベースのコマンドラインアプリケーションのプロジェクトを作成します。

f:id:ksby:20190420084840p:plain f:id:ksby:20190420085057p:plain f:id:ksby:20190420085206p:plain ※シンプルなコマンドアプリケーションなので何もチェックしません。

f:id:ksby:20190420085319p:plain

作成後 IntelliJ IDEA のウィンドウが開きますが、何もせずに閉じます。

.gitignore に設定を追加する

sample-cmdapp プロジェクトの下に作成された .gitignore から ### STS ###### IntelliJ IDEA ###### NetBeans ###### VS Code ### の設定をコピーして、ルートディレクトリの .gitignore に追加します。

# Ignore Gradle project-specific cache directory
.gradle

# Ignore Gradle build output directory
build

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
/out/

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/

### VS Code ###
.vscode/

sample-cmdapp プロジェクトから不要なファイルを削除する

D:\project-springboot\ksbysample-boot-miscellaneous\gradle-multiprj-lib-cmdapp\sample-cmdapp\ の下には以下のディレクトリ・ファイルがありますが、

f:id:ksby:20190420085717p:plain

src ディレクトリと build.gradle 以外は不要なので削除します。削除すると以下の状態になります。

f:id:ksby:20190420090738p:plain

settings.gradle に sample-cmdapp プロジェクトの include 文を追加する

D:\project-springboot\ksbysample-boot-miscellaneous\gradle-multiprj-lib-cmdapp の下の settings.gradle に include 'sample-cmdapp' を追加します。

rootProject.name = 'gradle-multiprj-lib-cmdapp'
include 'sample-lib'
include 'sample-cmdapp'

追加後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新すると :sample-cmdapp が追加されます。

f:id:ksby:20190420091403p:plain

sample-cmdapp プロジェクトの build.gradle から不要な記述を削除し、sample-lib プロジェクトへの依存関係を追加する

sample-cmdapp プロジェクトの build.gradle を以下の内容に変更します。

plugins {
    id "org.springframework.boot" version "2.1.4.RELEASE"
}

dependencyManagement {
    imports {
        mavenBom(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)
    }
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter")
    testImplementation("org.springframework.boot:spring-boot-starter-test")

    implementation project(":sample-lib")
}

sample-cmdapp の設定はプロジェクトのルートディレクトリにある build.gradle に project(':sample-cmdapp') { ... } で記述することも可能ですが、その場合 plugins { ... } が使えなくなるので sample-cmdapp の下に build.gradle を残してこの中に設定を記述することにします。

変更後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。

SampleCmdappApplication クラスに CommandLineRunner インターフェースを実装する

sample-cmdapp/src/main/java/ksbysample/cmdapp/samplecmdapp/SampleCmdappApplication.java を以下のように変更します。

package ksbysample.cmdapp.samplecmdapp;

import ksbysample.lib.samplelib.StrNumUtils;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SampleCmdappApplication implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication.run(SampleCmdappApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        System.out.println("★★★ " + StrNumUtils.plus("1", "2"));
    }

}

クラスに implements CommandLineRunner を追加し run メソッドを実装します。run メソッド内で sample-lib プロジェクトの StrNumUtils クラスを呼び出すようにします。

次にテストクラスを作成します。Spring Initializr でプロジェクトを作成したので sample-cmdapp/src/test/java/ksbysample/cmdapp/samplecmdapp/SampleCmdappApplicationTests.java が作成されていますが、このテストはファイル毎削除して Spock で作り直します。

f:id:ksby:20190420093746p:plain f:id:ksby:20190420093816p:plain

cmdapp/src/test/groovy/ksbysample/cmdapp/samplecmdapp/SampleCmdappApplicationTest.groovy が新規作成されますので、以下の内容を記述します。

package ksbysample.cmdapp.samplecmdapp

import spock.lang.Specification

class SampleCmdappApplicationTest extends Specification {

    def "sample-cmdapp を実行すると'★★★ 3'が出力される"() {
        setup:
        def buf = new ByteArrayOutputStream(1024)
        System.out = new PrintStream(buf)

        when:
        SampleCmdappApplication.main()

        then:
        buf.toString().contains("★★★ 3")
    }

}

ここまでで以下のディレクトリ構成になります。

f:id:ksby:20190420101420p:plain

clean タスク実行 → Rebuild Project 実行 → build タスク実行を行う

clean タスク実行 → Rebuild Project 実行 → build タスク実行を行うと、BUILD SUCCESSFUL のメッセージが出力されました。

f:id:ksby:20190420094611p:plain

各プロジェクトの build/libs ディレクトリの下に sample-cmdapp-1.0.0-RELEASE.jar、sample-lib-1.0.0-RELEASE.jar が作成されています。

f:id:ksby:20190420101620p:plain

sample-cmdapp-1.0.0-RELEASE.jar を zip ソフトで開いてみると BOOT-INF/lib の下に sample-lib-1.0.0-RELEASE.jar が入っていることも確認できます。

f:id:ksby:20190420101947p:plain

java -jar sample-cmdapp-1.0.0-RELEASE.jar コマンドを実行してみる

Multi-project で作成した sample-cmdapp-1.0.0-RELEASE.jar が問題なく動作することをコマンドラインから確認してみます。

コマンドラインから java -jar sample-cmdapp-1.0.0-RELEASE.jar コマンドを実行すると "★★★ 3" が出力されることが確認できました。

f:id:ksby:20190420102448p:plain

まとめ

  • Multi-project ではルートディレクトリの build.gradle の subprojects { ... } に共通の設定を記述する。plugin の設定だけ plugins { ... } が使えないので apply plugin: "..." で記述すること。
  • Spring を使用しないライブラリのサブプロジェクトを作成したい時はサブプロジェクトのディレクトリを作成した後、settings.gradle に include '<サブプロジェクトのディレクトリ名>' を書いてから IntelliJ IDEA の Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新すればよい(おそらくコマンドだと gradle wrapper だと思われる)。
  • Spring Boot ベースのコマンドラインアプリケーションのサブプロジェクトを作成したい時は Spring Initializr でサブプロジェクトを作成してから src, build.gradle 以外を削除し、settings.gradle に include '<サブプロジェクトのディレクトリ名>' を書いてから IntelliJ IDEA の Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新すればよい。
  • サブプロジェクトの build.gradle の設定はサブプロジェクトのディレクトリの下に build.gradle を置いてその中に記述するか、ルートディレクトリの build.gradle に project(':<サブプロジェクトのディレクトリ名>') { ... } の形式で記述する。

Multi-project を初めて作ってみましたが、Gradle Guides の Creating Multi-project Builds に基本は書かれているので、これを読めば何とか作れるものですね。

履歴

2019/04/20
初版発行。

Gradle で Multi-project を作成する ( その2 )( lib+cmdapp編、Multi-project の設定ファイルと Spring を使用しないライブラリのプロジェクトを作成する )

概要

記事一覧はこちらです。

Gradle で Multi-project を作成する ( その1 )( 概要 ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • Gradle で Spring を使用しないライブラリ+Spring Boot ベースのコマンドラインアプリケーションの Multi-project を作成します。
    • 2回に分けて書きます。
    • 今回は Multi-project のための各種設定ファイルとSpring を使用しないライブラリのプロジェクトを作成します。

参照したサイト・書籍

  1. Gradle Guides - Creating Multi-project Builds
    https://guides.gradle.org/creating-multi-project-builds/

  2. The Gradle Wrapper
    https://docs.gradle.org/5.0/userguide/gradle_wrapper.html#sec:wrapper_generation

  3. Authoring Multi-Project Builds
    https://docs.gradle.org/current/userguide/multi_project_builds.html

目次

  1. 方針
  2. gradle-multiprj-lib-cmdapp ディレクトリを作成する
  3. Spring Initializr で作成したプロジェクトから Gradle Wrapper のファイルをコピーする
  4. Gradle を最新バージョンにする
  5. gradlew init を実行する
  6. build.gradle に subproject 共通の設定を追加する
  7. Spring を使用しないライブラリのプロジェクトを作成する
    1. sample-lib ディレクトリを作成する
    2. settings.gradle に sample-lib プロジェクトの include 文を追加する
  8. IntelliJ IDEA で gradle-multiprj-lib-cmdapp プロジェクトをオープンする
  9. Project SDK を JDK 11 に設定する
  10. StrNumUtils クラスを追加する
  11. clean タスク実行 → Rebuild Project 実行 → build タスク実行を行う
  12. 続く。。。

手順

方針

gradle-multiprj-lib-cmdapp
├ sample-cmdapp    <-- Spring Boot ベースのコマンドラインアプリケーションの Project
└ sample-lib    <-- Spring を使用しないライブラリの Project
  • Spring Boot ベースのコマンドラインアプリケーションの Project では Profile は作成しません。
  • テスティングフレームワークは全ての Project で JUnit 5 と Spock を使用できるようにします。
  • checkstyle, spotbugs, pmd, error-prone は今回は導入しません。

gradle-multiprj-lib-cmdapp ディレクトリを作成する

ksby/ksbysample-boot-miscellaneous の repository を checkout している D:\project-springboot\ksbysample-boot-miscellaneous の下に gradle-multiprj-lib-cmdapp ディレクトリを作成します。

f:id:ksby:20190418224918p:plain

Spring Initializr で作成したプロジェクトから Gradle Wrapper のファイルをコピーする

IntelliJ IDEA で Spring Initializr の新規 Gradle プロジェクトを作成します。

f:id:ksby:20190418225523p:plain

ここから以下のディレクトリ・ファイルを D:\project-springboot\ksbysample-boot-miscellaneous\gradle-multiprj-lib-cmdapp の下にコピーします。

f:id:ksby:20190418225827p:plain

Gradle を最新バージョンにする

コピーした gradle/wrapper/gradle-wrapper.properties を見ると Gradle のバージョンは 5.2.1 だったのですが、https://gradle.org/releases/ を見ると Gradle の最新バージョンは 5.4 なので 5.4 にバージョンアップします。

コマンドプロンプトから gradlew wrapper --gradle-version=5.4gradlew --versiongradlew wrapper コマンドを実行します。

f:id:ksby:20190420003041p:plain

gradle/wrapper/gradle-wrapper.properties を見ると 5.4 になっています。

distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

gradlew init を実行する

gradlew init コマンドを実行します。選択肢は 1: basic1: groovy を選択し、Project name は何も入力せずに Enter キーを押します。

f:id:ksby:20190418231310p:plain

gradle-multiprj-lib-cmdapp ディレクトリの下は以下のようになり、

f:id:ksby:20190418231535p:plain

生成された .gitignore、build.gradle、settings.gradle は以下の内容になっています。

■.gitignore

# Ignore Gradle project-specific cache directory
.gradle

# Ignore Gradle build output directory
build

■build.gradle

/*
 * This file was generated by the Gradle 'init' task.
 *
 * This is a general purpose Gradle build.
 * Learn how to create Gradle builds at https://guides.gradle.org/creating-new-gradle-builds/
 */

■settings.gradle

/*
 * This file was generated by the Gradle 'init' task.
 *
 * The settings file is used to specify which projects to include in your build.
 *
 * Detailed information about configuring a multi-project build in Gradle can be found
 * in the user manual at https://docs.gradle.org/5.4/userguide/multi_project_builds.html
 */

rootProject.name = 'gradle-multiprj-lib-cmdapp'

build.gradle に subproject 共通の設定を追加する

build.gradle に subproject 共通の設定を追加します。以下の内容に変更します。

buildscript {
    repositories {
        mavenCentral()
        maven { url "https://plugins.gradle.org/m2/" }
    }
    dependencies {
        classpath "io.spring.gradle:dependency-management-plugin:1.0.7.RELEASE"
    }
}

allprojects {
    repositories {
        mavenCentral()
    }
}

subprojects {
    group "ksby.ksbysample-boot-miscellaneous"
    version "1.0.0-RELEASE"

    apply plugin: "java"
    apply plugin: "groovy"
    apply plugin: "io.spring.dependency-management"

    sourceCompatibility = JavaVersion.VERSION_11
    targetCompatibility = JavaVersion.VERSION_11

    [compileJava, compileTestGroovy, compileTestJava]*.options*.encoding = "UTF-8"
    [compileJava, compileTestGroovy, compileTestJava]*.options*.compilerArgs = ["-Xlint:all,-options,-processing,-path"]

    dependencyManagement {
        imports {
            mavenBom("org.junit:junit-bom:5.4.2")
        }
    }

    dependencies {
        def assertjVersion = "3.12.2"
        def spockVersion = "1.3-groovy-2.5"

        // for Spock
        testImplementation("org.spockframework:spock-core:${spockVersion}")
        testImplementation("org.spockframework:spock-spring:${spockVersion}")

        // for JUnit 5 + AssertJ
        // junit-jupiter で junit-jupiter-api, junit-jupiter-params, junit-jupiter-engine の3つが依存関係に追加される
        testCompile("org.junit.jupiter:junit-jupiter")
        testRuntime("org.junit.platform:junit-platform-launcher")
        testImplementation("org.assertj:assertj-core:${assertjVersion}")
    }

    def jvmArgsDefault = [
            "-ea",
            "-Dfile.encoding=UTF-8",
            "-Dsun.nio.cs.map=x-windows-iso2022jp/ISO-2022-JP"
    ]
    def jvmArgsAddOpens = [
            "--add-opens=java.base/java.io=ALL-UNNAMED",
            "--add-opens=java.base/java.lang=ALL-UNNAMED",
            "--add-opens=java.base/java.lang.invoke=ALL-UNNAMED",
            "--add-opens=java.base/java.lang.ref=ALL-UNNAMED",
            "--add-opens=java.base/java.lang.reflect=ALL-UNNAMED",
            "--add-opens=java.base/java.net=ALL-UNNAMED",
            "--add-opens=java.base/java.security=ALL-UNNAMED",
            "--add-opens=java.base/java.util=ALL-UNNAMED"
    ]
    def printTestCount = { desc, result ->
        if (!desc.parent) { // will match the outermost suite
            println "Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)"
        }
    }

    task testJUnit4AndSpock(type: Test) {
        jvmArgs = jvmArgsDefault +
                jvmArgsAddOpens

        testLogging {
            afterSuite printTestCount
        }
    }
    test.dependsOn testJUnit4AndSpock
    test {
        jvmArgs = jvmArgsDefault +
                jvmArgsAddOpens

        // for JUnit 5
        useJUnitPlatform()

        testLogging {
            afterSuite printTestCount
        }
    }
}
  • subprojects { ... } 内で subproject 共通の Gradle plugin を記述する時に plugins { ... } は使えません。apply plugin: "..." で記述します。

Spring を使用しないライブラリのプロジェクトを作成する

sample-lib ディレクトリを作成する

gradle-multiprj-lib-cmdapp ディレクトリの下に sample-lib ディレクトリを作成します。

settings.gradle に sample-lib プロジェクトの include 文を追加する

D:\project-springboot\ksbysample-boot-miscellaneous\gradle-multiprj-lib-cmdapp の下の settings.gradle に include 'sample-lib' を追加します。

rootProject.name = 'gradle-multiprj-lib-cmdapp'
include 'sample-lib'

IntelliJ IDEA で gradle-multiprj-lib-cmdapp プロジェクトをオープンする

gradle-multiprj-lib-cmdapp プロジェクトを以下の画像の手順でオープンします。

f:id:ksby:20190420073950p:plain f:id:ksby:20190420074054p:plain f:id:ksby:20190420074246p:plain

IntelliJ IDEA のメイン画面が表示されると Project Tool Window には以下のように表示されます。

f:id:ksby:20190420074626p:plain

Gradle Tool Window は以下のように表示されます。

f:id:ksby:20190420074748p:plain

Project SDKJDK 11 に設定する

IntelliJ IDEA のメインメニューから「File」-「Project Structure...」を選択し「Project Structure」ダイアログを表示し「Project SDK」で JDK 11 を、「Project language level」で「SDK default(11 - local variable syntax for lambda parameters)」を選択して「OK」ボタンをクリックします。

f:id:ksby:20190419072755p:plain

StrNumUtils クラスを追加する

sample-lib/src/main/java の下に ksbysample.lib.samplelib パッケージを作成し、その下に StrNumUtils.java を新規作成して以下の内容を記述します。

package ksbysample.lib.samplelib;

public class StrNumUtils {

    public static String plus(String v1, String v2) {
        return String.valueOf(Integer.parseInt(v1) + Integer.parseInt(v2));
    }

}

テストクラスも作成します。今回は JUnit 5 で作成します。

f:id:ksby:20190420075427p:plain f:id:ksby:20190420075505p:plain

src/test/java/ksbysample/lib/samplelib/StrNumUtilsTest.java が新規作成されるので、以下の内容を記述します。

package ksbysample.lib.samplelib;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

class StrNumUtilsTest {

    @Test
    @DisplayName("plusメソッドのテスト")
    void plus() {
        assertThat(StrNumUtils.plus("1", "2")).isEqualTo("3");
    }

}

ここまでで以下のディレクトリ構成になります。

f:id:ksby:20190420080105p:plain

clean タスク実行 → Rebuild Project 実行 → build タスク実行を行う

build タスクが正常に終了するか確認します。clean タスク実行 → Rebuild Project 実行 → build タスク実行を行うと、BUILD SUCCESSFUL のメッセージが出力されました。

f:id:ksby:20190420081113p:plain

sample-lib ディレクトリの下に build, out ディレクトリが作成されており、sample-lib/build/libs の下に sample-lib-1.0.0-RELEASE.jar が出力されていました。

f:id:ksby:20190420081359p:plain

ここまでは問題なさそうです。

続く。。。

次回は Spring Boot ベースのコマンドラインアプリケーションのプロジェクトを作成して Multi-project を完成させます。

履歴

2019/04/20
初版発行。

Gradle で Multi-project を作成する ( その1 )( 概要 )

概要

記事一覧はこちらです。

  • Gradle の Multi-project を作成したことがないので、作成手順を覚えるために作成してみます。
  • 以下のパターンの Multi-project を作成してみる予定です。Spring Boot ベースのアプリケーションを最低1つ+ライブラリのプロジェクト(Spring ベースかは問わない)を最低1つ+何か加えたものという構成です。
    • Spring を使用しないライブラリ+Spring Boot ベースのコマンドラインアプリケーション
    • Spring を使用しないライブラリ+Spring Boot ベースの Web アプリケーション x 2(メインとスタブ)
    • Doma 2 の Entity、Dao を提供するライブラリ+Spring Boot ベースのコマンドラインアプリケーション+Spring Boot ベースの Web アプリケーション
  • 他にやりたいパターンが思い浮かんだら変えるかもしれません。
  • 作成した Multi-project は ksby/ksbysample-boot-miscellaneous の repository にコミットします。

履歴

2019/04/18
初版発行。