1.http-api
添加Routing、Content Negotiation和kotlinx.serialization插件
Customer.kt
@Serializable //序列化注释响应JSON
data class Customer(val id: String, val firstName: String, val lastName: String, val email: String)
CustomerRoutes.kt
route("/customer") {}
get() {}
call.respond(customerStorage)
get("{id?}") {}
call.parameters["id"] ?: return@get call.respondText(" ", status = ) //请求携带的参数
val id = call.parameters.getOrFail<Int>("id").toInt()
post {}
call.receive<Customer>()
delete("{id?}") {}
2.静态及交互式网站
添加Routing、Static Content和Freemarker插件
get("/") { call.respondRedirect("articles") } // "articles" 从当前路径,"/articles" 从根路径
post {
val formParameters = call.receiveParameters() //取得form提交的参数
val title = formParameters.getOrFail("title")
}
staticResources("/static", "files") //导航资源路径,最新建议使用的
3.使用 Exposed 框架,H2 本地数据库来存储文章。
1.数据对象和表对象
Article.kt
data class Article(val id: Int, val title: String, val body: String)
object Articles : Table() { } //exposed 表对象
2.database单例和Query协程
DatabaseFactory.kt
object DatabaseFactory {
fun init() {
//......
val database = Database.connect(jdbcURL, driverClassName)
transaction(database) {
SchemaUtils.create(Articles) //表 ?: 创建表
}
}
suspend fun <T> dbQuery(block: suspend () -> T): T =
newSuspendedTransaction(Dispatchers.IO) { block() } //协程处理查询
}
3.DAO接口,实现,创建Dao
DAOFacade.kt
interface DAOFacade {
suspend fun allArticles(): List<Article>
//......
}
DAOFacadeImpl.kt
class DAOFacadeImpl : DAOFacade {
private fun resultRowToArticle(row: ResultRow) = Article(
id = row[Articles.id],
title = row[Articles.title],
body = row[Articles.body],
)
override suspend fun allArticles(): List<Article> = dbQuery {
Articles.selectAll().map(::resultRowToArticle)
}
//..........
}
val dao: DAOFacade = DAOFacadeImpl().apply {
runBlocking {
if (allArticles().isEmpty()) {
addNewArticle("The drive to develop!", "...it's what keeps me going.")
}
}
}
4.Application启动初始化
fun Application.module() {
DatabaseFactory.init()
configureTemplating()
configureRouting()
}
5.routing使用dao
routing {
get("/") {
call.respondRedirect("articles")
}
route("articles") {
get {
call.respond(FreeMarkerContent("index.ftl", mapOf("articles" to dao.allArticles())))
}
}
4.Ktor 连接mysql
dependencies {
implementation("mysql:mysql-connector-java:8.0.33")
}
val driverClassName = "com.mysql.cj.jdbc.Driver"
val jdbcURL = "jdbc:mysql://@localhost:3306/db_users"
val database = Database.connect(url = jdbcURL, driver = driverClassName, user = "root")
transaction(database) {
SchemaUtils.create(Articles,UsersTable)
}
5.创建客户端应用
AndroidManifest.xml 允许虚拟设备访问网络
<uses-permission android:name="android.permission.INTERNET"/>
dependencies {
implementation("io.ktor:ktor-client-core:$ktor_version")
implementation("io.ktor:ktor-client-cio:$ktor_version")
}
private val client = HttpClient(CIO)
suspend fun checkLogin(username: String, password: String): String {
val response: HttpResponse = client.submitForm(
"http://192.168.0.107:8080/login",
formParameters = parameters {
append("username", username)
append("password", password)
})
return response.bodyAsText()
}