备份代码
This commit is contained in:
parent
27e398ac73
commit
15ddb83d2d
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<String>) {
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -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<DocumentRepository> { DocumentRepositoryImpl() }
|
||||
single<FileOSS> { AliyunOssFileServiceImpl() }
|
||||
}
|
||||
|
||||
fun Route.handleDocuments() {
|
||||
|
||||
val documentRepository by inject<DocumentRepository>()
|
||||
val fileOSS by inject<FileOSS>()
|
||||
|
||||
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<DocumentQueryParam>()
|
||||
val pageQuery = documentRepository.pageQuery(documentQueryParam)
|
||||
call.respond(Result.success(pageQuery))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<Long>) : LongEntity(id) {
|
||||
companion object : LongEntityClass<Document>(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<Document>
|
||||
suspend fun pageQuery(documentQueryParam: DocumentQueryParam): PageResult<Document>
|
||||
}
|
||||
|
||||
data class DocumentQueryParam(var title: String? = null,
|
||||
var authorId: String? = null) : BasePageQueryParm()
|
||||
data class DocumentQueryParam(
|
||||
var id: Long? = null,
|
||||
var title: String? = null,
|
||||
var authorId: String? = null
|
||||
) : BasePageQueryParm()
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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<String> = varchar("title", 255)
|
||||
val content: Column<String> = text("content")
|
||||
val authorId: Column<String> = varchar("author_id", 50)
|
||||
val createdAt: Column<LocalDateTime> = datetime("created_at")
|
||||
val updatedAt: Column<LocalDateTime> = datetime("updated_at")
|
||||
val fileSize: Column<String> = 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<Document> {
|
||||
override suspend fun pageQuery(documentQueryParam: DocumentQueryParam): PageResult<Document> = 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)
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<LocalDateTime>() {
|
||||
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)
|
||||
}
|
||||
}
|
|
@ -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"
|
|
@ -4,7 +4,7 @@
|
|||
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<root level="trace">
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
<logger name="org.eclipse.jetty" level="INFO"/>
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue