KotlinでSpring Boot Webを作成する
概要
Kotlin言語を使って、簡単なSpring Boot Webアプリケーションを作成してみます。
プロジェクト作成
次のように curl コマンドを使って、Spring Bootの初期プロジェクトを作成します。
curl https://start.spring.io/starter.tgz \
-d bootVersion=2.4.11 \
-d dependencies=web \
-d baseDir=spring-boot-hello-world \
-d groupId=com.devkuma \
-d artifactId=spring-boot-hello-world \
-d packageName=com.devkuma.hello \
-d applicationName=HelloApplication \
-d packaging=jar \
-d language=kotlin \
-d javaVersion=11 \
-d type=gradle-project | tar -xzvf -
このコマンドを実行すると、Java 11、Spring Boot 2.4.11のWebプロジェクトが生成されます。
生成されたプロジェクトのファイル構成は次のとおりです。
.
├── HELP.md
├── build.gradle.kts
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle.kts
└── src
├── main
│ ├── kotlin
│ │ └── com
│ │ └── devkuma
│ │ └── hello
│ │ └── HelloApplication.kt
│ └── resources
│ ├── application.properties
│ ├── static
│ └── templates
└── test
└── kotlin
└── com
└── devkuma
└── hello
└── HelloApplicationTests.kt
生成されたプロジェクトの確認
build.gradle.kts
生成されたビルドファイルの拡張子が .kts になっており、Kotlinスクリプトファイルであることが分かります。
(参考までに、Javaで使うGradleのビルドファイルの拡張子は .gradle で、Groovyで記述されます。)
/build.gradle.kts
// ... 省略 ...
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
// ... 省略 ...
ファイル内の依存ライブラリを確認すると、Spring Framework (org.springframework.boot)、Kotlin用Jackson (com.fasterxml.jackson.module)、Kotlinライブラリ (org.jetbrains.kotlin) が追加されていることが分かります。
Application Context
/src/main/kotlin/com/devkuma/hello/controller/HelloController.kt
package com.devkuma.hello
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class HelloApplication
fun main(args: Array<String>) {
runApplication<HelloApplication>(*args)
}
Spring Bootを実行するための @SpringBootApplication アノテーションとmain関数があることを確認できます。
(全体的にはJavaコードと似ています。)
Controller作成
Controllerファイルを作成し、次のように記述します。
/src/main/kotlin/com/devkuma/hello/controller/HelloController.kt
package com.devkuma.hello.controller
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController
@RestController
class HelloController {
@GetMapping("/hello")
fun hello(): String {
return "hello world"
}
}
テストコードを作成して実行します。
/src/test/kotlin/com/devkuma/hello/controller/HelloControllerTests.kt
package com.devkuma.hello.controller
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.ResultActions
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
import org.springframework.test.web.servlet.result.MockMvcResultHandlers.print
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
@WebMvcTest(HelloController::class)
class HelloControllerTests {
@Autowired
lateinit var mockMvc: MockMvc
@Test
@DisplayName("Hello")
fun hello() {
// when
val resultActions: ResultActions = mockMvc.perform(get("/hello"))
.andDo(print())
// then
resultActions
.andExpect(status().is2xxSuccessful)
.andExpect(content().string("hello world"))
.andDo(print())
}
}
実行結果にエラーがないことを確認します。
実際の動作も確認するため、プロジェクトを実行した後、次の curl コマンドで動作を確認します。
% curl localhost:8080/hello
hello world%
Service作成
Serviceファイルを作成し、次のように記述します。
/src/main/kotlin/com/devkuma/hello/service/HelloService.kt
package com.devkuma.hello.service
import org.springframework.stereotype.Service
@Service
class HelloService {
fun getHello(): String {
return "hello service"
}
}
Controllerファイルに、次のように helloService() を追加します。
/src/main/kotlin/com/devkuma/hello/controller/HelloController.kt
package com.devkuma.hello.controller
import com.devkuma.hello.service.HelloService
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController
@RestController
class HelloController(val helloService: HelloService) {
// ... 省略 ...
@GetMapping("/hello-service")
fun helloService(): String {
return helloService.getHello()
}
}
次のようにテストコード helloService() を追加し、実行します。
/src/test/kotlin/com/devkuma/hello/controller/HelloControllerTests.kt
package com.devkuma.hello.controller
import com.devkuma.hello.service.HelloService
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.mockito.BDDMockito.given
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.boot.test.mock.mockito.MockBean
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.ResultActions
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
import org.springframework.test.web.servlet.result.MockMvcResultHandlers.print
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
@WebMvcTest(HelloController::class)
class HelloControllerTests {
@Autowired
lateinit var mockMvc: MockMvc
@MockBean
lateinit var helloService: HelloService
// ... 省略 ...
@Test
@DisplayName("Hello Service")
fun helloService() {
// given
given(helloService.getHello()).willReturn("hello service");
// when
val resultActions: ResultActions = mockMvc.perform(get("/hello-service"))
.andDo(print())
// then
resultActions
.andExpect(status().is2xxSuccessful)
.andExpect(content().string("hello service"))
.andDo(print())
}
}
実際の動作も確認するため、プロジェクトを実行した後、次の curl コマンドで動作を確認します。
% curl localhost:8080/hello-service
hello service%
DTO作成
DTOファイルを作成し、次のように記述します。
/src/main/kotlin/com/devkuma/hello/dto/HelloDto.kt
package com.devkuma.hello.dto
class HelloDto(val greeting: String)
Controllerファイルに、次のように helloDto() を追加します。
/src/main/kotlin/com/devkuma/hello/controller/HelloController.kt
@RestController
class HelloController(val helloService: HelloService) {
// ... 省略 ...
@GetMapping("/hello-dto")
fun helloDto(): HelloDto {
return HelloDto("hello dto")
}
}
次のようにテストコード helloDto() を追加し、実行します。
/src/test/kotlin/com/devkuma/hello/controller/HelloControllerTests.kt
package com.devkuma.hello.controller
import com.devkuma.hello.service.HelloService
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.mockito.BDDMockito.given
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.boot.test.mock.mockito.MockBean
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.ResultActions
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
import org.springframework.test.web.servlet.result.MockMvcResultHandlers.print
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.*
@WebMvcTest(HelloController::class)
class HelloControllerTests {
// ... 省略 ...
@Test
@DisplayName("Hello DTO")
fun helloDto() {
// when
val resultActions: ResultActions = mockMvc.perform(get("/hello-dto"))
.andDo(print())
// then
resultActions
.andExpect(status().is2xxSuccessful)
.andExpect(jsonPath("greeting").value("hello dto"))
.andDo(print())
}
}
実際の動作も確認するため、プロジェクトを実行した後、次の curl コマンドで動作を確認します。
% curl localhost:8080/hello-dto
{"greeting":"hello dto"}%
その他
- この投稿の内容は Baeldung: Spring Boot and Kotlin をもとに書き直したものです。
- 上記のすべてのソースコードは GitHub で確認できます。