如何用jersey从一个多部分表单中读取几个同名的(文件)输入?

6ju8rftf  于 2021-07-09  发布在  Java
关注(0)|答案(3)|浏览(353)

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

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

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

数组

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

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

但数组没有按预期注入。

多值Map

由于惨败,我记得 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类。我已经成功地使用它从表单中提取字符串值

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

问题是,这是我问题的简化版本的解决方案。虽然我知道jersey注入的每个参数都是通过在某个点解析字符串(难怪,它毕竟是http)来创建的,而且我有一些编写自己的参数类的经验,但我不知道如何将这些字段转换为 InputStream 或者 File 进一步处理的示例。
因此,在深入了解jersey源代码以了解这些对象是如何创建的之前,我决定在这里询问是否有更简单的方法来读取一组(大小未知)文件。你知道如何解决这个难题吗?

00jrzges

00jrzges1#

如果有人想做 type=text 输入框与 name 像我一样,你可以把它们换成 type=hidden 并将其作为 @FormParam("inputName") List<String> nameList 在你的路线上。
显然,当切换到隐藏输入时,唯一的一点是仍然将数据发送到服务器,而不为其创建ui元素,因此您将需要切换到另一个显示ui(例如,我使用了一个button元素来轻松单击以删除功能)。

hiz5n14c

hiz5n14c2#

我已经找到了解决办法,按照下面的例子 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
}
mftmpeh8

mftmpeh83#

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

相关问题