uploading multiple files with same name

18 / Nov / 2011 by Bhagwat Kumar 0 comments

A good binding feature in grails is that when you have multiple input fields with same name, they are available as a list in params. But this does not hold with html file input fileds. If you have multiple file input fields with same name, params.fieldName will not return a list but the first input field with name fieldName. This is due to using fileMap attribute of request object. Here is the relevant part of GrailsParameterMap class(I suspected this class because of params.getClass() returned GrailsParameterMap) :

[groovy]
GrailsParameterMap(HttpServletRequest request) {
//………………………..
if (request instanceof MultipartHttpServletRequest) {
def fileMap = request.fileMap
for (fileName in fileMap.keySet()) {
requestMap.put(fileName, request.getFile(fileName))
}
}
//………………………..
}
[/groovy]
Due to above implementation, If you have three file input fields with name familyPics, only the first one will be available via params.familyPics of type CommonsMultipartFile.

In one of the mail thread(links at the end of the blog), I got to know that grails uses Spring 3.0 starting from grails version 1.2 which supports multiFileMap attribute in request object. Using this attribute you can access multiple files from inputs with the same name (or that uses the HTML5 multiple attribute). So if the implementation is changed to something like :
[groovy]
GrailsParameterMap(HttpServletRequest request) {
//………………………..
if (request instanceof MultipartHttpServletRequest) {
def multipleFileMap = request.multiFileMap
/* instead of using fileMap. However this map value is always a list even if there is only one file input for a name */
multipleFileMap.each {fieldName, files ->
if (files.size() == 1) {
requestMap.put(fieldName, files.first())
/* Make this available as a single element instead of list, if the user wants he can use params.list(‘fieldName’) for list version */
} else {
requestMap.put(fieldName, files)
}
}
}
//………………………..
}
[/groovy]
Then if there are three file input fields with name familyPics, then params.familyPics will return a list of CommonsMultipartFile objects. If there is only one file input field with name profilePic then params.profilePic will return an object of type CommonsMultipartFile and params.list('profilePic') will return a list of CommonsMultipartFile objects.

This feature can be added using Groovy/Grails MetaProgramming(Until grails is updated for this feature). However I went with Grails Filter solution. Create/update a filter with this entry :

[groovy]
multipartFileSupport(controller: ‘*’, action: ‘*’) {
before = {
if (request instanceof MultipartHttpServletRequest) {
def multipleFileMap = request.multiFileMap
multipleFileMap.each {fieldName, files ->
if (files.size() == 1) {
params.put(fieldName, files.first())
} else {
params.put(fieldName, files)
}
}
}
}
}
[/groovy]

Now inside any controller/action you can access statements like(even grails auto binding will work fine) :
[groovy]
/* Suppose there is a file input field with name profilePic */
CommonsMultipartFile profilePic=params.profilePic
List<CommonsMultipartFile> profilePicAsList=params.list(‘profilePic’)

/* Suppose there are three file input fields with same name familyPics */
List<CommonsMultipartFile> familyPics=params.familyPics
[/groovy]

Hope this feature will be available soon in grails without having to write filters or doing meta programming.

Helpful links :

http://stackoverflow.com/questions/3710232/how-to-iterate-over-uploaded-files-in-grails

http://forum.springsource.org/showthread.php?44632-CommonsMultipartResolver-Uploading-many-files-with-same-html-name

~~~~~~Cheers~~~~~~~
Bhagwat Kumar
bhagwat(at)intellligrape(dot)com

FOUND THIS USEFUL? SHARE IT

Leave a Reply

Your email address will not be published. Required fields are marked *