Kotlin 練功場 - Ktor


根據 2020/8/23-2020/11/15 練功場的筆記所做的自己的學習筆記。
~ 2021/3/23

結論

照著筆記做了一次 Ktor 範例,覺得 Ktor 真的是滿輕便的。
今年的練功坊如果還有 Ktor,希望可以跟著做點什麼。

1.Hello

學到
Hello

參考

  • Ktor練功場#1筆記-就是在說哈囉我的 - YungHsin
    用 community 版
  • [Day 3] Ktor 的 Hello World-Recca
    用 Ultimate 版
  • Day 3:資料管理伺服器 (1) – 使用 Ktor 建立 HTTP Server

圖

程式的進入點:Application.kt

圖

執行:Gradle>Tasks>spplication>run

我的http://0.0.0.0:8080 沒有連上,要用 127.0.0.1

圖

2.Response

學到

  1. Response
  2. html template engine
  3. json response
  4. routing

參考

  • Ktor 練功場筆記(2)-重構、Template、Content Negotiation - Andy Lu
  • Ktor練功場#2筆記-練習寫JSON API - YungHsin
  • [Day 12] 要準備連線資料了!設置 Ktor 的連線資訊
  1. 重構程式
  2. 利用 Template Engine 回傳一個網頁
  3. 利用 Content Negotiation 回傳JSON格式的資料 (JSON API)
  4. 設定環境變數

routing

routing {
    get("/") {
        call.respondText("HELLO WORLD!", contentType = ContentType.Text.Plain)
    }

}

Templates Engines(樣板引擎)

Ktor支援的Templates Engines表,如下:

  • Freemarker
  • HTML DSL
  • Mustache
  • Pebble
  • Thymeleaf
  • Velocity

DSL

    get("/html-dsl") {
        call.respondHtml {
            body {
                h1 { +"HTML" }
                ul {
                    for (n in 1..10) {
                        li { +"$n" }
                    }
                }
            }
        }
    }

Freemarker

    get("/html-freemarker") {
        call.respond(FreeMarkerContent("index.ftl", mapOf("data" to IndexData(listOf(1, 2, 3))), ""))
    }

圖

Content negotiation (內容協商)

使用 Content Negotiation 可以讓資料轉成其它格式,如 Json。
Ktor支援的 Content negotiation 表,如下:

  • Gson
  • Jackson
  • kotlinx.serialization

Refactor

使用快速鍵抽取程式碼 (Extract Function)
(Windows): Ctrl + W
(Windows): Ctrl+Alt+M

圖

config

將機密資料寫在config,再import
設定好用這個 route 測試,變數成功從 config property引入

get("/password") {
    val password = environment.config.property("ktor.database.password").getString()
    call.respondText(password, contentType = ContentType.Text.Plain)
}

3.DB Expose & H2

學到

  1. Expose,H2
  2. DAO
  3. config
  4. H2 console

參考

  • Ktor 練功場筆記(3) — 資料庫串接
  • Ktor練功場#3筆記-使用Exposed資料庫
  • [Day 13] 用 Ktor 連線資料庫!談 Kotlin exposed 框架
  • [Day 15] 遠征 Kotlin × Spring Boot 設定資料庫與匯入初始資料

Exposed

在 Exposed 中,可以使用兩種方式存取資料庫:

  1. 包裝在 DSL (Domain Specific Language — 領域特定語言) 中,具有型別安全的 SQL 指令
    1. 輕量的DAO (Data Access Object — 資料存取物件)

目前支援的資料庫如下:

  • H2
  • MySQL
  • MariaDB
  • Oracle
  • PostgreSQL
  • PostgreSQL using the pgjdbc-ng JDBC driver
  • SQL Server
  • SQLite

我們在 gradle.build 裡面加上 h2database和exposed
旁邊的大象叫你更新

圖

資料庫串接

以 Andy 的筆記做
https://github.com/andyludeveloper/ktor_workshop/blob/master/src/Application.kt

圖

這邊被自動 impor 搞了一下,他幫我 import 到 connect,害我跟這範例卻出錯

import org.jetbrains.exposed.sql.Database.Companion.connect

import 到 Database 這一層就能跟範例一樣用Database.connect
import org.jetbrains.exposed.sql.Database

4.Request


要有Json serialization for HttpClient

implementation "io.ktor:ktor-client-core:$ktor_version"

出現這個錯誤

圖

確定有安裝 ktor client,後來看官方文件發現是要 import request

import io.ktor.client.request.*

完成

get("/") {
    //用泛型
    //val htmlContent = client.get<String>("https://en.wikipedia.org/wiki/Main_Page")
    //call.respondText(htmlContent, contentType = ContentType.Text.Plain)

    //也可以用宣告
    val content: String = client.get("https://en.wikipedia.org/wiki/Main_Page")
    call.respondText(content, contentType = ContentType.Text.Plain)
}

5.Asynchronous

    routing {
        //mock server
        get("/json/jackson1") {
            delay(2000)
            call.respond(mapOf("hello" to "hello1"))
        }
        get("/json/jackson2") {
            delay(2000)
            call.respond(mapOf("hello" to "hello2"))
        }
        get("/json/jackson3") {
            delay(2000)
            call.respond(mapOf("hello" to "hello3"))
        }

        //client
        get("/"){
            val beginTime = System.currentTimeMillis()

            val msg1 = client.get<String>("http://localhost:8080/json/jackson1")
            val msg2 = client.get<String>("http://localhost:8080/json/jackson2")
            val msg3 = client.get<String>("http://localhost:8080/json/jackson3")

            val resultMsg = "${msg1}${msg2}${msg3}"

            val endTime = System.currentTimeMillis()

            call.respondText("${resultMsg}\n costTime(millionseconds):${endTime-beginTime}")
        }
    }

執行要六秒

async

//import
import kotlinx.coroutines.async
import kotlinx.coroutines.delay

//加上 async tag
val msg1 = async {client.get<String>("http://localhost:8080/json/jackson1")}

變快了

await

//val resultMsg = "${msg1}${msg2}${msg3}"
val resultMsg = "${msg1.await()}${msg2.await()}${msg3.await()}"

非同步

6.Deploy

兩種方法自己選

  • Ktor練功場#6筆記-Fat Jar部署
  • 我在 kotlin讀書會的日子(八):Ktor組聚 - Heroku雲端佈署

7.FP & OOP (SOLID, DP)

沒部落格看 QQ

#Kotlin







Related Posts

前端串串 API

前端串串 API

從前端傳資料給後端(GET, POST)、從 PHP 連線到 MySQL 資料庫

從前端傳資料給後端(GET, POST)、從 PHP 連線到 MySQL 資料庫

[ 筆記 ] JavaScript 進階 06 - Closure

[ 筆記 ] JavaScript 進階 06 - Closure




Sponsored



Comments