The MongoFile plugin add methods to domain instances to save, retrieve and delete associated files from a MongoDB file store. The plugin can also write a file out to an HTTP response. This plugin depends on the MongoDB plugin.
Once installed, append the following to DataSource.groovy:
grails {
mongo {
databaseName = "db"
}
}
Each domain class in the Grails application will now have a number of methods you can call to create, retrieve, update and delete files. Note that the fieldName parameter is optional and only needs to be used in the case of a two or more files needing to be stored on a domain class instance. It can be omitted entirely for the first file if desired.
saveMongoFile(MultipartFile file, String fieldName = '')
Saves a file to the MongoDB store, associated with the domain instance, replacing any existing file for the domain instance (and fieldName if specified). See the section on uploading files in the Grails docs.
saveMongoFile(byte[] fileContents, String fileName, String fieldName = '')
Saves file bytes to the MongoDB store, associated with the domain instance, replacing any existing file for the domain instance (and fieldName if specified).
saveMongoFile(InputStream inputStream, String fileName, String fieldName = '')
Saves stream bytes to the MongoDB store, associated with the domain instance, replacing any existing file for the domain instance (and fieldName if specified).
deleteMongoFile(String fieldName = '')
Deletes the associated file from the MongoDB store.
getMongoFile(String fieldName = '')
Retrieves a GridFSDBFile object from the MongoDB store
mongoFileExists(String fieldName = '')
Returns true or false depending on whether a file is associated with the domain instance. Useful to test whether to render a tag or not
GSP:
<g:uploadForm action="save">
<input type="file" name="logo" />
<input type="submit" />
</g:uploadForm>
Controller:
def save() {
def userInstance = new User(params)
def logo = request.getFile('logo')
if (logo.empty) {
flash.message = 'Logo must be uploaded'
render(view: "create", model: [userInstance: userInstance])
return
}
if (!userInstance.save(flush: true)) {
render(view: "create", model: [userInstance: userInstance])
return
}
userInstance.saveMongoFile(file)
flash.message = message(code: 'default.created.message', args: [message(code: 'user.label', default: 'User'), userInstance.id])
redirect(action: "show", id: userInstance.id)
}
A taglib is provided to call files from GSP pages. In Controllers and GSPs, you can get a link to a file by using, for example
mongofile.createLinkTo(domainInstance: userInstance)
or alternatively without the instance (but with the optional fieldName and attachment parameters) by using
mongofile.createLinkTo(domainClass: 'User', id: 1, fieldName: 'icon', attachment: true)
However, it is more likely you will want to link to files stored as images or downloads. In the case of images, use for example
<mongofile:img domainInstance="${userInstance}" fieldName="icon" />
To link to a file download, use the following. Note you can add extra attributes such as 'class'. If you omit the body text in the tag, as in the example below, the file name is retrieved from the MongoDB store and used for the link text. (Note that if you are using this with large numbers of big files on a page it may be more performant to store the filename in the domain class instead.)
<mongofile:link domainInstance="${userInstance}" fieldName="pdf" class="download-pdf" />
It is often useful to test whether to render the tag first:
<g:if test="${userInstance.mongoFileExists('icon')}"><mongofile:img domainInstance="${userInstance}" fieldName="icon" /></g:if>
Most of the time the methods above should be enough. However, you can inject the MongoFileService into a Controller or another Service with
def mongoFileService
The following primary methods are available on MongoFileService:
saveFile(MultipartFile file, Class domainClass, Long id, String fieldName = '')
Saves a file to the MongoDB store, associated with an domain object. See the section on uploading files in the Grails docs.
saveFile(byte[] fileContents, String fileName, Class domainClass, Long id, String fieldName = '')
Saves file bytes to the MongoDB store, associated with an domain object.
saveFile(InputStream inputStream, String fileName, Class domainClass, Long id, String fieldName = '')
Saves stream bytes to the MongoDB store, associated with an domain object.
deleteFile(Class domainClass, Long id, String fieldName = '')
Deletes a associated file from the MongoDB store.
getFile(Class domainClass, Long id, String fieldName = '')
Retrieves a GridFSDBFile object from the MongoDB store
deliverFile(HttpServletResponse response, boolean asAttachment, Class domainClass, Long id, String fieldName = '')
Writes the associated file to the response, either directly or as an attachment. (Specifying attachment=true changes the response's Content-Disposition header.)
dropCollections()
Use to drop all collections the database in order to start afresh. Use with caution! For example:
import grails.util.GrailsUtil
class BootStrap {
def mongoFileService
def init = { servletContext ->
switch(GrailsUtil.environment) {
case "development":
mongoFileService.dropCollections()
}
}
....
}
dropDatabase()
Use to drop the database entirely in order to start afresh. Again, use with caution!
Each file is stored in a MongoDB collection (bucket), named after the domain class name and fieldname if present, joined with an underscore (${domain}_${fieldName}). On the mongo console you could list the stored files with
db.user_icon.files.find({});
db.user_thumbnail.files.find({});