2012-08-22 10 views
12

Sto scrivendo un'applicazione java di gioco 2.0 che consente agli utenti di caricare file. Questi file sono memorizzati su un servizio di terze parti accedo utilizzando una libreria Java, il metodo che uso in questa API ha la seguente firma:Caricamento file come stream in gioco framework 2.0

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

Sono riuscito a fare upload di lavoro utilizzando il seguente controller semplice:

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

la mia preoccupazione è che questa soluzione non è efficace perché per impostazione predefinita i negozi quadro di gioco tutti i dati caricati dal cliente in un file temporaneo sul server poi chiama il metodo mia UploadFile() nel controller.

In un'applicazione servlet tradizionale avrei scritto un servlet comportarsi in questo modo:

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

ho cercato dappertutto e non ho trovato alcuna soluzione. L'esempio più vicino che ho trovato è Why makes calling error or done in a BodyParser's Iteratee the request hang in Play Framework 2.0? ma non ho trovato come modificarlo per adattarlo alle mie esigenze.

Esiste un modo per giocare in questo gioco2, ovvero disporre dei dati caricati dal client per passare "attraverso" l'applicazione Web direttamente a un altro sistema?

Grazie.

risposta

12

Sono stato in grado di trasmettere i dati al mio API di terze parti utilizzando il seguente codice del controller Scala:

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

L'UploadFileWorker è davvero semplice classe Java che contiene la chiamata al API thrid-party .

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

}

Non è completamente perfetto, perché avrei preferito di recuperare il percorso come parametro per l'azione, ma non sono stato in grado di farlo. Ho quindi aggiunto un pezzo di javascript che aggiorna il nome del campo di input (e quindi il nomepart) e fa il trucco.

+0

Esiste comunque la possibilità di farlo in Java anziché in Scala? :( – by0

Problemi correlati