實作素材上傳
This commit is contained in:
parent
acf72d0aa7
commit
50dbcf60e1
@ -33,4 +33,5 @@ dependencies {
|
||||
implementation("org.litote.kmongo:kmongo:$kmongo_version")
|
||||
implementation("io.ktor:ktor-server-auth-jvm:$ktor_version")
|
||||
implementation("io.ktor:ktor-server-auth-jwt-jvm:$ktor_version")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0")
|
||||
}
|
||||
@ -2,15 +2,20 @@ package com.ray650128
|
||||
|
||||
import com.ray650128.model.dto.UserDto
|
||||
import com.ray650128.plugins.configureUserRouting
|
||||
import com.ray650128.plugins.configureSerialization
|
||||
import com.ray650128.plugins.configureArMaterialRouting
|
||||
import io.ktor.serialization.kotlinx.json.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.auth.*
|
||||
import io.ktor.server.auth.jwt.*
|
||||
import io.ktor.server.engine.*
|
||||
import io.ktor.server.netty.*
|
||||
import io.ktor.server.plugins.contentnegotiation.*
|
||||
|
||||
fun main() {
|
||||
embeddedServer(Netty, port = 8080, host = "0.0.0.0") {
|
||||
install(ContentNegotiation) {
|
||||
json()
|
||||
}
|
||||
install(Authentication) {
|
||||
jwt {
|
||||
verifier(JwtConfig.verifier)
|
||||
@ -26,6 +31,6 @@ fun main() {
|
||||
}
|
||||
}
|
||||
configureUserRouting()
|
||||
configureSerialization()
|
||||
configureArMaterialRouting()
|
||||
}.start(wait = true)
|
||||
}
|
||||
|
||||
28
src/main/kotlin/com/ray650128/extension/MaterialExtension.kt
Normal file
28
src/main/kotlin/com/ray650128/extension/MaterialExtension.kt
Normal file
@ -0,0 +1,28 @@
|
||||
package com.ray650128.extension
|
||||
|
||||
import com.ray650128.model.dto.MaterialDto
|
||||
import com.ray650128.model.dto.UserDto
|
||||
import com.ray650128.model.pojo.Material
|
||||
import com.ray650128.model.pojo.User
|
||||
|
||||
fun Material.toDto(): MaterialDto =
|
||||
MaterialDto(
|
||||
id = this.id.toString(),
|
||||
ownerId = this.ownerId.toString(),
|
||||
name = this.name,
|
||||
path = this.path,
|
||||
contentType = this.contentType,
|
||||
fileTag = this.fileTag,
|
||||
createAt = this.createAt,
|
||||
updatedAt = this.updatedAt
|
||||
)
|
||||
|
||||
fun MaterialDto.toMaterial(): Material =
|
||||
Material(
|
||||
name = this.name,
|
||||
path = this.path,
|
||||
contentType = this.contentType,
|
||||
fileTag = this.fileTag,
|
||||
createAt = this.createAt,
|
||||
updatedAt = this.updatedAt
|
||||
)
|
||||
@ -7,5 +7,6 @@ data class ErrorResponse(val message: String) {
|
||||
companion object {
|
||||
val NOT_FOUND_RESPONSE = ErrorResponse("Person was not found")
|
||||
val BAD_REQUEST_RESPONSE = ErrorResponse("Invalid request")
|
||||
val UNAUTHORIZED_RESPONSE = ErrorResponse("Unauthorized")
|
||||
}
|
||||
}
|
||||
16
src/main/kotlin/com/ray650128/model/dto/MaterialDto.kt
Normal file
16
src/main/kotlin/com/ray650128/model/dto/MaterialDto.kt
Normal file
@ -0,0 +1,16 @@
|
||||
package com.ray650128.model.dto
|
||||
|
||||
import io.ktor.server.auth.*
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class MaterialDto(
|
||||
val id: String? = null,
|
||||
var ownerId: String? = null,
|
||||
var name: String,
|
||||
val path: String,
|
||||
val contentType: String,
|
||||
var fileTag: ArrayList<String>? = null,
|
||||
var createAt: Long? = null,
|
||||
var updatedAt: Long? = null
|
||||
): Principal
|
||||
15
src/main/kotlin/com/ray650128/model/pojo/Material.kt
Normal file
15
src/main/kotlin/com/ray650128/model/pojo/Material.kt
Normal file
@ -0,0 +1,15 @@
|
||||
package com.ray650128.model.pojo
|
||||
|
||||
import org.bson.codecs.pojo.annotations.BsonId
|
||||
import org.litote.kmongo.Id
|
||||
|
||||
data class Material(
|
||||
@BsonId var id: Id<Material>? = null,
|
||||
var ownerId: Id<User>? = null,
|
||||
var name: String,
|
||||
var path: String,
|
||||
var contentType: String,
|
||||
var fileTag: ArrayList<String>? = null,
|
||||
var createAt: Long? = null,
|
||||
var updatedAt: Long? = null
|
||||
)
|
||||
8
src/main/kotlin/com/ray650128/model/pojo/NewMaterial.kt
Normal file
8
src/main/kotlin/com/ray650128/model/pojo/NewMaterial.kt
Normal file
@ -0,0 +1,8 @@
|
||||
package com.ray650128.model.pojo
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class NewMaterial(
|
||||
var name: String
|
||||
)
|
||||
@ -1,16 +1,128 @@
|
||||
package com.ray650128.plugins
|
||||
|
||||
import io.ktor.serialization.kotlinx.json.*
|
||||
import io.ktor.server.plugins.contentnegotiation.*
|
||||
import io.ktor.server.response.*
|
||||
import com.ray650128.extension.*
|
||||
import com.ray650128.model.ErrorResponse
|
||||
import com.ray650128.model.dto.MaterialDto
|
||||
import com.ray650128.model.dto.UserDto
|
||||
import com.ray650128.model.pojo.Material
|
||||
import com.ray650128.model.pojo.NewMaterial
|
||||
import com.ray650128.service.MaterialService
|
||||
import com.ray650128.service.UserService
|
||||
import io.ktor.http.*
|
||||
import io.ktor.http.content.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.auth.*
|
||||
import io.ktor.server.request.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.litote.kmongo.Id
|
||||
import java.io.File
|
||||
|
||||
fun Application.configureArMaterialRouting() {
|
||||
|
||||
val userService = UserService()
|
||||
val materialService = MaterialService()
|
||||
|
||||
fun Application.configureSerialization() {
|
||||
install(ContentNegotiation) {
|
||||
json()
|
||||
}
|
||||
routing {
|
||||
route("/upload") {
|
||||
get("/{name}") {
|
||||
val fileName = call.parameters["name"] ?: run {
|
||||
call.sendNotFound(ErrorResponse.NOT_FOUND_RESPONSE)
|
||||
return@get
|
||||
}
|
||||
println("[File]filename: $fileName")
|
||||
val file = File("./upload/$fileName")
|
||||
println("[File]file: ${file.absolutePath}")
|
||||
if(!file.exists()) {
|
||||
call.sendNotFound(ErrorResponse.NOT_FOUND_RESPONSE)
|
||||
return@get
|
||||
}
|
||||
call.respondFile(file)
|
||||
}
|
||||
}
|
||||
|
||||
authenticate {
|
||||
route("/api") {
|
||||
route("/v1") {
|
||||
route("/materials") {
|
||||
post("/upload") {
|
||||
val account = call.authentication.principal<UserDto>()?.account ?: run {
|
||||
call.sendUnauthorized(ErrorResponse.UNAUTHORIZED_RESPONSE)
|
||||
return@post
|
||||
}
|
||||
val user = userService.findByAccount(account) ?: run {
|
||||
call.sendUnauthorized(ErrorResponse.UNAUTHORIZED_RESPONSE)
|
||||
return@post
|
||||
}
|
||||
var materialId: String? = null
|
||||
// retrieve all multipart data (suspending)
|
||||
val multipart = call.receiveMultipart()
|
||||
var params: NewMaterial? = null
|
||||
multipart.forEachPart { part ->
|
||||
// Check part type
|
||||
when (part) {
|
||||
is PartData.FormItem -> {
|
||||
params = Json.decodeFromString(NewMaterial.serializer(), part.value)
|
||||
println(part.value)
|
||||
}
|
||||
|
||||
is PartData.FileItem -> {
|
||||
// retrieve file name of upload
|
||||
println("File content type: ${part.contentType?.contentType}/${part.contentType?.contentSubtype}")
|
||||
val extensionName = when (part.contentType?.contentSubtype) {
|
||||
"gltf-binary" -> "glb"
|
||||
"gltf+json" -> "gltf"
|
||||
else -> part.contentType?.contentSubtype
|
||||
}
|
||||
val name = "${System.currentTimeMillis()}.$extensionName"
|
||||
val directory = File("./upload/")
|
||||
if (!directory.exists()) {
|
||||
directory.mkdir()
|
||||
}
|
||||
val file = File("${directory.path}/$name")
|
||||
|
||||
// use InputStream from part to save file
|
||||
part.streamProvider().use { its ->
|
||||
// copy the stream to the file with buffering
|
||||
file.outputStream().buffered().use {
|
||||
// note that this is blocking
|
||||
its.copyTo(it)
|
||||
}
|
||||
}
|
||||
|
||||
val tmpMaterial = MaterialDto(
|
||||
name = if (params == null) {
|
||||
part.originalFileName!!
|
||||
} else {
|
||||
params!!.name
|
||||
},
|
||||
path = "/upload/$name",
|
||||
contentType = "${part.contentType}",
|
||||
createAt = System.currentTimeMillis()
|
||||
).toMaterial().apply {
|
||||
ownerId = user.id!!
|
||||
}
|
||||
materialId = materialService.create(tmpMaterial).toString()
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
// make sure to dispose of the part after use to prevent leaks
|
||||
part.dispose()
|
||||
}
|
||||
if (materialId != null) {
|
||||
val data = materialService.findById(materialId!!)?.toDto()
|
||||
call.sendSuccess(data)
|
||||
} else {
|
||||
call.sendBadRequest(ErrorResponse("Add material fail."))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get("/json/kotlinx-serialization") {
|
||||
call.respond(mapOf("hello" to "world"))
|
||||
}
|
||||
|
||||
45
src/main/kotlin/com/ray650128/service/MaterialService.kt
Normal file
45
src/main/kotlin/com/ray650128/service/MaterialService.kt
Normal file
@ -0,0 +1,45 @@
|
||||
package com.ray650128.service
|
||||
|
||||
import com.ray650128.model.pojo.Material
|
||||
import org.bson.types.ObjectId
|
||||
import org.litote.kmongo.*
|
||||
import org.litote.kmongo.id.toId
|
||||
|
||||
class MaterialService {
|
||||
private val client = KMongo.createClient("mongodb://www.ray650128.com:27017")
|
||||
private val database = client.getDatabase("ar_system")
|
||||
private val userCollection = database.getCollection<Material>()
|
||||
|
||||
fun create(user: Material): Id<Material>? {
|
||||
userCollection.insertOne(user)
|
||||
return user.id
|
||||
}
|
||||
|
||||
fun findAll(): List<Material> = userCollection.find().toList()
|
||||
|
||||
fun findById(id: String): Material? {
|
||||
val bsonId: Id<Material> = ObjectId(id).toId()
|
||||
return userCollection.findOne(Material::id eq bsonId)
|
||||
}
|
||||
|
||||
fun findByName(name: String): List<Material> {
|
||||
val caseSensitiveTypeSafeFilter = Material::name regex name
|
||||
return userCollection.find(caseSensitiveTypeSafeFilter).toList()
|
||||
}
|
||||
|
||||
fun updateById(id: String, request: Material): Boolean =
|
||||
findById(id)?.let { user ->
|
||||
val updateResult = userCollection.replaceOne(
|
||||
user.copy(
|
||||
name = request.name,
|
||||
updatedAt = request.updatedAt
|
||||
)
|
||||
)
|
||||
updateResult.modifiedCount == 1L
|
||||
} ?: false
|
||||
|
||||
fun deleteById(id: String): Boolean {
|
||||
val deleteResult = userCollection.deleteOneById(ObjectId(id))
|
||||
return deleteResult.deletedCount == 1L
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user