Play Framework 2.6 Alpakka S3 文件上传
Play Framework 2.6 Alpakka S3 File Upload
我使用 Play Framework 2.6 (Scala) 和 Alpakka AWS S3 连接器将文件异步上传到 S3 存储桶。我的代码如下所示:
def richUpload(extension: String, checkFunction: (String, Option[String]) => Boolean, cannedAcl: CannedAcl, bucket: String) = userAction(parse.multipartFormData(handleFilePartAsFile)).async { implicit request =>
val s3Filename = request.user.get.id + "/" + java.util.UUID.randomUUID.toString + "." + extension
val fileOption = request.body.file("file").map {
case FilePart(key, filename, contentType, file) =>
Logger.info(s"key = ${key}, filename = ${filename}, contentType = ${contentType}, file = $file")
if(checkFunction(filename, contentType)) {
s3Service.uploadSink(s3Filename, cannedAcl, bucket).runWith(FileIO.fromPath(file.toPath))
} else {
throw new Exception("Upload failed")
}
}
fileOption match {
case Some(opt) => opt.map(o => Ok(s3Filename))
case _ => Future.successful(BadRequest("ERROR"))
}
}
有效,但在上传到 S3 之前它是 returns 文件名。但我想 return 上传到 S3 后的值。有什么解决办法吗?
此外,是否可以将文件直接流式传输到 S3,以正确显示进度并且不使用临时磁盘文件?
你需要翻转源和汇来获得你感兴趣的materialized value。
你有:
- 从您的本地文件读取并在完成读取文件后具体化为
Future[IOResult]
的源。
- 写入 S3 并在完成写入 S3 后实现
Future[MultipartUploadResult]
的接收器。
您对后者感兴趣,但在您的代码中使用的是前者。这是因为 runWith
函数始终将阶段的物化值作为参数传递。
下面示例代码段中的类型应阐明这一点:
val fileSource: Source[ByteString, Future[IOResult]] = ???
val s3Sink : Sink [ByteString, Future[MultipartUploadResult]] = ???
val m1: Future[IOResult] = s3Sink.runWith(fileSource)
val m2: Future[MultipartUploadResult] = fileSource.runWith(s3Sink)
获得 Future[MultipartUploadResult]
后,您可以 map
以相同的方式访问 location
字段以获取文件的 URI,例如:
val location: URI = fileSource.runWith(s3Sink).map(_.location)
我使用 Play Framework 2.6 (Scala) 和 Alpakka AWS S3 连接器将文件异步上传到 S3 存储桶。我的代码如下所示:
def richUpload(extension: String, checkFunction: (String, Option[String]) => Boolean, cannedAcl: CannedAcl, bucket: String) = userAction(parse.multipartFormData(handleFilePartAsFile)).async { implicit request =>
val s3Filename = request.user.get.id + "/" + java.util.UUID.randomUUID.toString + "." + extension
val fileOption = request.body.file("file").map {
case FilePart(key, filename, contentType, file) =>
Logger.info(s"key = ${key}, filename = ${filename}, contentType = ${contentType}, file = $file")
if(checkFunction(filename, contentType)) {
s3Service.uploadSink(s3Filename, cannedAcl, bucket).runWith(FileIO.fromPath(file.toPath))
} else {
throw new Exception("Upload failed")
}
}
fileOption match {
case Some(opt) => opt.map(o => Ok(s3Filename))
case _ => Future.successful(BadRequest("ERROR"))
}
}
有效,但在上传到 S3 之前它是 returns 文件名。但我想 return 上传到 S3 后的值。有什么解决办法吗?
此外,是否可以将文件直接流式传输到 S3,以正确显示进度并且不使用临时磁盘文件?
你需要翻转源和汇来获得你感兴趣的materialized value。 你有:
- 从您的本地文件读取并在完成读取文件后具体化为
Future[IOResult]
的源。 - 写入 S3 并在完成写入 S3 后实现
Future[MultipartUploadResult]
的接收器。
您对后者感兴趣,但在您的代码中使用的是前者。这是因为 runWith
函数始终将阶段的物化值作为参数传递。
下面示例代码段中的类型应阐明这一点:
val fileSource: Source[ByteString, Future[IOResult]] = ???
val s3Sink : Sink [ByteString, Future[MultipartUploadResult]] = ???
val m1: Future[IOResult] = s3Sink.runWith(fileSource)
val m2: Future[MultipartUploadResult] = fileSource.runWith(s3Sink)
获得 Future[MultipartUploadResult]
后,您可以 map
以相同的方式访问 location
字段以获取文件的 URI,例如:
val location: URI = fileSource.runWith(s3Sink).map(_.location)