我已经成功地开发了一个服务,在该服务中,我可以读取在泽西岛以多部分形式上传的文件。以下是我一直在做的一个极其简化的版本:
@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源代码以了解这些对象是如何创建的之前,我决定在这里询问是否有更简单的方法来读取一组(大小未知)文件。你知道如何解决这个难题吗?
3条答案
按热度按时间00jrzges1#
如果有人想做
type=text
输入框与name
像我一样,你可以把它们换成type=hidden
并将其作为@FormParam("inputName") List<String> nameList
在你的路线上。显然,当切换到隐藏输入时,唯一的一点是仍然将数据发送到服务器,而不为其创建ui元素,因此您将需要切换到另一个显示ui(例如,我使用了一个button元素来轻松单击以删除功能)。
hiz5n14c2#
我已经找到了解决办法,按照下面的例子
FormDataMultipart
. 原来我离答案很近。这个
FormDataBodyPart
类提供了一个方法,该方法允许其用户将值作为InputStream
(或理论上,任何其他类,其中存在消息体读取器)。以下是最终解决方案:
形式
形式不变。我有几个同名的字段,可以在其中放置文件。两者都可以使用
multiple
表单输入(当从一个目录上传多个文件时需要这些输入)和共享一个名称的多个输入(从不同位置上传未指定数量的文件的灵活方式)。也可以使用javascript在表单中附加更多的输入。服务-使用formdatamultipart
下面是一个从多部分窗体读取文件集合的简化方法。所有具有相同的输入都分配给
List
它们的值被转换为InputStream
使用getValueAs
方法FormDataBodyPart
. 一旦你把这些文件作为InputStream
例如,用它们做任何事情都很容易。mftmpeh83#