2012-06-05 12 views
8

Java Httpリクエストでは、マルチパートHTTP POSTを行うことができます。Play 2.0 WS.urlまたはWS.WSRequestを使用してMultipartFormDataを投稿する方法

HttpClient httpclient = new DefaultHttpClient(); 
HttpPost httppost = new HttpPost(url); 

FileBody bin = new FileBody(new File(fileName)); 
StringBody comment = new StringBody("Filename: " + fileName); 

MultipartEntity reqEntity = new MultipartEntity(); 
reqEntity.addPart("bin", bin); 
reqEntity.addPart("comment", comment); 
httppost.setEntity(reqEntity); 

HttpResponse response = httpclient.execute(httppost); 
HttpEntity resEntity = response.getEntity(); 

WS.urlまたはWS.WSRequestを使用して同じ結果を達成するにはどうすればよいですか?

WSRequestHolder wsReq = WS.url("http//url");    
wsReq.setHeader("Content-type", "multipart/form-data"); 

答えて

5

これはややこしく、間違いなくクリーンアップすることができますが、ここで私はそれを動作させるために何をしましたか?これをもっと良くするために自由に感じてください。

これは、すべてのプレイですでに2.0フレームワークを片を用いている
import java.io.ByteArrayInputStream; 
import java.io.ByteArrayOutputStream; 

import play.libs.WS; 

import com.ning.http.multipart.FilePart; 
import com.ning.http.multipart.MultipartRequestEntity; 
import com.ning.http.multipart.Part; 

ByteArrayOutputStream bos = new ByteArrayOutputStream(); 

// Build up the Multiparts 
List<Part> parts = new ArrayList<>(); 
parts.add(new FilePart("file", new File(filename))); 
Part[] partsA = parts.toArray(new Part[parts.size()]); 

// Add it to the MultipartRequestEntity 
MultipartRequestEntity reqE = new MultipartRequestEntity(partsA, null); 
reqE.writeRequest(bos); 
InputStream reqIS = new ByteArrayInputStream(bos.toByteArray()); 
WS.WSRequestHolder req = WS.url(InterchangeConfig.conflateUrl+"dataset") 
    .setContentType(reqE.getContentType()); 
req.post(reqIS).map(...); 
// or req.post(reqIS).get(); 

+0

これはPlay 2.2で私たちのために働いていましたが、 'play.libs.ws'の変更を修正した後でさえ、Play 2.3で壊れているようです。理由を推測してみてください。 –

+0

@EricWilsonあなたは「壊れた」よりも具体的になりますか? – nafg

+0

申し訳ありませんが、私はもうプレイをしませんし、そのコードにアクセスすることはできません。 –

0

再生APIドキュメントに基づいて、マルチパートPOST本体の組み込みがないようです。

しかし、あまりにもあなたの好みのタイプT、および対応する書き込み可能とContentTypeOf種類の方法に

post[T](body: T)(implicit wrt: Writeable[T], ct: ContentTypeOf[T]): Future[Response] 

を使用して、独自のマルチパートの体を作成することも可能です。

しかし、これは、マルチパート本体がHTTPで動作する仕組みを掘り下げることを意味します。

+0

例を共有できますか? – angelokh

+0

実際、私はあなたにScala APIを示しました。あなたはJavaを使用しているようです、ごめんなさい。 Javaでは、post(InputStream)メソッドがあります。おそらく入力ストリームに適切なコンテンツを作成することができます:) –

+0

@angelokh:ここに例があります:http://cdmckay.org/blog/2015/06/24/how-to-add-support-for-posting- – cdmckay

3

外部ライブラリに依存することなく、今のところ唯一の解決策は、マルチパートフォームデータリクエストを手動で作成しているようです。

WSRequestHolder wsRequestHolder = WS.url(URL); 

String boundary = "--XYZ123--"; 

String body = ""; 
for (String key : data.keySet()) { 
    body += "--" + boundary + "\r\n" 
     + "Content-Disposition: form-data; name=\"" 
     + key + "\"\r\n\r\n" 
     + data.get(key) + "\r\n"; 
} 
body += "--" + boundary + "--"; 

wsRequestHolder.setHeader("Content-Type", "multipart/form-data; boundary=" + boundary); 
wsRequestHolder.setHeader("Content-length", String.valueOf(body.length())); 

wsRequestHolder.post(body); 

dataは、フォームパラメータとして渡したいすべての名前/値のペアを含むjava.util.Map<String, String>次のようになります。これは、play.libs.WS.urlを使用して行うことができる方法の例です。 randomStringは、境界から要求に変更するランダム化された値です。バイナリデータの追加も同じように動作します。

このhttp://www.htmlcodetutorial.com/forms/form_enctype.htmlは、仕様を理解するのに参考になる場所です。

0

Romain Sertelonが示唆したように、このケースを処理するためにWriteableを書くことができます。ここでは一つだ、私は書いた:

package utilities 

import java.io.{ByteArrayOutputStream, File} 

import com.ning.http.client.FluentCaseInsensitiveStringsMap 
import com.ning.http.multipart.{MultipartRequestEntity, FilePart, StringPart} 
import play.api.http.HeaderNames._ 
import play.api.http.{ContentTypeOf, Writeable} 
import play.api.mvc.{Codec, MultipartFormData} 

object MultipartFormDataWriteable { 

    implicit def contentTypeOf_MultipartFormData[A](implicit codec: Codec): ContentTypeOf[MultipartFormData[A]] = { 
     ContentTypeOf[MultipartFormData[A]](Some("multipart/form-data; boundary=__X_PROCESS_STREET_BOUNDARY__")) 
    } 

    implicit def writeableOf_MultipartFormData(implicit contentType: ContentTypeOf[MultipartFormData[File]]): Writeable[MultipartFormData[File]] = { 
     Writeable[MultipartFormData[File]]((formData: MultipartFormData[File]) => { 

      val stringParts = formData.dataParts flatMap { 
       case (key, values) => values map (new StringPart(key, _)) 
      } 

      val fileParts = formData.files map { filePart => 
       new FilePart(filePart.key, filePart.ref, filePart.contentType getOrElse "application/octet-stream", null) 
      } 

      val parts = stringParts ++ fileParts 

      val headers = new FluentCaseInsensitiveStringsMap().add(CONTENT_TYPE, contentType.mimeType.get) 
      val entity = new MultipartRequestEntity(parts.toArray, headers) 
      val outputStream = new ByteArrayOutputStream 
      entity.writeRequest(outputStream) 

      outputStream.toByteArray 

     })(contentType) 
    } 

} 

はここでそれを使用する方法は次のとおりです。ファイルのアップロード中に

import utilities.MultipartFormDataWriteable._ 

... 

val url = "https://example.com" 

val dataParts = Map(
    "foo" -> Seq("bar"), 
    "alice" -> Seq("bob") 
) 

val file = new jave.io.File(... path to a jpg ...) 
val fileParts = Seq(new FilePart("attachment", "foo.jpg", Some("image/jpeg"), file) 

val multipartFormData = MultipartFormData(dataParts, fileParts, Seq(), Seq()) 

WS.url(url).post(multipartFormData) 
+0

本当に素晴らしいアイデア!しかし、もはやコンパイルされません。あなたは 'import com.ning.http.client.multipart ...'を意味しましたか?また、 'stringParts ++ fileParts'は、Seq [FilePart]にStringPartを追加し、Seq [BasePart]につなぎます。 'MultipartRequestEntity'はutil.List [Part]を必要とします(配列[PartBase]ではありません)。最新のPlayリリース2.4.6でコンパイルできますか? –

3

の作業例をプレイ2.3のためのアプローチの上に使用して、またのcontentTypeを追加しました。

public Promise<WSResponse> upload(Http.MultipartFormData.FilePart policyFilePart, String contentType) { 
    ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
    List<Part> parts = new ArrayList<>(); 
    try { 
     parts.add(new FilePart("file", policyFilePart.getFile(), contentType, null)); 
     parts.add(new StringPart("param1", "value1")); 
     parts.add(new StringPart("param2", "value2")); 
     Part[] partsA = parts.toArray(new Part[parts.size()]); 

     // Add it to the multipart request entity 
     MultipartRequestEntity requestEntity = new MultipartRequestEntity(partsA, new FluentCaseInsensitiveStringsMap()); 
     requestEntity.writeRequest(bos); 
     InputStream reqIS = new ByteArrayInputStream(bos.toByteArray()); 
     return WS.url(baseUrl + "upload") 
       .setContentType(requestEntity.getContentType()) 
       .post(reqIS).map(new Function<WSResponse, WSResponse>() { 
        @Override 
        public WSResponse apply(WSResponse wsResponse) throws Throwable { 
          return wsResponse; 
        } 
       }); 
    } catch (IOException e) { 
     e.printStackTrace(); 
     return null; 
    } 
} 
+0

ソリューションへのリンクは歓迎しますが、あなたの答えはそれが無ければ有用であることを確認してください:[リンクの前後にコンテキストを追加](// meta.stackexchange.com/a/8259)あなたの仲間のユーザーは、なぜそれがあるのか​​、ターゲットページが利用できない場合にリンクしているページの最も関連性の高い部分を引用します。 [リンク以上の回答は削除される可能性があります。](// stackoverflow.com/help/deleted-answers) –

+0

@ M.A.R。私はリンクを削除しました、代わりに私はここにコードを書いた –

+0

ありがとう!ずっといい。 –

関連する問題