在播放框架 2.0 中将文件作为流上传 [英] Uploading file as stream in play framework 2.0
问题描述
我正在编写一个允许用户上传文件的 play 2.0 java 应用程序.这些文件存储在我使用 Java 库访问的第三方服务中,我在此 API 中使用的方法具有以下签名:
I'm writing a play 2.0 java application that allows users to upload files. Those files are stored on a third-party service I access using a Java library, the method I use in this API has the following signature:
void store(InputStream stream, String path, String contentType)
我已经使用以下简单的控制器设法使上传工作:
I've managed to make uploads working using the following simple controller:
public static Result uploadFile(String path) {
MultipartFormData body = request().body().asMultipartFormData();
FilePart filePart = body.getFile("files[]");
InputStream is = new FileInputStream(filePart.getFile())
myApi.store(is,path,filePart.getContentType());
return ok();
}
我担心这个解决方案效率不高,因为默认情况下,播放框架将客户端上传的所有数据存储在服务器上的临时文件中,然后在控制器中调用我的 uploadFile() 方法.
My concern is that this solution is not efficient because by default the play framework stores all the data uploaded by the client in a temporary file on the server then calls my uploadFile() method in the controller.
在传统的 servlet 应用程序中,我会编写一个行为如下的 servlet:
In a traditional servlet application I would have written a servlet behaving this way:
myApi.store(request.getInputStream(), ...)
我到处寻找,没有找到任何解决方案.我发现的最接近的例子是 为什么调用错误或在 BodyParser 的 Iteratee 中完成请求在 Play Framework 2.0 中挂起? 但我没有找到如何修改它以满足我的需要.
I have been searching everywhere and didn't find any solution. The closest example I found is Why makes calling error or done in a BodyParser's Iteratee the request hang in Play Framework 2.0? but I didn't found how to modify it to fit my needs.
play2 有没有办法实现这种行为,即让客户端上传的数据通过"网络应用程序直接到另一个系统?
Is there a way in play2 to achieve this behavior, i.e. having the data uploaded by the client to go "through" the web-application directly to another system ?
谢谢.
推荐答案
我已经能够使用以下 Scala 控制器代码将数据流式传输到我的第三方 API:
I've been able to stream data to my third-party API using the following Scala controller code:
def uploadFile() =
Action( parse.multipartFormData(myPartHandler) )
{
request => Ok("Done")
}
def myPartHandler: BodyParsers.parse.Multipart.PartHandler[MultipartFormData.FilePart[Result]] = {
parse.Multipart.handleFilePart {
case parse.Multipart.FileInfo(partName, filename, contentType) =>
//Still dirty: the path of the file is in the partName...
String path = partName;
//Set up the PipedOutputStream here, give the input stream to a worker thread
val pos:PipedOutputStream = new PipedOutputStream();
val pis:PipedInputStream = new PipedInputStream(pos);
val worker:UploadFileWorker = new UploadFileWorker(path,pis);
worker.contentType = contentType.get;
worker.start();
//Read content to the POS
Iteratee.fold[Array[Byte], PipedOutputStream](pos) { (os, data) =>
os.write(data)
os
}.mapDone { os =>
os.close()
Ok("upload done")
}
}
}
UploadFileWorker 是一个非常简单的 Java 类,其中包含对第三方 API 的调用.
The UploadFileWorker is a really simple Java class that contains the call to the thrid-party API.
public class UploadFileWorker extends Thread {
String path;
PipedInputStream pis;
public String contentType = "";
public UploadFileWorker(String path, PipedInputStream pis) {
super();
this.path = path;
this.pis = pis;
}
public void run() {
try {
myApi.store(pis, path, contentType);
pis.close();
} catch (Exception ex) {
ex.printStackTrace();
try {pis.close();} catch (Exception ex2) {}
}
}
}
它并不完全完美,因为我更希望将路径恢复为 Action 的参数,但我一直无法这样做.因此,我添加了一段 javascript 来更新输入字段的名称(以及 partName),它就完成了.
It's not completely perfect because I would have preferred to recover the path as a parameter to the Action but I haven't been able to do so. I thus have added a piece of javascript that updates the name of the input field (and thus the partName) and it does the trick.
这篇关于在播放框架 2.0 中将文件作为流上传的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!