How to read several (file) inputs with the same na

2019-06-27 09:31发布

我已经成功地开发服务,在我读在新泽西州多形式上传的文件。 这里是我一直在做一个非常简化的版本:

@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 .NET文本输入成功地做到了,我认为这不会在泽西更难。 事实证明我错了。

在发现没有关于该问题的教程,我开始试验。

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

<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>

很显然,我需要有某种形式的集合作为参数传递给我的方法。 这里是我的尝试,通过集合类型进行分组。

排列

起初,我检查是否泽西足够聪明来处理一个简单的数组:

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

但如预期未注入的阵列。

MultiValuedMap

已经悲惨地失败了,我记得MultiValuedMap对象可以开箱处理。

@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

一些研究之后,我发现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进行进一步的处理实例。

因此,在深入泽西源代码,看看如何创建这些对象之前,我决定在这里问是否有读一组文件(未知大小)的简单方法。 你知道如何解决这个难题?

Answer 1:

我已经在与例子找到了解决办法FormDataMultipart 。 原来我是非常接近的答案。

所述FormDataBodyPart类提供一种方法,其允许其用户读取的值作为InputStream (或理论上,任何其他类,针对其消息体读取器存在的话)。

下面是最终的解决方案:

形成

形式保持不变。 我有一对夫妇使用相同的名称,我在其中可以放置文件的字段。 它可以同时使用multiple共享一个名字(灵活的方式来上传文件的不同位置上的数目不详)的形式输入(从目录中上传多个文件时,你想这些),和大量的投入。 它也可以附加使用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>

服务-使用FormDataMultipart

下面是从多形式读取文件的集合的简化方法。 用相同的所有输入被分配给List和它们的值被转换成InputStream使用getValueAs的方法FormDataBodyPart 。 一旦你有这些文件作为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
}


Answer 2:

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


Answer 3:

如果有人试图做通用type=text输入框使用相同的name属性,好像我是,你将能够切换他们type=hidden输入功能,并且这项工作提供了@FormParam("inputName") List<String> nameList在你的路线。

显然,在切换到隐藏输入时的唯一点是静止的数据发送到所述服务器,而无需为它创建的UI元素,因此将需要切换到备用显示UI(例如,我使用的按钮元件为轻松点击-to-删除功能)。



文章来源: How to read several (file) inputs with the same name from a multipart form with Jersey?