To illustrate the problem, suppose you need to process form data that include a file upload along with some other information, perhaps a keyword designation for the file. Your HTML <form> element might look something like this.
<form id="upload" enctype="multipart/form-data" method="post" action="upload"> Keyword: <input name="keyword" /><br /> File:<br/> <input type="file" name="file" size="44"/><br/> <input type="submit" value="Upload file" /><br /> </form>
And the (simplified) Java code you use to handle the form data might look like this.
@POST @Path("upload") @Consumes(MediaType.MULTIPART_FORM_DATA) public DataFile upload( @FormDataParam("keyword") String keyword, @FormDataParam("file") InputStream file_in, @FormDataParam("file") FormDataContentDisposition contentdisp) throws Exception { // Do something with the form data... }
That should all work fine, but what if you want to let users provide an arbitrary number of keywords, using a separate input box for each keyword? You could write some javascript to allow the user to click a "more keywords" button that adds more input boxes to the form. Then, your form would effectively look something like the following.
<form id="upload" enctype="multipart/form-data" method="post" action="upload"> Keyword: <input name="keywords" /><br /> Keyword: <input name="keywords" /><br /> Keyword: <input name="keywords" /><br /> <!-- Could be any number of keyword elements here... --> File:<br/> <input type="file" name="file" size="44"/><br/> <input type="submit" value="Upload file" /><br /> </form>
How should you handle this on the server side? The obvious solution is to specify a parameter that is a List, like this.
@POST @Path("upload") @Consumes(MediaType.MULTIPART_FORM_DATA) public DataFile upload( @FormDataParam("keywords") List<String> keywords, @FormDataParam("file") InputStream file_in, @FormDataParam("file") FormDataContentDisposition contentdisp) throws Exception { // Do something with the form data... }
Unfortunately, this straightforward approach doesn't work for MediaType.MULTIPART_FORM_DATA, even though it works fine for other media types. The trick is to replace the "keywords" parameter with a List of FormDataBodyPart objects. Then, we can extract the keyword String from each FormDataBodyPart. In the following example, the extracted keyword strings are placed into another List.
@POST @Path("upload") @Consumes(MediaType.MULTIPART_FORM_DATA) public DataFile upload( @FormDataParam("keywords") List<FormDataBodyPart> bparts, @FormDataParam("file") InputStream file_in, @FormDataParam("file") FormDataContentDisposition contentdisp) throws Exception { // Get the keyword strings. ArrayList<String> keywords = new ArrayList<String>(); for (FormDataBodyPart bpart : keywords) keywords.add(bpart.getValueAs(String.class)); // Do something with the form data... }
And that should work. It's a bit awkward, but still a fairly simple solution. Finally, I must acknowledge these two threads, which provided the clues I needed to figure this out.
Nice one! was going mental trying to process a List in multi-part form. thanks
ReplyDeleteYou bet! I'm glad somebody else found this useful.
DeleteHuge thanks! I've been looking for this solution for a couple hours.
ReplyDelete