Gradle で Multi-project を作成する ( その5 )( lib+webappx2編、Spring Boot ベースの Web アプリケーション(スタブ)のプロジェクトを作成する )
概要
記事一覧はこちらです。
- 今回の手順で確認できるのは以下の内容です。
- Gradle で Spring を使用しないライブラリ+Spring Boot ベースの Web アプリケーション x 2(メインとスタブ)の Multi-project を作成します。
- sample-stubapp プロジェクト(こちらが sample-lib の StrNumUtils クラスを呼び出します)を作成した後、sample-webapp の SampleController クラスを本実装して Multi-project を完成させます。
参照したサイト・書籍
Spring @WebMvcTest with Spock Framework
https://allegro.tech/2018/04/Spring-WebMvcTest-with-Spock.htmlSpring Boot RestTemplate POST JSON Example
https://howtodoinjava.com/spring-boot2/resttemplate-post-json-example/
目次
- Spring Boot ベースの Web アプリケーション(スタブ)のプロジェクトを作成する
- IntelliJ IDEA で sample-stubapp プロジェクトを作成する
- sample-stubapp プロジェクトから不要なファイルを削除する
- sample-stubapp プロジェクトの build.gradle を変更する
- gradle-multiprj-lib-webapp2 プロジェクトの build.gradle を変更する
- settings.gradle に sample-stubapp プロジェクトの include 文を追加する
- application.properties に
server.port=9080
を追加する - StubWebapiController クラスを新規作成する
- sample-webapp の SampleController クラスを本実装する
- clean タスク実行 → Rebuild Project 実行 → build タスク実行を行う
- Run Dashboard から sample-webapp、sample-stubapp を起動して動作確認する
- sample-webapp、sample-stubapp を jar ファイルから起動して動作確認する
- まとめ
手順
Spring Boot ベースの Web アプリケーション(スタブ)のプロジェクトを作成する
IntelliJ IDEA で sample-stubapp プロジェクトを作成する
IntelliJ IDEA から Spring Initializr を利用して Spring Boot ベースの Web アプリケーションのプロジェクトを作成します。
※DevTools と Web の2つをチェックします。
作成後 IntelliJ IDEA のウィンドウが開きますが、何もせずに閉じます。
sample-stubapp プロジェクトから不要なファイルを削除する
D:\project-springboot\ksbysample-boot-miscellaneous\gradle-multiprj-lib-webapp2\sample-stubapp\
の下には以下のディレクトリ・ファイルがありますが、
src ディレクトリと build.gradle 以外を削除します。削除すると以下の状態になります。
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 が追加されます。
また IntelliJ IDEA の画面右下に「Run Dashboard」のダイアログが表示されます。「Show run configurations Run Dashboard」リンクをクリックすると Run Dashboard Tool Window が表示されます。
※ちなみに Run Dashboard Tool Window は Run/Debug Configurations で Spring Boot に2つ以上設定を追加すれば表示させることができます。
clean タスク実行 → Rebuild Project 実行 → build タスク実行を行うと、BUILD SUCCESSFUL のメッセージが出力されました。
Project Tool Window を見ると以下のディレクトリ構成になっています。sample-stubapp/build/libs の下に sample-stubapp-1.0.0-RELEASE.jar が生成されています。
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 で作成します。
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 のオプションを 設定していないためです。
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 で作成します。
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")) } }
テストを実行すると成功しました。
sample-webapp/src/test/java/ksbysample/webapp/samplewebapp/SampleWebappApplicationTests.java は不要なので削除します。
clean タスク実行 → Rebuild Project 実行 → build タスク実行を行う
全ての実装が完了したので build タスクが正常に終了するか確認します。clean タスク実行 → Rebuild Project 実行 → build タスク実行を行うと、BUILD SUCCESSFUL のメッセージが出力されました。
Run Dashboard から sample-webapp、sample-stubapp を起動して動作確認する
Run Dashboard から sample-webapp、sample-stubapp を起動します。Run Dashboard から起動すると使用されているポート番号が表示されるのが分かりやすくていいですね。
ブラウザから http://localhost:8080/sample にアクセスすると画面上に "3" の文字が表示されました。
確認後、sample-webapp、sample-stubapp を停止します。
sample-webapp、sample-stubapp を jar ファイルから起動して動作確認する
今度は生成された jar ファイルから起動して確認してみます。コマンドプロンプトから jar ファイルが生成されている build/libs ディレクトリに移動した後、java -jar sample-webapp-1.0.0-RELEASE.jar
、java -jar sample-stubapp-1.0.0-RELEASE.jar
コマンドを実行します。
ブラウザから http://localhost:8080/sample にアクセスすると画面上に "3" の文字が表示されました。
確認後、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
初版発行。