Playframework 2.0 播放2.0如何使用WS.url或WS.WSRequest发布MultipartFormData
在JavaHTTP请求中,我们可以这样做以使多部分Http POSTPlayframework 2.0 播放2.0如何使用WS.url或WS.WSRequest发布MultipartFormData,playframework-2.0,Playframework 2.0,在JavaHTTP请求中,我们可以这样做以使多部分Http POST HttpClient httpclient = new DefaultHttpClient(); HttpPost httppost = new HttpPost(url); FileBody bin = new FileBody(new File(fileName)); StringBody comment = new StringBody("Filename: " + fileName); MultipartEntit
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");
根据PlayAPI文档,似乎没有内置的多部分POST主体 但是,可以使用该方法创建自己的多部分主体
post[T](body: T)(implicit wrt: Writeable[T], ct: ContentTypeOf[T]): Future[Response]
使用您选择的T类型,以及相应的Writeable和ContentTypeOf类型
但这意味着要深入研究多部分实体如何与HTTP一起工作。这太草率了,而且肯定可以清理,但下面是我为让它工作所做的。让这一切变得更好吧
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();
import java.io.ByteArrayInputStream;
导入java.io.ByteArrayOutputStream;
导入play.libs.WS;
导入com.ning.http.multipart.FilePart;
导入com.ning.http.multipart.MultipartRequestEntity;
导入com.ning.http.multipart.Part;
ByteArrayOutputStream bos=新建ByteArrayOutputStream();
//建立多部分
列表部件=新的ArrayList();
添加(新文件部分(“文件”,新文件(文件名));
零件[]零件SA=零件.toArray(新零件[parts.size()]);
//将其添加到MultipartRequestEntity
MultipartRequestEntity reqE=新的MultipartRequestEntity(partsA,null);
要求书面请求(bos);
InputStream Requis=新的ByteArrayInputStream(bos.toByteArray());
WS.WSRequestHolder req=WS.url(InterchangeConfig.conflateUrl+“数据集”)
.setContentType(reque.getContentType());
要求职位(要求职位)地图(…);
//或req.post(reqIS.get();
这都是使用Play 2.0框架中已有的片段。目前唯一的解决方案,不依赖外部库,似乎是手动创建多部分表单数据请求。这是一个如何使用
play.libs.WS.url
实现的示例:
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
,其中包含要作为表单参数传递的所有名称/值对randomString
是一个随机化值,用于在不同请求之间更改边界。添加二进制数据也会以同样的方式工作
这是一个了解规范的好地方。正如Romain Sertelon所建议的,您可以编写一个可写的程序来处理这种情况。这是我写的一封信:
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)
使用上述方法的Play2.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;
}
}
公共承诺上载(Http.MultipartFormData.FilePart-policyFilePart,String-contentType){
ByteArrayOutputStream bos=新建ByteArrayOutputStream();
列表部件=新的ArrayList();
试一试{
添加(新文件部分(“文件”,policyFilePart.getFile(),contentType,null));
增加(新的StringPart(“参数1”,“值1”));
添加(新的StringPart(“参数2”,“值2”));
零件[]零件SA=零件.toArray(新零件[parts.size()]);
//将其添加到多部分请求实体
MultipartRequestEntity requestEntity=新的MultipartRequestEntity(partsA,新的FluentCaseInsensitiveStringsMap());
requestEntity.writeRequest(bos);
InputStream Requis=新的ByteArrayInputStream(bos.toByteArray());
返回WS.url(baseUrl+“上传”)
.setContentType(requestEntity.getContentType())
.post(requis).map(新函数(){
@凌驾
公共WSResponse应用(WSResponse WSResponse)抛出可丢弃{
返回wsResponse;
}
});
}捕获(IOE异常){
e、 printStackTrace();
返回null;
}
}
接受的答案与播放2.5不兼容。文档中的答案也不适用于2.5。
以下方法效果良好:
Http.MultipartFormData.FilePart part = new Http.MultipartFormData.FilePart("fileKey",
"abc.zip", "multipart/form-data",
FileIO.fromFile(new File("/home/testData/abc.zip")));
List<Http.MultipartFormData.Part<Source<ByteString, ?>>> data = Arrays.asList(part);
Http.RequestBuilder requestBuilder = AuthFakeRequest.getAuthFakeRequest(routes.MyController.uploadZip()).method(POST)
.bodyMultipart(data, mat);
Result result = route(app, requestBuilder);
Http.MultipartFormData.FilePart=new Http.MultipartFormData.FilePart(“fileKey”,
“abc.zip”、“多部分/表单数据”,
FileIO.fromFile(新文件(“/home/testData/abc.zip”);
列表数据=数组.asList(部分);
Http.RequestBuilder RequestBuilder=AuthFakeRequest.getAuthFakeRequest(routes.MyController.uploadZip()).method(POST)
.bodyMultipart(数据、mat);
结果=路线(应用程序、requestBuilder);
对于
mat
和app
对象,它们是在继承play.test.WithApplication
类时获得的。您可以分享一个示例吗?事实上,我已经向您展示了Scala API,您似乎在使用Java,对不起。在Java中,有一个post(InputStream)方法。也许你可以在输入流中创建正确的内容:)@angelokh:这里有一个例子:这在Play 2.2中对我们有效,但在Play 2.3中似乎已经失效。。。即使在修复了play.libs.ws
更改之后。非常感谢您的猜测。@EricWilson您能比“断开”更具体一点吗?对不起,我不再使用play,也没有访问该代码的权限。查看MultipartRequestEntity的源代码,如果您为Headers传递null,它看起来会爆炸。类似的东西在scala中对我适用。对于第二个ctor参数,我编写了新的FluentCaseInsensitiveStringsMap,我发布了如下内容:.post(baos.toByteArray())(Writeable.wBytes,ContentTypeOf(Some(mpre.getContentType))
真是个好主意!不过,它不再编译。您的意思是导入com.ning.http.client.multipart…?另外,stringParts++fileParts
将StringPart添加到Seq[FilePart],从而生成Seq[BasePart]MultipartRequestEntity
需要util.List[Part](而不是数组[PartBase])。它是否在最新的Play release 2.4.6中为您编译?欢迎提供指向解决方案的链接,但请确保您的答案在没有它的情况下是有用的:这样您的其他用户就会知道它是什么以及为什么存在,然后引用您链接到的页面的最相关部分,以防目标页面不可用@M.A.R.我已经删除了链接,而是在这里编写了代码only@live_alone我试图在游戏2.4中使用这个,但是由于