From 27e398ac733c7d774d95e578be623b8a06a2457c Mon Sep 17 00:00:00 2001 From: Superdandan <1033719135@qq.com> Date: Sun, 5 May 2024 10:47:44 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=87=E4=BB=BD=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 20 +++++ gradle.properties | 5 ++ src/main/kotlin/echo/org/Application.kt | 21 ++++- src/main/kotlin/echo/org/domain/Documents.kt | 31 +++++-- .../kotlin/echo/org/domain/ValueObject.kt | 15 +++- .../kotlin/echo/org/instructure/Database.kt | 36 +++++++++ .../kotlin/echo/org/instructure/Exposed.kt | 81 +++++++++++++++++++ src/main/kotlin/echo/org/plugins/Routing.kt | 4 +- src/main/resources/application.yaml | 8 ++ 9 files changed, 211 insertions(+), 10 deletions(-) create mode 100644 src/main/kotlin/echo/org/instructure/Database.kt create mode 100644 src/main/kotlin/echo/org/instructure/Exposed.kt diff --git a/build.gradle.kts b/build.gradle.kts index d0f9297..c9a2dc5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,6 +1,11 @@ val ktor_version: String by project val kotlin_version: String by project val logback_version: String by project +val exposed_version: String by project +val h2_version: String by project +val hikaricp_version: String by project +val ehcache_version: String by project +val mysql_driver_version: String by project plugins { kotlin("jvm") version "1.9.23" @@ -29,7 +34,22 @@ dependencies { implementation("io.ktor:ktor-server-freemarker-jvm") implementation("io.ktor:ktor-server-netty-jvm") implementation("ch.qos.logback:logback-classic:$logback_version") + implementation("io.ktor:ktor-server-config-yaml:2.3.10") + // Exposed + implementation("org.jetbrains.exposed:exposed-core:$exposed_version") + implementation("org.jetbrains.exposed:exposed-dao:$exposed_version") + implementation("org.jetbrains.exposed:exposed-jdbc:$exposed_version") + implementation("org.jetbrains.exposed:exposed-java-time:$exposed_version") + implementation("com.h2database:h2:$h2_version") + + //pool + implementation("com.zaxxer:HikariCP:$hikaricp_version") + implementation("org.ehcache:ehcache:$ehcache_version") + + //mysql + implementation("mysql:mysql-connector-java:$mysql_driver_version") + testImplementation("io.ktor:ktor-server-tests-jvm") testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version") } diff --git a/gradle.properties b/gradle.properties index f107887..450ee8e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,3 +2,8 @@ ktor_version=2.3.10 kotlin_version=1.9.23 logback_version=1.4.14 kotlin.code.style=official +exposed_version = 0.41.1 +h2_version = 2.2.224 +hikaricp_version = 5.1.0 +ehcache_version = 3.10.8 +mysql_driver_version = 8.0.32 \ No newline at end of file diff --git a/src/main/kotlin/echo/org/Application.kt b/src/main/kotlin/echo/org/Application.kt index 124f1f8..be41f64 100644 --- a/src/main/kotlin/echo/org/Application.kt +++ b/src/main/kotlin/echo/org/Application.kt @@ -1,7 +1,13 @@ package echo.org -import echo.org.plugins.* +import com.zaxxer.hikari.HikariDataSource +import echo.org.instructure.DatabaseSingleton +import echo.org.plugins.configureRouting +import echo.org.plugins.configureSecurity +import echo.org.plugins.configureSerialization +import echo.org.plugins.configureTemplating import io.ktor.server.application.* +import org.jetbrains.exposed.sql.Database fun main(args: Array) { io.ktor.server.netty.EngineMain.main(args) @@ -12,4 +18,17 @@ fun Application.module() { configureSerialization() configureTemplating() configureRouting() + initDatabase() +} + +fun Application.initDatabase() { + val config = environment.config.config("storage") + val dateSourceConfig = DatabaseSingleton.createHikariDataSource( + url = config.property("jdbcURL").getString(), + driver = config.property("driverClassName").getString(), + usernameInput = config.property("username").getString(), + passwordInput = config.property("password").getString() + ) + val dataSource = HikariDataSource(dateSourceConfig) + Database.connect(dataSource) } diff --git a/src/main/kotlin/echo/org/domain/Documents.kt b/src/main/kotlin/echo/org/domain/Documents.kt index 4bea8fd..34f186a 100644 --- a/src/main/kotlin/echo/org/domain/Documents.kt +++ b/src/main/kotlin/echo/org/domain/Documents.kt @@ -1,9 +1,28 @@ package echo.org.domain -data class Document(val id: Long, val content: String,val name: String) +import echo.org.instructure.Documents +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import java.time.LocalDateTime -val Documents : MutableList = mutableListOf( - Document(1,"测试1","测试名称1"), - Document(2,"测试2","测试名称2"), - Document(3,"测试3","测试名称3"), -) \ No newline at end of file +class Document(id: EntityID) : LongEntity(id) { + companion object : LongEntityClass(Documents) + var title: String by Documents.title + var content: String by Documents.content + var authorId: String by Documents.authorId + var createdAt: LocalDateTime by Documents.createdAt + var updatedAt: LocalDateTime by Documents.updatedAt + var fileSize: String by Documents.fileSize +} + + +interface DocumentRepository { + suspend fun save(document: Document): Document? + suspend fun findById(id: Long): Document? + suspend fun deleteById(id: Long): Boolean + suspend fun pageQuery(documentQueryParam:DocumentQueryParam): PageResult +} + +data class DocumentQueryParam(var title: String? = null, + var authorId: String? = null) : BasePageQueryParm() \ No newline at end of file diff --git a/src/main/kotlin/echo/org/domain/ValueObject.kt b/src/main/kotlin/echo/org/domain/ValueObject.kt index 4d78753..8c92cd4 100644 --- a/src/main/kotlin/echo/org/domain/ValueObject.kt +++ b/src/main/kotlin/echo/org/domain/ValueObject.kt @@ -23,4 +23,17 @@ data class Result( return Result(code = code, message = message, data = data) } } -} \ No newline at end of file +} + +data class PageResult( + val results: List, // 查询结果列表 + val totalCount: Long // 总记录数 +) { +// companion object { +// fun of(results: List,totalCount: Long ): PageResult { +// return PageResult() +// } +// } +} + +open class BasePageQueryParm(var pageNum: Int = 1, var pageSize: Int = 10) \ No newline at end of file diff --git a/src/main/kotlin/echo/org/instructure/Database.kt b/src/main/kotlin/echo/org/instructure/Database.kt new file mode 100644 index 0000000..4f4a2ad --- /dev/null +++ b/src/main/kotlin/echo/org/instructure/Database.kt @@ -0,0 +1,36 @@ +package echo.org.instructure + +import com.zaxxer.hikari.HikariConfig +import com.zaxxer.hikari.HikariDataSource +import io.ktor.server.config.* +import kotlinx.coroutines.Dispatchers +import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction + +object DatabaseSingleton { + + fun init(config: ApplicationConfig) { + val driverClassName = config.property("storage.driverClassName").getString() + val jdbcURL = config.property("storage.jdbcURL").getString() + + config.propertyOrNull("storage.database")?.getString() + + } + + fun createHikariDataSource( + url: String, + driver: String, + usernameInput: String, + passwordInput: String + ) = HikariDataSource(HikariConfig().apply { + driverClassName = driver + jdbcUrl = url + username = usernameInput + password = passwordInput + maximumPoolSize = 30 + isAutoCommit = false + transactionIsolation = "TRANSACTION_REPEATABLE_READ" + validate() + }) + + suspend fun dbQuery(block: suspend () -> T): T = + newSuspendedTransaction(Dispatchers.IO) { block() } +} \ No newline at end of file diff --git a/src/main/kotlin/echo/org/instructure/Exposed.kt b/src/main/kotlin/echo/org/instructure/Exposed.kt new file mode 100644 index 0000000..4526cc8 --- /dev/null +++ b/src/main/kotlin/echo/org/instructure/Exposed.kt @@ -0,0 +1,81 @@ +package echo.org.instructure + +import echo.org.domain.Document +import echo.org.domain.DocumentQueryParam +import echo.org.domain.DocumentRepository +import echo.org.domain.PageResult +import echo.org.instructure.DatabaseSingleton.dbQuery +import org.jetbrains.exposed.dao.id.LongIdTable +import org.jetbrains.exposed.sql.Column +import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq +import org.jetbrains.exposed.sql.andWhere +import org.jetbrains.exposed.sql.deleteWhere +import org.jetbrains.exposed.sql.javatime.datetime +import org.jetbrains.exposed.sql.selectAll +import java.time.LocalDateTime + + +object Documents : LongIdTable() { + val title: Column = varchar("title", 255) + val content: Column = text("content") + val authorId: Column = varchar("author_id", 50) + val createdAt: Column = datetime("created_at") + val updatedAt: Column = datetime("updated_at") + val fileSize: Column = varchar("file_size", 255) +} + + +class DocumentRepositoryImpl : DocumentRepository { + + override suspend fun save(document: Document): Document = dbQuery { + // 检查文档是否有有效的ID + val existingDocument = document.id.let { + Document.findById(it) + } + // 如果文档存在,则更新,否则创建新文档 + existingDocument?.apply { + title = document.title + content = document.content + authorId = document.authorId + createdAt = document.createdAt + updatedAt = LocalDateTime.now() // 更新时间应为当前时间 + fileSize = document.fileSize + } ?: Document.new { + title = document.title + content = document.content + authorId = document.authorId + createdAt = document.createdAt + updatedAt = document.updatedAt + fileSize = document.fileSize + } + } + + override suspend fun findById(id: Long): Document? = dbQuery { + Document.find { Documents.id eq id }.firstOrNull() + } + + override suspend fun deleteById(id: Long): Boolean { + Document.find { Documents.id eq id } + .firstOrNull()?.delete() + return Documents.deleteWhere { Documents.id eq id } > 0 + } + + override suspend fun pageQuery(documentQueryParam: DocumentQueryParam): PageResult { + // 构建查询条件 + val query = Documents.selectAll().apply { + documentQueryParam.authorId?.let { + andWhere { Documents.authorId eq documentQueryParam.authorId!! } + } + documentQueryParam.title?.let { + andWhere { Documents.title like "%${documentQueryParam.title}%" } + } + } + val pageSize = documentQueryParam.pageSize ?: 10 // 默认页面大小 + val pageIndex = documentQueryParam.pageNum ?: 0 // 默认页码 + val offset = pageSize * pageIndex.toLong() + // 执行查询 + val count = query.count() + val documentList = query.limit(pageSize, offset).map { Document.wrapRow(it) } + return PageResult(documentList, count) + } +} \ No newline at end of file diff --git a/src/main/kotlin/echo/org/plugins/Routing.kt b/src/main/kotlin/echo/org/plugins/Routing.kt index b3b6d6f..32fd735 100644 --- a/src/main/kotlin/echo/org/plugins/Routing.kt +++ b/src/main/kotlin/echo/org/plugins/Routing.kt @@ -1,7 +1,7 @@ package echo.org.plugins -import echo.org.domain.Documents +import echo.org.domainDocuments import echo.org.domain.Result import io.ktor.http.content.* import io.ktor.server.application.* @@ -17,7 +17,7 @@ fun Application.configureRouting() { staticResources("/files", "files") route("/documents") { get("") { - val model = mapOf("Documents" to Documents) + call.respond(FreeMarkerContent("index.ftl", model, "e")) } post("/add") { diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index f384b82..e2378c7 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -4,3 +4,11 @@ ktor: - echo.org.ApplicationKt.module deployment: port: 8080 + + +storage: + driverClassName: "com.mysql.cj.jdbc.Driver" + jdbcURL: "jdbc:mysql://47.97.21.20:3306/" + database: "document" + username: "documentAdmin" + password: "123456" \ No newline at end of file