Как прочитать несколько (файловых) входов с одинаковым именем из составной формы с Джерси?

Я успешно разработал сервис, в котором я читаю файлы, загруженные в многочастной форме на Джерси. Вот очень упрощенная версия того, что я делал:

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

Очевидно, мне нужно было иметь какую-то коллекцию в качестве параметра для моего метода. Вот что я пробовал, сгруппированный по типу коллекции.

Array

Сначала я проверил, достаточно ли у Джерси умение работать с простым массивом:

@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), и у меня есть некоторый опыт написания собственных классов параметров, я действительно не понимаю, как преобразовать эти строки. поля дляInputStream или жеFile экземпляры для дальнейшей обработки.

Поэтому, прежде чем погрузиться в исходный код Джерси, чтобы увидеть, как создаются эти объекты, я решил спросить здесь, существует ли более простой способ чтения набора (неизвестного размера) файлов. Вы знаете, как решить эту головоломку?

Ответы на вопрос(3)

Ваш ответ на вопрос