Spring BootとCortlinを使用したブログWebの作成(4)

11949 ワード

Http APIの作成


セグメントプラグを使用してarticleリストとarticleのコントローラをクエリーする
ユーザー・リスト・クエリーとユーザー・ログイン・クエリーを生成するコントロールsrc/main/kotlin/com/example/demo/HttpControllers.kt
package com.example.demo.blog

import org.springframework.http.HttpStatus
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.server.ResponseStatusException

@RestController
@RequestMapping("/api/articles")
class ArticleController (private val repositoriy: ArticleRepositoriy) {

    @GetMapping("/")
    fun findAll() = repositoriy.findAllByOrderByAddedAtDesc()

    @GetMapping("/{slug}")
    fun findOne(@PathVariable slug : String) =
        repositoriy.findBySlug(slug)
            ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "this article does not exist")
}

@RestController
@RequestMapping("/api/users")
class UserController(private val repositoriy: UserRepository){
    @GetMapping("/")
    fun findAll() = repositoriy.findAll();

    @GetMapping("/{login}")
    fun findOne(@PathVariable login: String) =
        repositoriy.findByLogin(login)
            ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "this user does not exist")
}

試験Http API


テストのために@WebMvcTestとMockkを使用します.MockkはMockitoと似ていますが、Cottinに適しています.build.gradle.kts
dependencies {
	implementation("org.springframework.boot:spring-boot-starter-data-jpa")
	implementation("org.springframework.boot:spring-boot-starter-mustache")
	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")
	developmentOnly("org.springframework.boot:spring-boot-devtools")
	runtimeOnly("com.h2database:h2")
	providedRuntime("org.springframework.boot:spring-boot-starter-tomcat")
	testImplementation("org.springframework.boot:spring-boot-starter-test"){
		exclude(module="junit")
		exclude(module="mockito-core")
	}
	testImplementation("org.junit.jupiter:junit-jupiter-api")
	testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
	implementation("com.ninja-squad:springmockk:3.0.1")
}
既存のmockitoに加えてmockkを追加
src/test/kotlin/com/example/demo/HttpControllersTests.kt
package com.example.demo

import com.example.demo.blog.Article
import com.example.demo.blog.ArticleRepositoriy
import com.example.demo.blog.User
import com.example.demo.blog.UserRepository
import com.ninjasquad.springmockk.MockkBean
import io.mockk.every
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.http.MediaType
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.*

@WebMvcTest
class HttpsControllersTests(@Autowired val mockMvc: MockMvc) {

    @MockkBean
    private lateinit var articleRepositoriy: ArticleRepositoriy

    @MockkBean
    private lateinit var userRepository: UserRepository

    @Test
    fun `List articles`() {
        val user = User("login", "firstName", "lastName")
        val article1 = Article("title1", "headline1", "content1", user)
        val article2 = Article("title2", "headline2", "content2", user)

        every { articleRepositoriy.findAllByOrderByAddedAtDesc() } returns
                listOf(article1, article2)

        mockMvc.perform(get("/api/articles/").accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk)
            .andExpect(content().contentType(MediaType.APPLICATION_JSON))
            .andExpect(jsonPath("\$.[0].author.login").value(user.login))
            .andExpect(jsonPath("\$.[0].slug").value(article1.slug))
            .andExpect(jsonPath("\$.[1].author.login").value(article2.author.login))
            .andExpect(jsonPath("\$.[1].slug").value(article2.slug))
    }

    @Test
    fun `List users`() {
        val user1 = User("login1", "firstName1", "lastName1")
        val user2 = User("login2", "firstName2", "lastName2")

        every { userRepository.findAll() } returns listOf(user1, user2)

        mockMvc.perform(get("/api/users/").accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk)
            .andExpect(content().contentType(MediaType.APPLICATION_JSON))
            .andExpect(jsonPath("\$.[0].login").value(user1.login))
            .andExpect(jsonPath("\$.[1].login").value(user2.login))
    }

}
List articlesのテスト
ArticleRepositoryは各関数を通過します.findAllByOrderByAddDeAtDesc()の戻りリストを指定し、mockMvcを使用して/api/articles/ APIが正常に動作しているかどうかを確認します.

プロパティの設定

  • メニューでIntelliJ IDEA|プラグイン|Spring Bootの検出を有効にする
  • メニューのIntelliJ IDEA|Build、実行、配置|Compiler|Annotation Processors|Enablel注釈処理チェック
  • build.gradle.kts
    
    plugins {
    	...
    	kotlin("kapt") version "1.4.32"
    }
    
    dependencies {
      ...
      kapt("org.springframework.boot:spring-boot-configuration-processor")
    }
    コートリンは@ConstructureBindingと@ConfigurationPropertiesを使用してPropertyを管理することを推奨します
    src/main/kotlin/com/example/demo/BlogProperties.kt
    package com.example.demo
    
    import org.springframework.boot.context.properties.ConfigurationProperties
    import org.springframework.boot.context.properties.ConstructorBinding
    
    @ConstructorBinding
    @ConfigurationProperties("blog")
    data class BlogProperties(var title: String, val banner: Banner) {
        data class Banner(val title: String?=null, val content:String)
    
    }
    BlogApplicationレベルでPropertyを許可する
    src/main/kotlin/com/example/blog/BlogApplication.kt
    package com.example.demo
    
    import org.springframework.boot.autoconfigure.SpringBootApplication
    import org.springframework.boot.context.properties.EnableConfigurationProperties
    import org.springframework.boot.runApplication
    
    @SpringBootApplication
    @EnableConfigurationProperties(BlogProperties::class)
    class DemoApplication
    
    fun main(args: Array<String>) {
    	runApplication<DemoApplication>(*args)
    }
    
    application.propertiesでpropertyを設定します.
    src/main/resources/application.properties
    blog.title=Blog
    blog.banner.title=Warning
    blog.banner.content=The Blog will be down tomorrow
    コントローラでの使用
    src/main/kotlin/com/example/demo/HtmlController.kt
    @Controller
    class HtmlController (private val repository: ArticleRepositoriy,
    		private val properties: BlogProperties) {
    
        @GetMapping("/")
        fun blog(model: Model): String {
            model["title"] = properties.title
            model["banner"] = properties.banner
            model["articles"] = repository.findAllByOrderByAddedAtDesc().map {
                it.render()
            }
            return "blog"
        }
        // ...
    最後にムスタッチに適用されます.
    src/main/kotlin/com/example/demo/HtmlController.kt
    {{> header}}
    
    <h1>{{title}}</h1>
    
    <div class="articles">
        {{#banner.title}}
            <section>
                <header class="banner">
                    <h2 class="banner-title">{{banner.title}}</h2>
                </header>
                <div class="banner-content">
                    {{banner.content}}
                </div>
            </section>
        {{/banner.title}}
    </div>
    
    {{> footer}}
    http://localhost:8080/活動場所を表すの結果を確認できます

    Http APIを作成してテストし、Property設定も行いました.
    これを使ってSpringBootとCortlinでブログサイトを作成して終了です.
    ソースはここです。で確認できます.

    Reference


    https://spring.io/guides/tutorials/spring-boot-kotlin/