当前位置: 首页 > 知识库问答 >
问题:

如何使用Jersey从多部分表单读取多个同名(文件)输入?

章岳
2023-03-14

我已经成功地开发了一项服务,在该服务中,我阅读了在泽西岛以多部分形式上传的文件。以下是我所做工作的一个极其简化的版本:

@POST
@Path("FileCollection")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(@FormDataParam("file") InputStream uploadedInputStream,
        @FormDataParam("file") FormDataContentDisposition fileDetail) throws IOException {
    //handle the file
}

这很好,但我有一个新的要求。除了上传的文件,我还需要处理任意数量的资源。假设这些是图像文件。

我想我应该为客户端提供一个表单,其中包含文件的一个输入,第一个图像的一个输入,以及允许向表单添加更多输入的按钮(使用AJAX或简单的纯JavaScript)。

<form action="blahblahblah" method="post" enctype="multipart/form-data">
   <input type="file" name="file" />
   <input type="file" name="image" />
   <input type="button" value="add another image" />
   <input type="submit"  />
</form>

因此,用户可以在表单中附加更多图像输入,如下所示:

<form action="blahblahblah" method="post" enctype="multipart/form-data">
   <input type="file" name="file" />
   <input type="file" name="image" />
   <input type="file" name="image" />
   <input type="file" name="image" />
   <input type="button" value="add another image" />
   <input type="submit"  />
</form>

我希望阅读与集合同名的字段足够简单。我在MVC中成功地完成了文本输入。我想在新泽西不会更难。事实证明我错了。

由于没有找到关于这个主题的教程,我开始尝试。

为了了解如何做到这一点,我将问题简化为简单的文本输入。

<form action="blahblabhblah" method="post" enctype="multipart/form-data">
   <fieldset>
       <legend>Multiple inputs with the same name</legend>
       <input type="text" name="test" />
       <input type="text" name="test" />
       <input type="text" name="test" />
       <input type="text" name="test" />
       <input type="submit" value="Upload It" />
   </fieldset>
</form>

显然,我需要某种类型的集合作为我的方法的参数。这是我尝试的,按集合类型分组。

首先,我检查Jersey是否足够聪明,可以处理一个简单的数组:

@POST
@Path("FileCollection")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(@FormDataParam("test") String[] inputs) {
    //handle the request
}

但是阵列并没有像预期的那样被注入。

惨败之后,我想起了多值map对象可以开箱即用地处理。

@POST
@Path("FileCollection")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(MultiValuedMap<String, String> formData) {
    //handle the request
}

但它也不起作用。这次我有个例外

SEVERE: A message body reader for Java class javax.ws.rs.core.MultivaluedMap, 
and Java type javax.ws.rs.core.MultivaluedMap<java.lang.String, java.lang.String>, 
and MIME media type multipart/form-data; 
boundary=----WebKitFormBoundaryxgxeXiWk62fcLALU was not found.

我被告知可以通过包含mimepull库来消除此异常,因此我向pom添加了以下依赖项:

    <dependency>
        <groupId>org.jvnet</groupId>
        <artifactId>mimepull</artifactId>
        <version>1.3</version>
    </dependency>

不幸的是,问题依然存在。这可能是一个选择正确的身体阅读器和使用不同的参数为通用的问题。我不知道该怎么做。我想使用文件和文本输入,以及其他一些输入(主要是Long值和自定义参数类)。

经过进一步研究,我发现了FormDataMultiPart类。我已经成功地使用它从表单中提取字符串值

@POST
@Path("upload2")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadMultipart(FormDataMultiPart multiPart){
    List<FormDataBodyPart> fields = multiPart.getFields("test");
    System.out.println("Name\tValue");
    for(FormDataBodyPart field : fields){
        System.out.println(field.getName() + "\t" + field.getValue());
        //handle the values
    }
    //prepare the response
}

问题是,这是我问题简化版的解决方案。虽然我知道泽西注入的每个参数都是在某个时候通过解析字符串创建的(难怪,毕竟是HTTP),而且我有一些编写自己参数类的经验,但我真的不知道如何将这些字段转换为InputStreamFile实例进行进一步处理。

因此,在深入研究Jersey源代码以了解如何创建这些对象之前,我决定在这里询问是否有更简单的方法来读取一组(未知大小)文件。你知道如何解决这个难题吗?

共有3个答案

桂坚
2023-03-14

如果有人试图使用与我相同的名称属性来执行通用type=text输入框,您将能够将它们切换到type=hidden输入,并将其作为@FormParam(“inputName”)列表使用

显然,当切换到隐藏输入时,唯一的一点是仍然将数据发送到服务器,而不为其创建UI元素,因此您需要切换到另一个显示UI(例如,我使用button元素来轻松单击以删除功能)。

弓晔
2023-03-14
@Path("/upload/multiples")
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_JSON)
public Response uploadImage(@FormDataParam("image") List<FormDataBodyPart> imageDatas){
   for( FormDataBodyPart imageData : imageDatas ){
       // Your actual code.
       imageData.getValueAs(InputStream.class);
    }
}
荀子轩
2023-03-14

通过以下示例,我找到了解决方案:FormDataMultipart。原来我离答案很近。

FormDataBodyPart类提供了一种方法,允许其用户以InputStream的形式读取值(理论上,也可以是存在消息体读取器的任何其他类)。

以下是最终解决方案:

形式保持不变。我有两个同名的字段,可以在其中放置文件。可以同时使用多个表单输入(从目录上载多个文件时需要这些输入)和多个共享名称的输入(从不同位置上载未指定数量的文件的灵活方式)。还可以使用JavaScript将更多输入附加到表单中。

<form action="/files" method="post" enctype="multipart/form-data">
   <fieldset>
       <legend>Multiple inputs with the same name</legend>
       <input type="file" name="test" multiple="multiple"/>
       <input type="file" name="test" />
       <input type="file" name="test" />
   </fieldset>
   <input type="submit" value="Upload It" />
</form>

下面是一个从多部分表单读取文件集合的简化方法。所有具有相同的输入都被分配到一个列表,它们的值使用FormDataBodyPartgetValueAs方法转换为InputStream。一旦您将这些文件作为InputStream实例,就可以轻松地处理它们。

@POST
@Path("files")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadMultipart(FormDataMultiPart multiPart) throws IOException{        
    List<FormDataBodyPart> fields = multiPart.getFields("test");        
    for(FormDataBodyPart field : fields){
        handleInputStream(field.getValueAs(InputStream.class));
    }
    //prepare the response
}

private void handleInputStream(InputStream is){
    //read the stream any way you want
}

 类似资料:
  • 问题内容: 我已经成功开发了一项服务,可以读取在Jersey中以多部分形式上传的文件。这是我一直在做的极其简化的版本: 这个工作很好,但是给了我一个新的要求。除了要上传的文件之外,我还必须处理任意数量的资源。让我们假设这些是图像文件。 我想我只是为客户提供一个表单,其中包含一个文件输入,一个输入用于第一个图像以及一个按钮,以允许向该表单添加更多输入(使用AJAX或简单的纯JavaScript)。

  • 我正在编写一个Go客户端,通过REST-API创建备份。带有多部分表单数据的REST-API响应到GET请求。因此,响应(类型*http.response)正文的内容如下: 如何从响应正文中提取zip文件? 我试图使用内置(net / http)方法,但这些方法需要一个请求结构。

  • 问题内容: 我有一个带有方法的控制器方法,该方法接收multipart / form-data: 我想使用进行测试。不幸的是创建了一个具有方法的实例: 编辑: 当然,我 不能 创建自己的实现,例如 因为具有包本地构造函数。 但是我想知道是否还有其他更方便的 方法?可以这样做吗,可能是我错过了一些现有的类或方法吗? 问题答案: 是的,有一种方法,而且也很简单! 我自己也遇到了同样的问题。尽管我不满意

  • 我正在尝试使用Support Bee API创建附件,如下所述:https://supportbee.com/api#create_attachment 我编写了一个服务,它使用创建并发送使用文件名的请求。 如果我在《邮递员》中测试,它会成功。我正在为正文使用,只是从UI中选择要上载的文件: 当我试图通过我的服务上传它时,它不起作用: 这将导致500内部服务器错误。检查对象时,我可以看到它的标题值

  • 我想使用一个BufferedReader对象从两个或多个文件中读取文本。

  • 我想让我的Jmeter从一个位置读取多个csv文件,比如C:\Jmeter\file。 当前,如果我在csv数据集配置下的'filename'中提供特定的csv文件名,Jmeter会识别该文件并执行我的脚本。 我不想对文件名进行硬编码,我想让jmeter从该位置自动读取。 我已经编写了BeenShell预处理器(因为我找不到任何简单的解决方案),这个程序从位置读取所有csv文件列表,并将它们存储在