🚀 Ktor 簡介
📖 什麼是 Ktor?
Ktor 是用 Kotlin 建立的輕量級非同步 Web 框架。基於協程,可以輕鬆建立快速高效的伺服器!
💡 建立專案
build.gradle.kts
plugins {
kotlin("jvm") version "1.9.0"
id("io.ktor.plugin") version "2.3.5"
}
dependencies {
implementation("io.ktor:ktor-server-core:2.3.5")
implementation("io.ktor:ktor-server-netty:2.3.5")
implementation("ch.qos.logback:logback-classic:1.4.11")
}
🎯 第一個伺服器
Hello World
import io.ktor.server.application.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
fun main() {
embeddedServer(Netty, port = 8080) {
routing {
get("/") {
call.respondText("Hello, Ktor!")
}
}
}.start(wait = true)
}
執行後在瀏覽器中存取 http://localhost:8080!
多個路由
fun main() {
embeddedServer(Netty, port = 8080) {
routing {
get("/") {
call.respondText("홈페이지")
}
get("/hello") {
call.respondText("안녕하세요!")
}
get("/about") {
call.respondText("소개 페이지")
}
}
}.start(wait = true)
}
🎨 路由
路徑參數
fun Application.configureRouting() {
routing {
get("/user/{id}") {
val id = call.parameters["id"]
call.respondText("사용자 ID: $id")
}
get("/product/{category}/{id}") {
val category = call.parameters["category"]
val id = call.parameters["id"]
call.respondText("카테고리: $category, 상품 ID: $id")
}
}
}
fun main() {
embeddedServer(Netty, port = 8080) {
configureRouting()
}.start(wait = true)
}
// 접속: http://localhost:8080/user/123
// 출력: 사용자 ID: 123
查詢參數
routing {
get("/search") {
val query = call.request.queryParameters["q"]
val page = call.request.queryParameters["page"]
call.respondText("검색어: $query, 페이지: $page")
}
}
// 접속: http://localhost:8080/search?q=kotlin&page=1
// 출력: 검색어: kotlin, 페이지: 1
🔧 JSON 回應
設定 ContentNegotiation
plugins {
// build.gradle.kts에 추가
implementation("io.ktor:ktor-server-content-negotiation:2.3.5")
implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.5")
}
JSON 回應
import io.ktor.serialization.kotlinx.json.*
import io.ktor.server.plugins.contentnegotiation.*
import kotlinx.serialization.Serializable
@Serializable
data class User(val id: Int, val name: String, val email: String)
fun Application.module() {
install(ContentNegotiation) {
json()
}
routing {
get("/user/{id}") {
val id = call.parameters["id"]?.toInt() ?: 0
val user = User(id, "홍길동", "hong@example.com")
call.respond(user)
}
get("/users") {
val users = listOf(
User(1, "홍길동", "hong@example.com"),
User(2, "김철수", "kim@example.com")
)
call.respond(users)
}
}
}
🎯 實戰範例
簡單的 API
@Serializable
data class Product(
val id: Int,
val name: String,
val price: Double
)
fun Application.productAPI() {
install(ContentNegotiation) {
json()
}
val products = mutableListOf(
Product(1, "노트북", 1500000.0),
Product(2, "마우스", 30000.0),
Product(3, "키보드", 80000.0)
)
routing {
// 전체 상품 조회
get("/products") {
call.respond(products)
}
// 특정 상품 조회
get("/products/{id}") {
val id = call.parameters["id"]?.toInt()
val product = products.find { it.id == id }
if (product != null) {
call.respond(product)
} else {
call.respondText("상품을 찾을 수 없습니다", status = HttpStatusCode.NotFound)
}
}
}
}
fun main() {
embeddedServer(Netty, port = 8080) {
productAPI()
}.start(wait = true)
}
狀態碼
import io.ktor.http.*
routing {
get("/status/ok") {
call.respondText("정상", status = HttpStatusCode.OK)
}
get("/status/created") {
call.respondText("생성됨", status = HttpStatusCode.Created)
}
get("/status/not-found") {
call.respondText("없음", status = HttpStatusCode.NotFound)
}
get("/status/error") {
call.respondText("서버 오류", status = HttpStatusCode.InternalServerError)
}
}
🔥 中介軟體
日誌記錄
import io.ktor.server.plugins.callloging.*
fun Application.module() {
install(CallLogging)
routing {
get("/") {
call.respondText("Hello!")
}
}
}
// 콘솔에 요청 로그 출력
CORS 設定
import io.ktor.server.plugins.cors.routing.*
fun Application.module() {
install(CORS) {
anyHost() // 모든 호스트 허용 (개발 환경)
allowHeader(HttpHeaders.ContentType)
}
routing {
get("/api/data") {
call.respond(mapOf("message" to "CORS 설정됨"))
}
}
}
🛠️ 應用程式結構
模組化
// routes/UserRoutes.kt
fun Route.userRoutes() {
route("/users") {
get {
call.respond(listOf("User1", "User2"))
}
get("/{id}") {
val id = call.parameters["id"]
call.respondText("User $id")
}
}
}
// routes/ProductRoutes.kt
fun Route.productRoutes() {
route("/products") {
get {
call.respond(listOf("Product1", "Product2"))
}
}
}
// Application.kt
fun Application.module() {
install(ContentNegotiation) {
json()
}
routing {
userRoutes()
productRoutes()
}
}
🤔 常見問題
Q1. Ktor vs. Spring Boot?
A: Ktor 輕量且對協程友好!
// Ktor - 간결하고 가벼움
fun Application.module() {
routing {
get("/hello") {
call.respondText("Hello!")
}
}
}
// Spring Boot - 더 많은 기능과 생태계
@RestController
class HelloController {
@GetMapping("/hello")
fun hello() = "Hello!"
}
Q2. 如何變更連接埠?
A: 在建立伺服器時指定!
// 코드에서
embeddedServer(Netty, port = 3000) {
// ...
}.start(wait = true)
// application.conf 파일
ktor {
deployment {
port = 3000
}
}
Q3. 如何提供靜態檔案?
A: 使用 Static 外掛!
import io.ktor.server.http.content.*
routing {
static("/static") {
resources("static")
}
static("/files") {
files("uploads")
}
}
🎬 結語
使用 Ktor 快速開始伺服器開發!
핵심 정리:
✅ 경량 비동기 프레임워크
✅ 코루틴 기반
✅ 간단한 라우팅
✅ JSON 직렬화 지원
✅ 모듈화 가능
下一步:在 REST API 中建立完整的 API!