2012-08-22 61 views
12

我正在編寫允許用戶上傳文件的play 2.0 java應用程序。這些文件都存儲在第三方服務,我訪問使用Java庫,我這個API中使用的方法具有以下特徵:在播放框架2.0中作爲流上傳文件

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

我擔心的是,這個解決方案不是有效的,因爲在默認情況下發揮框架存儲由客戶端服務器上的臨時文件上傳的所有數據,然後叫我uploadFile()控制器方法。

在我會寫一個servlet表現這樣一個傳統的servlet應用:

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

我一直在到處尋找,並沒有發現任何解決方案。我發現的最接近的例子是Why makes calling error or done in a BodyParser's Iteratee the request hang in Play Framework 2.0?,但我沒有找到如何修改它以適應我的需求。

play2有沒有辦法實現這種行爲,即讓客戶端上傳的數據直接通過網絡應用程序直接轉到另一個系統?

謝謝。

回答

12

我已經能夠使用下面的斯卡拉控制器代碼到數據流到我的第三方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是包含調用THRID第三方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) {} 
    } 
} 

}

這不是完全完美的,因爲我本來希望恢復路徑作爲參數來操作,但我一直沒能如願。因此,我添加了一段JavaScript,它更新了輸入字段的名稱(因此更新了partName),並且它實現了訣竅。

+0

無論如何要在Java而不是Scala中做到這一點? :( – by0