17

私は、ユーザーがファイルをアップロードできるようにするPlay2.0Javaアプリケーションを作成しています。これらのファイルは、Javaライブラリを使用してアクセスするサードパーティのサービスに保存されます。このAPIで使用するメソッドには、次の署名があります。

void store(InputStream stream, String path, String contentType)

次の簡単なコントローラーを使用して、アップロードを機能させることができました。

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();
  }

私の懸念は、このソリューションは効率的ではないことです。デフォルトでは、Playフレームワークは、クライアントによってアップロードされたすべてのデータをサーバー上の一時ファイルに保存し、コントローラーのuploadFile()メソッドを呼び出します。

従来のサーブレットアプリケーションでは、次のように動作するサーブレットを作成していました。

myApi.store(request.getInputStream(), ...)

私はどこでも検索してきましたが、解決策は見つかりませんでした。私が見つけた最も近い例は、なぜ呼び出しエラーが発生したり、BodyParserのIterateeで要求がPlay Framework2.0でハングしたりするのですか?しかし、自分のニーズに合うように変更する方法が見つかりませんでした。

play2にこの動作を実現する方法はありますか?つまり、クライアントによってアップロードされたデータを使用して、Webアプリケーションを直接別のシステムに「通過」させる方法はありますか?

ありがとう。

4

1 に答える 1

13

次のScalaコントローラーコードを使用して、サードパーティのAPIにデータをストリーミングすることができました。

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は、サードパーティAPIへの呼び出しを含む非常に単純なJavaクラスです。

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) {}
    }
}

}

アクションへのパラメーターとしてパスを回復することを望んでいたので、完全ではありませんが、それはできませんでした。したがって、入力フィールドの名前(したがってpartName)を更新するJavaScriptを追加しました。これにより、このトリックが実行されます。

于 2012-08-22T12:29:04.750 に答える