Tuesday, October 12, 2010

Uploading Files in Grails

Here's the slides from a presentation I did at the UGGUG in May 2010. I found that I needed to use it again today so I posted it.

Here is the source code for the uploader service I created:

package berry
import org.springframework.web.multipart.MultipartFile
import org.codehaus.groovy.grails.web.context.ServletContextHolder
class FileUploadService {
boolean transactional = true
def String uploadFile(MultipartFile file, String name, String destinationDirectory) {
def servletContext = ServletContextHolder.servletContext
def storagePath = servletContext.getRealPath(destinationDirectory)
// Create storage path directory if it does not exist
def storagePathDirectory = new File(storagePath)
if (!storagePathDirectory.exists()) {
print "CREATING DIRECTORY ${storagePath}: "
if (storagePathDirectory.mkdirs()) {
println "SUCCESS"
} else {
println "FAILED"
}
}
// Store file
if (!file.isEmpty()) {
file.transferTo(new File("${storagePath}/${name}"))
println "Saved file: ${storagePath}/${name}"
return "${storagePath}/${name}"
} else {
println "File ${file.inspect()} was empty!"
return null
}
}
}

A tip that you may enjoy is the way I implemented this uploader into a real world application. I wanted to be able to upload files into a folder within the web-app folder for development, but in production, I wanted to put it in a folder that is served via Tomcat directly. So on our production server, I created a folder at /opt/assets and created a symbolic link in the $TOMCAT_ROOT/webapps/assets to point to it. I modified the service as follows:

package berry
import org.springframework.web.multipart.MultipartFile
import org.codehaus.groovy.grails.web.context.ServletContextHolder
import grails.util.GrailsUtil
class FileUploadService {
boolean transactional = true
def String uploadFile(MultipartFile file, String name) {
String storagePath = ""
if (GrailsUtil.environment == "production") {
storagePath = "/opt/assets"
} else {
def servletContext = ServletContextHolder.servletContext
storagePath = servletContext.getRealPath('assets')
}
// Create storage path directory if it does not exist
def storagePathDirectory = new File(storagePath)
if (!storagePathDirectory.exists()) {
print "CREATING DIRECTORY ${storagePath}: "
if (storagePathDirectory.mkdirs()) {
println "SUCCESS"
} else {
println "FAILED"
}
}
// Store file
if (!file.isEmpty()) {
file.transferTo(new File("${storagePath}/${name}"))
println "Saved file: ${storagePath}/${name}"
return "${storagePath}/${name}"
} else {
println "File ${file.inspect()} was empty!"
return null
}
}
}

I then create a folder in my web-app folder named 'assets', being sure to add it to my ignore list for the repository. So once I upload the file, it will save to the correct location.

Now to view the image, all I have to do is the following:

<img src="${resource(dir:'assets', file: 'myfile.jpg')}" />
view raw img.html hosted with ❤ by GitHub

This now will work in both DEVELOPMENT and PRODUCTION enviroments.

http://github.com/cavneb/FileUploader

4 comments:

  1. Many Grails learners like me would have same problem I got when try to upload huge file.

    So I found a solution and share:

    To increase/set the limit of file size to be uploaded, add resources.xml in /con/spring/


    1000000


    S.Kim

    ReplyDelete
  2. Ok... tags in comment are not allowed... so here is the related link: http://tinyurl.com/36ugc6w

    ReplyDelete
  3. If you use g:uploadForm instead of g:form you can omit setting enctype since the tag does it for you - see http://grails.org/doc/latest/ref/Tags/uploadForm.html

    ReplyDelete
  4. Any ideas using JAXRS to create a User resource and POST data to /api/user instead of use a form??? Thanks!

    ReplyDelete