From 15ddb83d2d756de1fbd15fd1f60f8fd3898f1696 Mon Sep 17 00:00:00 2001 From: Superdandan <1033719135@qq.com> Date: Sun, 19 May 2024 23:07:25 +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 | 14 +- gradle.properties | 2 +- src/main/kotlin/echo/org/Application.kt | 24 ++-- .../org/application/route/DocumentRoute.kt | 100 +++++++++++++++ src/main/kotlin/echo/org/domain/Documents.kt | 43 +++++-- .../kotlin/echo/org/domain/FileService.kt | 9 ++ .../kotlin/echo/org/instructure/AliyunOss.kt | 89 +++++++++++++ .../kotlin/echo/org/instructure/Database.kt | 24 +++- .../kotlin/echo/org/instructure/Exposed.kt | 120 +++++++++++------- src/main/kotlin/echo/org/plugins/Routing.kt | 38 +----- .../kotlin/echo/org/plugins/Serialization.kt | 18 +++ src/main/resources/application.yaml | 4 +- src/main/resources/logback.xml | 2 +- src/test/kotlin/echo/org/ApplicationTest.kt | 7 + src/test/kotlin/echo/org/OssTest.kt | 18 +++ 15 files changed, 397 insertions(+), 115 deletions(-) create mode 100644 src/main/kotlin/echo/org/application/route/DocumentRoute.kt create mode 100644 src/main/kotlin/echo/org/domain/FileService.kt create mode 100644 src/main/kotlin/echo/org/instructure/AliyunOss.kt create mode 100644 src/test/kotlin/echo/org/OssTest.kt diff --git a/build.gradle.kts b/build.gradle.kts index c9a2dc5..6351c4c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,7 +1,7 @@ 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 exposed_version: String by project val h2_version: String by project val hikaricp_version: String by project val ehcache_version: String by project @@ -33,16 +33,28 @@ dependencies { implementation("io.ktor:ktor-serialization-gson-jvm") implementation("io.ktor:ktor-server-freemarker-jvm") implementation("io.ktor:ktor-server-netty-jvm") + implementation("io.insert-koin:koin-ktor:3.2.0") + implementation("io.insert-koin:koin-core:3.2.0") 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-crypt:$exposed_version") implementation("org.jetbrains.exposed:exposed-jdbc:$exposed_version") implementation("org.jetbrains.exposed:exposed-java-time:$exposed_version") + implementation("org.jetbrains.exposed:exposed-json:$exposed_version") + implementation("org.jetbrains.exposed:exposed-money:$exposed_version") implementation("com.h2database:h2:$h2_version") + //aliyunOss + implementation("com.aliyun.oss:aliyun-sdk-oss:3.17.4") + implementation("javax.xml.bind:jaxb-api:2.3.1") + implementation("javax.activation:activation:1.1.1") + implementation("org.glassfish.jaxb:jaxb-runtime:2.3.3") + + //pool implementation("com.zaxxer:HikariCP:$hikaricp_version") implementation("org.ehcache:ehcache:$ehcache_version") diff --git a/gradle.properties b/gradle.properties index 450ee8e..53a0aa6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ ktor_version=2.3.10 kotlin_version=1.9.23 logback_version=1.4.14 kotlin.code.style=official -exposed_version = 0.41.1 +exposed_version = 0.50.1 h2_version = 2.2.224 hikaricp_version = 5.1.0 ehcache_version = 3.10.8 diff --git a/src/main/kotlin/echo/org/Application.kt b/src/main/kotlin/echo/org/Application.kt index be41f64..51fa2b8 100644 --- a/src/main/kotlin/echo/org/Application.kt +++ b/src/main/kotlin/echo/org/Application.kt @@ -1,34 +1,34 @@ package echo.org -import com.zaxxer.hikari.HikariDataSource +import echo.org.application.route.DocumentModule +import echo.org.instructure.AliyunOss 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 +import org.koin.ktor.ext.inject +import org.koin.ktor.plugin.Koin fun main(args: Array) { io.ktor.server.netty.EngineMain.main(args) + } fun Application.module() { + // Initialize Koin + install(Koin) { + modules(DocumentModule) + } + AliyunOss.init() configureSecurity() configureSerialization() - configureTemplating() configureRouting() + configureTemplating() 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) + DatabaseSingleton.init(environment.config) } diff --git a/src/main/kotlin/echo/org/application/route/DocumentRoute.kt b/src/main/kotlin/echo/org/application/route/DocumentRoute.kt new file mode 100644 index 0000000..42c3c3b --- /dev/null +++ b/src/main/kotlin/echo/org/application/route/DocumentRoute.kt @@ -0,0 +1,100 @@ +package echo.org.application.route + +import echo.org.domain.* +import echo.org.instructure.AliyunOssFileServiceImpl +import echo.org.instructure.DocumentRepositoryImpl +import io.ktor.http.* +import io.ktor.http.content.* +import io.ktor.server.application.* +import io.ktor.server.freemarker.* +import io.ktor.server.request.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import org.koin.dsl.module +import org.koin.ktor.ext.inject +import java.io.File +import java.net.URLEncoder +import java.nio.charset.StandardCharsets +import java.time.LocalDateTime + +val DocumentModule = module { + single { DocumentRepositoryImpl() } + single { AliyunOssFileServiceImpl() } +} + +fun Route.handleDocuments() { + + val documentRepository by inject() + val fileOSS by inject() + + route("/documents") { + get("") { + val res = documentRepository.pageQuery(DocumentQueryParam()) + call.respond(FreeMarkerContent("index.ftl", res.results, "e")) + } + post("/add") { + // 添加一个文件 + val multipart = call.receiveMultipart() + var fileSize: String? + var fileType: String? + var uploadName: String? + multipart.forEachPart { part -> + when (part) { + is PartData.FileItem -> { + val fileName = part.originalFileName as String + fileType = fileName.split(".").last() + uploadName = System.currentTimeMillis().toString() + "." + fileType + val file = File(uploadName!!) + part.streamProvider() + .use { its -> + file.outputStream().buffered() + .use { its.copyTo(it) } + } + fileSize = file.length().toString() + if (fileOSS.upload(file)) { + file.delete() + documentRepository.create( + DocumentVO( + fileName, "someAuthorId", + LocalDateTime.now(), LocalDateTime.now(), + fileType ?: "", uploadName ?: "", + fileSize ?: "", "" + ) + ) + } + } + + else -> {} + } + part.dispose() + } + call.respond(Result.success(null)) + } + get("/download") { + // 获取下载地址 + val documentQueryParam = DocumentQueryParam() + documentQueryParam.id = 1 + documentQueryParam.id?.let { + documentRepository.findById(it)?.let { document -> + val file = fileOSS.download(document.uploadName) + if (file.exists()) { + val encodedFileName = URLEncoder.encode(document.title, StandardCharsets.UTF_8.toString()) + call.response.header( + HttpHeaders.ContentDisposition, + "attachment; filename*=UTF-8''$encodedFileName" + ) + call.response.header(HttpHeaders.ContentType, document.fileType) + call.respondFile(file) + } else { + call.respond(HttpStatusCode.NotFound, mapOf("error" to "File not found")) + } + } ?: call.respond(HttpStatusCode.NotFound, mapOf("error" to "Document not found")) + } ?: call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Missing or invalid document ID")) + } + post("/query") { + val documentQueryParam = call.receive() + val pageQuery = documentRepository.pageQuery(documentQueryParam) + call.respond(Result.success(pageQuery)) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/echo/org/domain/Documents.kt b/src/main/kotlin/echo/org/domain/Documents.kt index 34f186a..7a40ae3 100644 --- a/src/main/kotlin/echo/org/domain/Documents.kt +++ b/src/main/kotlin/echo/org/domain/Documents.kt @@ -6,23 +6,40 @@ import org.jetbrains.exposed.dao.LongEntityClass import org.jetbrains.exposed.dao.id.EntityID import java.time.LocalDateTime -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 -} + +data class Document( + val id: Long, + val title: String, + val uploadName: String, + val fileType: String, + val authorId: String, + val createdAt: LocalDateTime, + val updatedAt: LocalDateTime, + val fileSize: String, + val filePath: String +) + +data class DocumentVO( + val title: String, val authorId: String, + val updatedAt: LocalDateTime, + val createdAt: LocalDateTime, + val fileType: String, + val uploadName: String, + val fileSize: String, + val filePath: String +) interface DocumentRepository { - suspend fun save(document: Document): Document? + suspend fun create(documentVO: DocumentVO): Document? + suspend fun edit(document: Document): Document? suspend fun findById(id: Long): Document? suspend fun deleteById(id: Long): Boolean - suspend fun pageQuery(documentQueryParam:DocumentQueryParam): PageResult + suspend fun pageQuery(documentQueryParam: DocumentQueryParam): PageResult } -data class DocumentQueryParam(var title: String? = null, - var authorId: String? = null) : BasePageQueryParm() \ No newline at end of file +data class DocumentQueryParam( + var id: Long? = null, + var title: String? = null, + var authorId: String? = null +) : BasePageQueryParm() \ No newline at end of file diff --git a/src/main/kotlin/echo/org/domain/FileService.kt b/src/main/kotlin/echo/org/domain/FileService.kt new file mode 100644 index 0000000..5778045 --- /dev/null +++ b/src/main/kotlin/echo/org/domain/FileService.kt @@ -0,0 +1,9 @@ +package echo.org.domain + +import java.io.File + +interface FileOSS { + fun upload(file: File): Boolean + fun download(fileName: String): File + fun delete(fileName: String): Boolean +} \ No newline at end of file diff --git a/src/main/kotlin/echo/org/instructure/AliyunOss.kt b/src/main/kotlin/echo/org/instructure/AliyunOss.kt new file mode 100644 index 0000000..82a4582 --- /dev/null +++ b/src/main/kotlin/echo/org/instructure/AliyunOss.kt @@ -0,0 +1,89 @@ +package echo.org.instructure + +import com.aliyun.oss.OSS +import com.aliyun.oss.OSSClientBuilder +import com.aliyun.oss.common.auth.CredentialsProvider +import com.aliyun.oss.common.auth.CredentialsProviderFactory +import com.aliyun.oss.common.auth.DefaultCredentialProvider +import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider +import com.aliyun.oss.model.Bucket +import echo.org.domain.FileOSS +import java.io.File +import java.io.FileOutputStream + + +//获取本地环境的oss访问凭证信息 +fun credentialsProvider(): EnvironmentVariableCredentialsProvider = + CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider() + +object AliyunOss { + + private lateinit var ossClient: OSS + + private const val ENDPOINT = "https://oss-cn-hangzhou.aliyuncs.com" + + private const val BUCKET_NAME = "echolaw" + + fun init(): OSS { + val accessKeyId = System.getenv("OSS_ACCESS_KEY_ID") + val accessKeySecret = System.getenv("OSS_ACCESS_KEY_SECRET") + val credentialsProvider: CredentialsProvider = DefaultCredentialProvider(accessKeyId, accessKeySecret) + ossClient = OSSClientBuilder().build(ENDPOINT, credentialsProvider) + return ossClient + } + + fun shutdown() { + ossClient.shutdown() + } + + fun client(): OSS { + return ossClient + } + + fun bucket(): Bucket { + return ossClient.createBucket(BUCKET_NAME) + } + + fun bucketName(): String { + return BUCKET_NAME + } +} + +class AliyunOssFileServiceImpl : FileOSS { + override fun upload(file: File): Boolean { + try { + AliyunOss.client().putObject( + AliyunOss.bucketName(), + file.name, + file + ) + } catch (e: Exception) { + e.printStackTrace() + return false + } + return true + } + + override fun download(fileName: String): File { + val ossObject = AliyunOss.client().getObject(AliyunOss.bucketName(), fileName) + val file = File(fileName) + val outputStream = FileOutputStream(file) + ossObject.objectContent?.use { input -> + outputStream.use { output -> + input.copyTo(output) + } + } + return file + } + + override fun delete(fileName: String): Boolean { + val client = AliyunOss.client() + try { + client.deleteObject(AliyunOss.bucketName(), fileName) + } catch (e: Exception) { + e.printStackTrace() + return false + } + return true + } +} diff --git a/src/main/kotlin/echo/org/instructure/Database.kt b/src/main/kotlin/echo/org/instructure/Database.kt index 4f4a2ad..92e85c6 100644 --- a/src/main/kotlin/echo/org/instructure/Database.kt +++ b/src/main/kotlin/echo/org/instructure/Database.kt @@ -4,18 +4,32 @@ import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource import io.ktor.server.config.* import kotlinx.coroutines.Dispatchers +import org.jetbrains.exposed.sql.Database +import org.jetbrains.exposed.sql.SchemaUtils import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction +import org.jetbrains.exposed.sql.transactions.transaction 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() + lateinit var dataSource: HikariDataSource + fun init(config: ApplicationConfig) { + val jdbcUrl = config.property("storage.jdbcURL").getString() + val database = config.property("storage.database").getString() + val dateSourceConfig = createHikariDataSource( + url = "$jdbcUrl/$database", + driver = config.property("storage.driverClassName").getString(), + usernameInput = config.property("storage.username").getString(), + passwordInput = config.property("storage.password").getString() + ) + dataSource = HikariDataSource(dateSourceConfig) + Database.connect(dataSource) + transaction { + SchemaUtils.create(Documents) + } } - fun createHikariDataSource( + private fun createHikariDataSource( url: String, driver: String, usernameInput: String, diff --git a/src/main/kotlin/echo/org/instructure/Exposed.kt b/src/main/kotlin/echo/org/instructure/Exposed.kt index 4526cc8..7ba0cc0 100644 --- a/src/main/kotlin/echo/org/instructure/Exposed.kt +++ b/src/main/kotlin/echo/org/instructure/Exposed.kt @@ -1,66 +1,95 @@ 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.domain.* import echo.org.instructure.DatabaseSingleton.dbQuery -import org.jetbrains.exposed.dao.id.LongIdTable -import org.jetbrains.exposed.sql.Column +import echo.org.instructure.Documents.id +import org.jetbrains.exposed.sql.* 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) +object Documents : Table() { + val id = long("id").autoIncrement().uniqueIndex() + val title = varchar("title", 255) + val uploadName = varchar("upload_name", 255) + val fileType = varchar("file_type", 50) + val authorId = varchar("author_id", 255) + val createdAt = datetime("created_at") + val updatedAt = datetime("updated_at") + val fileSize = varchar("file_size", 100) + val filePath = varchar("file_path", 255) + override val primaryKey = PrimaryKey(id) + + // Convert a ResultRow to a Document + fun toDocument(row: ResultRow): Document { + return Document( + id = row[id], + title = row[title], + authorId = row[authorId], + createdAt = row[createdAt], + updatedAt = row[updatedAt], + fileType = row[fileType], + uploadName = row[uploadName], + fileSize = row[fileSize], + filePath = row[filePath] + ) + } } class DocumentRepositoryImpl : DocumentRepository { - override suspend fun save(document: Document): Document = dbQuery { + override suspend fun edit(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 + val existingDocument = Documents.selectAll().where { id eq document.id }.singleOrNull() + // 如果文档存在,则更新,否则返回 null + existingDocument?.let { + Documents.update({ id eq document.id }) { + it[title] = document.title + it[authorId] = document.authorId + it[createdAt] = document.createdAt + it[updatedAt] = LocalDateTime.now() // 更新时间应为当前时间 + it[fileSize] = document.fileSize + } + // 返回更新后的 Document 对象 + Documents.selectAll().where { id eq document.id } + .map { Documents.toDocument(it) } + .singleOrNull() } } + override suspend fun create( + documentVO: DocumentVO + ): Document = dbQuery { + Documents.insert { + it[title] = documentVO.title + it[authorId] = documentVO.authorId + it[updatedAt] = documentVO.updatedAt + it[createdAt] = documentVO.createdAt + it[fileType] = documentVO.fileType + it[uploadName] = documentVO.uploadName + it[fileSize] = documentVO.fileSize + it[filePath] = documentVO.filePath + } + Documents.selectAll().where { id eq id } + .map { Documents.toDocument(it) } + .single() + } + + override suspend fun findById(id: Long): Document? = dbQuery { - Document.find { Documents.id eq id }.firstOrNull() + Documents.selectAll().where { Documents.id eq id } + .mapNotNull { Documents.toDocument(it) } + .singleOrNull() } - 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 deleteById(id: Long): Boolean = dbQuery { + Documents.deleteWhere { Documents.id eq id } > 0 } - override suspend fun pageQuery(documentQueryParam: DocumentQueryParam): PageResult { + override suspend fun pageQuery(documentQueryParam: DocumentQueryParam): PageResult = dbQuery { // 构建查询条件 val query = Documents.selectAll().apply { documentQueryParam.authorId?.let { @@ -70,12 +99,13 @@ class DocumentRepositoryImpl : DocumentRepository { andWhere { Documents.title like "%${documentQueryParam.title}%" } } } - val pageSize = documentQueryParam.pageSize ?: 10 // 默认页面大小 - val pageIndex = documentQueryParam.pageNum ?: 0 // 默认页码 + val pageSize = documentQueryParam.pageSize // 默认页面大小 + val pageIndex = documentQueryParam.pageNum - 1 // 默认页码 val offset = pageSize * pageIndex.toLong() // 执行查询 val count = query.count() - val documentList = query.limit(pageSize, offset).map { Document.wrapRow(it) } - return PageResult(documentList, count) + val documents = query.limit(pageSize, offset) + .map { Documents.toDocument(it) } + PageResult(documents, 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 32fd735..718b882 100644 --- a/src/main/kotlin/echo/org/plugins/Routing.kt +++ b/src/main/kotlin/echo/org/plugins/Routing.kt @@ -1,47 +1,15 @@ package echo.org.plugins -import echo.org.domainDocuments -import echo.org.domain.Result -import io.ktor.http.content.* +import echo.org.application.route.handleDocuments import io.ktor.server.application.* -import io.ktor.server.freemarker.* import io.ktor.server.http.content.* -import io.ktor.server.request.* -import io.ktor.server.response.* import io.ktor.server.routing.* -import java.io.File + fun Application.configureRouting() { routing { staticResources("/files", "files") - route("/documents") { - get("") { - - call.respond(FreeMarkerContent("index.ftl", model, "e")) - } - post("/add") { - // 添加一个文件 - val multipart = call.receiveMultipart() - multipart.forEachPart { part -> - when (part) { - is PartData.FileItem -> { - val fileName = part.originalFileName as String - val file = File("upload-directory/$fileName") - part.streamProvider() - .use { its -> file.outputStream().buffered() - .use { its.copyTo(it) } } - } - else -> {} - } - part.dispose() - } - call.respond(Result.success("")) - } - post("/download"){ - // 获取下载第 - } - } - + handleDocuments() } } diff --git a/src/main/kotlin/echo/org/plugins/Serialization.kt b/src/main/kotlin/echo/org/plugins/Serialization.kt index 3032e34..845b3a2 100644 --- a/src/main/kotlin/echo/org/plugins/Serialization.kt +++ b/src/main/kotlin/echo/org/plugins/Serialization.kt @@ -1,14 +1,20 @@ package echo.org.plugins +import com.google.gson.TypeAdapter +import com.google.gson.stream.JsonReader +import com.google.gson.stream.JsonWriter import io.ktor.serialization.gson.* import io.ktor.server.application.* import io.ktor.server.plugins.contentnegotiation.* import io.ktor.server.response.* import io.ktor.server.routing.* +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter fun Application.configureSerialization() { install(ContentNegotiation) { gson { + registerTypeAdapter(LocalDateTime::class.java, LocalDateTimeAdapter()) } } routing { @@ -17,3 +23,15 @@ fun Application.configureSerialization() { } } } + +class LocalDateTimeAdapter : TypeAdapter() { + private val formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME + + override fun write(out: JsonWriter, value: LocalDateTime) { + out.value(value.format(formatter)) + } + + override fun read(input: JsonReader): LocalDateTime { + return LocalDateTime.parse(input.nextString(), formatter) + } +} \ No newline at end of file diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index e2378c7..5b69b39 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -3,12 +3,12 @@ ktor: modules: - echo.org.ApplicationKt.module deployment: - port: 8080 + port: 8012 storage: driverClassName: "com.mysql.cj.jdbc.Driver" - jdbcURL: "jdbc:mysql://47.97.21.20:3306/" + jdbcURL: "jdbc:mysql://47.97.21.20:3306" database: "document" username: "documentAdmin" password: "123456" \ No newline at end of file diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 3e11d78..aadef5d 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -4,7 +4,7 @@ %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - + diff --git a/src/test/kotlin/echo/org/ApplicationTest.kt b/src/test/kotlin/echo/org/ApplicationTest.kt index 8fd6a72..8c50952 100644 --- a/src/test/kotlin/echo/org/ApplicationTest.kt +++ b/src/test/kotlin/echo/org/ApplicationTest.kt @@ -1,10 +1,17 @@ package echo.org +import echo.org.application.route.DocumentModule +import echo.org.instructure.Documents import echo.org.plugins.* import io.ktor.client.request.* import io.ktor.client.statement.* import io.ktor.http.* +import io.ktor.server.application.* import io.ktor.server.testing.* +import org.jetbrains.exposed.sql.SchemaUtils +import org.jetbrains.exposed.sql.transactions.transaction +import org.koin.dsl.module +import org.koin.ktor.plugin.Koin import kotlin.test.* class ApplicationTest { diff --git a/src/test/kotlin/echo/org/OssTest.kt b/src/test/kotlin/echo/org/OssTest.kt new file mode 100644 index 0000000..b241e6c --- /dev/null +++ b/src/test/kotlin/echo/org/OssTest.kt @@ -0,0 +1,18 @@ +package echo.org + +import echo.org.instructure.AliyunOss +import io.ktor.server.testing.* +import java.io.File +import kotlin.test.Test + +class ApplicationOSSTest { + + @Test + fun testRoot() = testApplication { + AliyunOss.init() + + AliyunOss.client().putObject(AliyunOss.bucketName(), + "测试.txt", + File("D:\\code\\blog\\upload-directory\\新建 文本文档 (3).txt")) + } +} \ No newline at end of file