I find it sorely disappointing that ServletContext#getMimeType() doesn't just use apache's standard /etc/mime.types
automatically. Instead, it seems to use some smaller subset of extension mappings included in some servlet jar somewhere. Fortunately, it's easy enough to use spring's ConfigurableMimeFileTypeMap bean to get the mappings from the mime.types
files of your choosing.
The way I like to set it up is to add a custom configuration property in my grails-app/conf/Config.groovy
, and specify a comma-separated list of file paths to use (that way I can use the standard /etc/mime.types
file, but also add in my own custom mime.types
file if I need some mappings not in the standard one):
grails-app/conf/Config.groovy
mime.types = '/etc/mime.types'
Then, in grails-app/conf/spring/resources.groovy
, I define a ConfigurableMimeFileTypeMap
bean (I call it fileTypeMap
, but you can call it whatever):
grails-app/conf/resources.groovy
fileTypeMap(org.springframework.mail.javamail.ConfigurableMimeFileTypeMap) {
application.config.mime.types.split(/,/).each {
mappingLocation = new org.springframework.core.io.FileSystemResource(it)
}
}
Finally, in the controller actions where I want to stream out a file, I use the ConfigurableMimeFileTypeMap
bean's getContentType()
method to calculate the file's content type from its name:
grails-app/controllers/MyController.groovy
def fileTypeMap
def download = {
try {
// some logic here to locate the appropriate file to stream
def file = new File('/tmp/foo.txt')
// use /etc/mime.types to determine the file's content type from its extension
def contentType = fileTypeMap.getContentType(file.name.toLowerCase())
// must special-case text/html; see http://jira.grails.org/browse/GRAILS-1223
if (contentType == 'text/html')
return render(contentType: contentType, text: file.text)
// set up standard (inline) file-download headers
response.contentType = contentType
response.contentLength = file.length() as Integer
response.setHeader 'Content-Disposition', "inline; filename=\"${file.name}\""
// stream the file
file.inputStream.withStream { response.outputStream << it }
} catch (FileNotFoundException e) {
response.sendError 404
}
}
No comments:
Post a Comment