2012-08-22 15 views
12

Ich schreibe eine Play 2.0 Java-Anwendung, mit der Benutzer Dateien hochladen können. Diese Dateien auf einem Drittdienst gespeichert werden ich eine Java-Bibliothek zugreifen, wobei das Verfahren I in dieser API verwenden, hat die folgende Signatur:Hochladen von Datei als Stream in Play Framework 2.0

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

Ich habe es geschafft, Uploads, um die Arbeit der folgenden einfachen 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(); 
    } 

Meine Sorge ist, dass diese Lösung, weil standardmäßig nicht effizient ist das Spiel Rahmen speichert alle vom Kunden in einer temporären Datei auf dem Server hochgeladen Daten dann meinen upload Anrufe() -Methode in der Steuerung.

In einem traditionellen Servlet-Anwendung würde ich auf diese Weise ein Servlet geschrieben haben, verhalten:

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

Ich habe überall gesucht, und keine Lösung gefunden hat. Das nächste Beispiel, das ich gefunden habe, ist Why makes calling error or done in a BodyParser's Iteratee the request hang in Play Framework 2.0?, aber ich habe nicht herausgefunden, wie ich es an meine Bedürfnisse anpassen kann.

Gibt es einen Weg in play2, um dieses Verhalten zu erreichen, d. H., Die vom Client hochgeladenen Daten sollen direkt durch die Web-Anwendung auf ein anderes System übertragen werden?

Danke.

Antwort

12

Ich habe in der Lage Daten zu meinem Drittanbieter-API mit dem folgenden Scala Controller-Code zu streamen:

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

Die UploadFileWorker ist eine wirklich einfache Java-Klasse, die den Aufruf des thrid-Party-API enthält .

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

}

Es ist nicht ganz perfekt, weil ich vorgezogen hätte, den Pfad als Parameter für die Aktion zu gewinnen, aber ich habe nicht in der Lage, dies zu tun. Ich habe also ein Stück Javascript hinzugefügt, das den Namen des Eingabefeldes (und somit den PartName) aktualisiert und es macht den Trick.

+0

Gibt es das in Java statt in Scala? :( – by0

Verwandte Themen