Groovy中用于multipart/form-data的编码器函数

3

我需要创建一个'multipart/form-data' REST请求,其中包含jpeg图像和JSON文件作为内容。我卡在将'multipart/form-data'编码为zip文件上。

有人能告诉我如何使用groovy RESTClient实现这一点吗?我找不到任何相关文档。


这是我正在使用的代码:http://www.coderanch.com/t/646732/Groovy/form-multipart-requests-RestClient#2978425。但是我遇到了一个错误:“未找到请求内容类型multipart/form-data的编码器”。 - sailakshmi
我的回答有用吗? - Opal
@opal:感谢您提供的代码。但是我对将两个文件(图像文件和JSON文件)作为单个输入流文件添加到多部分主体中感到困惑。 - sailakshmi
这些应该是两个独立的请求。 - Opal
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - sailakshmi
4个回答

4
正如在 文档 中所看到的,RESTClient 扩展了 HTTPBuilderHTTPBuilder 有一个 getEncoder 方法,可以用于添加专用编码器(具有类型和方法)。请参阅以下代码片段:
import org.codehaus.groovy.runtime.MethodClosure
import javax.ws.rs.core.MediaType

//this part adds a special encoder    
def client = new RESTClient('some host')
client.encoder.putAt(MediaType.MULTIPART_FORM_DATA, new MethodClosure(this, 'encodeMultiPart'))

//here is the method for the encoder added above
HttpEntity encodeMultiPart(MultipartBody body) {
    MultipartEntityBuilder.create()
    .addBinaryBody(
        'file', 
        body.file, 
        ContentType.MULTIPART_FORM_DATA, 
        body.filename
    ).build()
}

//here's how MultipartBody class looks:
class MultipartBody {
   InputStream file
   String filename
}

现在要创建一个多部分请求,您需要将MultipartBody的实例作为请求的正文参数传递。

你能否使用上述代码创建一个带有示例的类? - Talysson de Castro
@TalyssondeCastro,你是什么意思? - Opal

2
我正在使用Groovy rest客户端编写测试以上传.zip文件。
当我使用Groovy Rest Client进行测试时,上述答案都不能直接使用。我不得不对上述答案进行一些调整。我在这里发布,以便某些人想要使用Groovy Rest客户端进行发布可以获益。
import groovyx.net.http.RESTClient
import org.apache.http.HttpEntity
import org.apache.http.entity.mime.MultipartEntityBuilder
import org.codehaus.groovy.runtime.MethodClosure
import static groovyx.net.http.ContentType.JSON

def uploadFile() {
    def httpClient = new RESTClient(this.host)
    File fileToUpload = new File("src/test/resources/fileName.zip")
    httpClient.encoder.putAt(javax.ws.rs.core.MediaType.MULTIPART_FORM_DATA, new MethodClosure(this, 'encodeMultiPart'))
    def multipartBody = new MultipartBody()
    multipartBody.file = new FileInputStream(fileToUpload)
    multipartBody.filename = fileToUpload.name
    def response = httpClient.post(
            path: '/app/uploadfile/path',
            headers: [Accept  : JSON,

                      User    : "user",
                      Password: "password"
              ],
            body: multipartBody,
            requestContentType: 'multipart/form-data')
}

// register multipart encoder
HttpEntity encodeMultiPart(MultipartBody body) {
    MultipartEntityBuilder.create()
            .addBinaryBody(
                    'file',
                    body.file,
                    org.apache.http.entity.ContentType.MULTIPART_FORM_DATA,
                    body.filename
            ).build()
}

class MultipartBody {
    InputStream file
    String filename
}

1

我知道这篇文章有些年头了,但它可能会对其他人有所帮助。虽然问题的答案从初学者的角度回答了它,但要完全理解如何正确地重用上述所有内容仍然很困难。

首先,问题的最后一条评论指向 this link

它试图不正确地重用答案。它将上面的答案与 this link 的答案混合在一起。

def content1 = new ContentDisposition("filename=aa.json")
    def json1 = new File("resources/aa.json")
    def attachments1 = new Attachment("root", new ByteArrayInputStream(json1.getBytes()), content1)
    InputStream is2 = getClass().getResourceAsStream("resources/aa.json");
    InputStream is1 = getClass().getResourceAsStream("resources/img.png");
    ContentDisposition content2 = new ContentDisposition("attachment;filename=img.png")
    Attachment attachments2 = new Attachment("root1", is1, content2)
    def attachments = [attachments1, attachments2]
    def body1 = new MultipartBody(attachments)
    def client = new RESTClient( "https://somehost.com" )
    ocutag.encoder.putAt(MediaType.MULTIPART_FORM_DATA, new MethodClosure(this, 'encodeMultiPart1'))
    ocutag.encoder.putAt(MediaType.MULTIPART_FORM_DATA, new MethodClosure(this, 'encodeMultiPart2'))

上述方法永远不会起作用,我已经将其修改为以下方式:

def http = new RESTClient('http://localhost:8080')
http.encoder.putAt(MediaType.MULTIPART_FORM_DATA, new MethodClosure(this, 'encodeMultiPart'))
def body1 = new MultipartBody()   //This is that MultipartBody class in the first answer example not the one from your imports......
body1.file=file.getInputStream()
body1.filename=file.name
def response = http.put( path: url, body:body1, query:['query':action, ], requestContentType: 'multipart/form-data' )

你还有encodeMultiPart2和encodeMultiPart1,我认为这是一个误解,只需在两种情况下重用此方法的1个声明即可。您不需要执行示例中所述的任何附件等操作。

1

前面的响应中编码器注册非常混乱,这里是我的工作示例:

import org.apache.cxf.jaxrs.ext.multipart.Attachment
import org.apache.cxf.jaxrs.ext.multipart.ContentDisposition
import org.apache.cxf.jaxrs.ext.multipart.MultipartBody
import org.apache.http.entity.ContentType
import org.apache.http.entity.mime.MultipartEntityBuilder
import javax.ws.rs.core.MediaType 

...

def filenameToUpload = "doggo.jpg"
def expectedRequestParamName = "file"

def static uploadFile() {
    // create attachment
    def fileToUpload = new File(filenameToUpload)
    def attachment = new Attachment(expectedRequestParamName, new ByteArrayInputStream(fileToUpload.getBytes()), new ContentDisposition("filename=" + filenameToUpload))
    def body = new MultipartBody(attachment)

    // create REST client
    def httpClient = new RESTClient('http://localhost:8080')

    // register encoder
    httpClient.encoder.putAt(MediaType.MULTIPART_FORM_DATA, customMultipartEncoder)

    // call REST
    httpClient.post(
        path: "upload",
        body: body,
        requestContentType: MediaType.MULTIPART_FORM_DATA)
}

// register multipart encoder
private def static customMultipartEncoder = { body ->
    def builder = MultipartEntityBuilder.create()

    body.allAttachments.collect {
        builder.addBinaryBody(
            it.contentId,
            it.dataHandler.inputStream,
            ContentType.MULTIPART_FORM_DATA,
            it.contentId) }

    return builder.build()
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接