Kotlin与Ktor构建Android后端API

发布于:2025-05-13 ⋅ 阅读:(13) ⋅ 点赞:(0)

以下是一个使用 Kotlin 和 Ktor 构建 Android 后端 API 的详细示例,包含常见功能实现:

1. 项目搭建 (build.gradle.kts)

plugins {
    application
    kotlin("jvm") version "1.9.0"
    id("io.ktor.plugin") version "2.3.4"
    id("org.jetbrains.kotlin.plugin.serialization") version "1.9.0"
}

dependencies {
    implementation("io.ktor:ktor-server-core")
    implementation("io.ktor:ktor-server-netty")
    implementation("io.ktor:ktor-server-content-negotiation")
    implementation("io.ktor:ktor-serialization-kotlinx-json")
    implementation("io.ktor:ktor-server-status-pages")
    implementation("io.ktor:ktor-server-auth")
    implementation("io.ktor:ktor-server-auth-jwt")
    
    // 数据库
    implementation("org.jetbrains.exposed:exposed-core:0.41.1")
    implementation("org.jetbrains.exposed:exposed-jdbc:0.41.1")
    implementation("com.h2database:h2:2.1.214")
    
    // 日志
    implementation("ch.qos.logback:logback-classic:1.4.7")
    
    // 测试
    testImplementation("io.ktor:ktor-server-test-host")
}

2. 主入口文件 (Application.kt)

fun main() {
    embeddedServer(Netty, port = 8080, host = "0.0.0.0") {
        install(ContentNegotiation) {
            json()
        }
        install(StatusPages) {
            exception<Throwable> { call, cause ->
                when (cause) {
                    is ApiException -> {
                        call.respond(
                            HttpStatusCode.fromValue(cause.statusCode),
                            ErrorResponse(cause.message ?: "Unknown error")
                        )
                    }
                    else -> {
                        call.respond(
                            HttpStatusCode.InternalServerError,
                            ErrorResponse("Internal server error")
                        )
                    }
                }
            }
        }
        install(Authentication) {
            jwt {
                realm = "My API"
                verifier(JwtConfig.verifier)
                validate { credential ->
                    if (credential.payload.getClaim("userId").asString() != "") {
                        JWTPrincipal(credential.payload)
                    } else {
                        null
                    }
                }
            }
        }
        
        DatabaseFactory.init()
        configureRouting()
    }.start(wait = true)
}

class ApiException(
    val statusCode: Int,
    override val message: String
) : RuntimeException(message)

data class ErrorResponse(val message: String)

3. 路由配置 (Routing.kt)

fun Application.configureRouting() {
    routing {
        // 公共路由
        route("/api") {
            post("/register") {
                // 用户注册逻辑
            }
            
            post("/login") {
                // 用户登录逻辑
            }
            
            // 需要认证的路由
            authenticate {
                route("/users") {
                    get {
                        // 获取所有用户
                    }
                    
                    get("{id}") {
                        // 获取单个用户
                    }
                }
                
                route("/posts") {
                    get {
                        // 获取所有帖子
                    }
                    
                    post {
                        // 创建新帖子
                    }
                    
                    put("{id}") {
                        // 更新帖子
                    }
                }
            }
        }
    }
}

4. 数据库配置 (Database.kt)

object DatabaseFactory {
    fun init() {
        val database = Database.connect(
            url = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1",
            driver = "org.h2.Driver"
        )
        
        transaction {
            SchemaUtils.create(Users, Posts)
        }
    }
}

object Users : Table() {
    val id = uuid("id").primaryKey().autoGenerate()
    val username = varchar("username", 50).uniqueIndex()
    val password = varchar("password", 100)
    val createdAt = datetime("created_at")
}

object Posts : Table() {
    val id = uuid("id").primaryKey().autoGenerate()
    val title = varchar("title", 100)
    val content = text("content")
    val authorId = (uuid("author_id") references Users.id)
    val createdAt = datetime("created_at")
}

5. JWT 配置 (JwtConfig.kt)

object JwtConfig {
    private const val SECRET = "your_secret_key_here"
    private const val ISSUER = "your_issuer"
    private const val AUDIENCE = "your_audience"
    private const val EXPIRATION = 3600L // 1小时
    
    val verifier = JWT
        .require(Algorithm.HMAC256(SECRET))
        .withIssuer(ISSUER)
        .withAudience(AUDIENCE)
        .build()
    
    fun generateToken(userId: UUID): String {
        return JWT.create()
            .withIssuer(ISSUER)
            .withAudience(AUDIENCE)
            .withClaim("userId", userId.toString())
            .withExpiresAt(Date(System.currentTimeMillis() + EXPIRATION * 1000))
            .sign(Algorithm.HMAC256(SECRET))
    }
}

6. 数据模型 (Models.kt)

@Serializable
data class UserRequest(
    val username: String,
    val password: String
)

@Serializable
data class UserResponse(
    val id: String,
    val username: String,
    val createdAt: String
)

@Serializable
data class PostRequest(
    val title: String,
    val content: String
)

@Serializable
data class PostResponse(
    val id: String,
    val title: String,
    val content: String,
    val authorId: String,
    val createdAt: String
)

7. 示例端点实现 (UserRoutes.kt)

fun Route.userRoutes() {
    route("/users") {
        get {
            val users = transaction {
                Users.selectAll().map { row ->
                    UserResponse(
                        id = row[Users.id].toString(),
                        username = row[Users.username],
                        createdAt = row[Users.createdAt].toString()
                    )
                }
            }
            call.respond(users)
        }
        
        get("{id}") {
            val id = call.parameters["id"] ?: throw ApiException(400, "Missing ID")
            val user = transaction {
                Users.select { Users.id eq UUID.fromString(id) }.singleOrNull()
            } ?: throw ApiException(404, "User not found")
            
            call.respond(
                UserResponse(
                    id = user[Users.id].toString(),
                    username = user[Users.username],
                    createdAt = user[Users.createdAt].toString()
                )
            )
        }
    }
}

8. 测试示例 (UserRoutesTest.kt)

class UserRoutesTest {
    @Test
    fun testGetUsers() = testApplication {
        application {
            configureRouting()
        }
        
        client.get("/api/users").apply {
            assertEquals(HttpStatusCode.OK, status)
            val users = Json.decodeFromString<List<UserResponse>>(bodyAsText())
            assertTrue(users.isNotEmpty())
        }
    }
}

关键功能说明:

  1. 认证系统:使用 JWT 进行身份验证
  2. 数据库集成:使用 Exposed ORM 和 H2 数据库
  3. 错误处理:统一异常处理中间件
  4. RESTful API:实现标准 CRUD 操作
  5. 内容协商:支持 JSON 序列化
  6. 路由分层:模块化路由配置

运行与测试:

  1. 启动应用:./gradlew run
  2. 访问 API:
    • GET http://localhost:8080/api/users
    • POST http://localhost:8080/api/register
  3. 使用 Postman 或 curl 进行测试

扩展建议:

  1. 添加 Swagger/OpenAPI 文档
  2. 实现文件上传功能
  3. 添加 Redis 缓存层
  4. 集成邮件服务
  5. 实现分页和过滤功能
  6. 添加速率限制
  7. 配置 CORS 支持

注意:实际部署时需要:

  1. 使用生产级数据库(如 PostgreSQL)
  2. 配置 HTTPS
  3. 设置环境变量管理敏感信息
  4. 添加监控和日志系统
  5. 考虑容器化部署(Docker)

网站公告

今日签到

点亮在社区的每一天
去签到