Comment lire plusieurs (fichier) entrées avec le même nom à partir d'un formulaire multipart avec Jersey?

J'ai développé avec succès un service, j'ai lu les fichiers téléchargés dans un formulaire multipart en Jersey. Voici une très version simplifiée de ce que j'ai fait:

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

Cela fonctionne bien mais j'ai reçu une nouvelle exigence. En plus du fichier j'upload, je dois gérer un nombre arbitraire de ressources. Supposons ce sont des fichiers d'image.

J'ai pensé que je venais de fournir au client un formulaire avec une entrée pour le fichier, une entrée pour la première image et un bouton pour autoriser l'ajout de plus d'entrées de la forme (à l'aide d'AJAX ou tout simplement de 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>

De sorte que l'utilisateur peut ajouter de la forme, avec plus d'entrées pour les images, comme ceci:

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

J'espère qu'il sera assez simple pour lire les champs avec le même nom qu'une collection. Je l'ai fait avec succès avec des saisies de texte dans MVC .NET et j'ai pensé qu'il ne serait pas plus difficile à Jersey. Il s'avère que j'ai eu tort.

Ayant pas trouvé de tutoriels sur le sujet, j'ai commencé à expérimenter.

Afin de voir comment faire, j'ai simplifié le problème à un simple texte d'entrées.

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

Évidemment, j'avais besoin d'avoir une sorte de collection en tant que paramètre à ma méthode. Voici ce que j'ai essayé, regroupés par type de collection.

Tableau

Au premier abord, j'ai vérifié si Jersey a été assez intelligent pour gérer un tableau simple:

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

mais le tableau n'était pas injecté comme prévu.

MultiValuedMap

Ayant lamentablement échoué, je me suis souvenu que MultiValuedMap objets pourraient être pris en charge hors de la boîte.

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

mais ça ne fonctionne pas non plus. Cette fois, j'ai eu une exception

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.

M'a dit que cette exception pourrait être éliminé en incluant les mimepull bibliothèque, j'ai donc ajouté ce qui suit dépendance à mon pompon:

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

Malheureusement, le problème persiste. C'est probablement une question de choisir le bon organisme lecteur et à l'aide de différents paramètres pour le générique. Je ne suis pas sûr de la façon de le faire. Je veux consomment à la fois des fichiers et des saisies de texte, ainsi que quelques autres (surtout Long des valeurs et des paramètres personnalisés classes).

FormDataMultipart

Après un peu plus de recherche, j'ai trouvé le FormDataMultiPart classe. J'ai utilisé avec succès pour extraire les valeurs de chaîne à partir de mon formulaire

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

Le problème est que c'est une solution à la version simplifiée de mon problème. Même si je sais que chaque paramètre injecté par Jersey est créé par l'analyse d'une chaîne de caractères à un certain point (pas étonnant, c'est HTTP, après tout) et j'ai une certaine expérience de l'écriture de mon propre paramètre de classes, je n'ai pas vraiment comment faire pour convertir ces champs pour InputStream ou File cas pour la poursuite du traitement.

Par conséquent, avant de plonger dans le Maillot de code source pour voir comment ces objets sont créés, j'ai décidé de demander ici s'il existe un moyen plus facile de lire une série (de taille inconnue) de fichiers. Savez-vous comment résoudre cette énigme?

InformationsquelleAutor toniedzwiedz | 2012-08-25