This step by step tutorial on how to export data to excel file using Grails 3, MongoDB and Grails 3 Export Plugin. There's a new update of Grails 3 Excel-Export plugin which updates a few months ago. Because there's a long time to wait for the new update of the excel-export plugin so we are using Grails 3 Export plugin that already updated and ready for Grails 3.

What we export is excel worksheet to display employees attendance which attendance data get dynamically from child collections of the employee. So, we have to create 2 collections that have relations they are Employee and Attendance collections. The export results should be like this.

The following tools and dependencies are required to achieve this tutorial:

- Grails 3.3.0

- MongoDB

- Grails 3 MongoDB Plugin

- Grails 3 Export Plugin



1. Create a New Grails 3 Application

As usual, we are doing a tutorial from scratch that means starting from creating a new Grails 3 application. We assume you are already installed latest Grails 3.3.0 and latest MongoDB on your machine. So, we do not show how to install that required tools for this tutorial. Now, open the terminal or cmd then go to your Grails projects folder then type this command to create a new Grails 3 application.

grails create-app grails3-excel-export

Now, go to the newly created Grails 3 project folder.

cd grails3-excel-export

Run this command to enter the Grails 3 interactive console.

grails

Now, you ready to type some required command for this tutorial. The first thing to make sure everything still on the path, type this command.

run-app

Now, open the browser then go to this address `http://localhost:8080`, you should see this page if everything working properly.

To stop the application just type this command.

stop-app



2. Add and Configure Grails 3 MongoDB and Export Plugin Dependencies

To add Grails 3 MongoDB and Export plugin dependencies, open and edit `build.gradle` on the root of project folder then add this lines inside dependencies.

compile "org.grails.plugins:mongodb:6.1.3" compile "org.grails.plugins:export:2.0.0"

Don't forget to comment out all plugin and dependencies related to `hibernate` and `h2`. Now, type this command in the Grails 3 interactive console.

compile

Next, open and edit `grails-app/conf/application.yml` and replace all Hibernate and H2 related datasource section with this.

environments: development: grails: mongodb: host: "localhost" port: 27017 username: "" password: "" databaseName: "grails-mongodb" production: grails: mongodb: host: "localhost" port: 27017 username: "" password: "" databaseName: "grails-mongodb"

That configuration tells Grails to use MongoDB on localhost and port 27017 with database name `grails-mongodb`. For Export plugin, there's no configuration required for standard usage.



3. Create Required Domain Class

As mention above, we need to create to related domain class for Employee and Attendance. Type this command in the Grails 3 interactive console to create it.

create-domain-class Employee create-domain-class Attendance

Open and edit `grails-app/domain/grails3/excel/export/Employee.groovy` then replace all codes with this.

package grails3.excel.export class Employee { String employeeId String employeeName static hasMany = [attendances:Attendance] static constraints = { } }

Open and edit `grails-app/domain/grails3/excel/export/Attendance.groovy` then replace all codes with this.

package grails3.excel.export class Attendance { static belongsTo = [employee:Employee] Date attDate String timeIn String timeOut static constraints = { timeIn nullable: true timeOut nullable: true } }



4. Populate Employee and Attendance with Dummy Data

For testing export to excel we need to populate employee and attendance with some dummy data. For that, open and edit `grails-app/init/grails3/excel/export/Bootstrap.groovy` then add this lines inside `init`.

def emp1 = Employee.findByEmployeeId("EMP001")?:new Employee(employeeId:"EMP001", employeeName:"John Doe").save(flush:true, failOnError:true) def emp2 = Employee.findByEmployeeId("EMP002")?:new Employee(employeeId:"EMP002", employeeName:"Jane Doe").save(flush:true, failOnError:true) def att1 = Attendance.findByEmployeeAndAttDate(emp1,new SimpleDateFormat("dd/MM/yyyy").parse("01/08/2017"))?:new Attendance(employee: emp1, attDate: new SimpleDateFormat("dd/MM/yyyy").parse("01/08/2017"), timeIn: "08:01", timeOut: "16:11").save(flush:true, failOnError: true) def att2 = Attendance.findByEmployeeAndAttDate(emp1,new SimpleDateFormat("dd/MM/yyyy").parse("02/08/2017"))?:new Attendance(employee: emp1, attDate: new SimpleDateFormat("dd/MM/yyyy").parse("02/08/2017"), timeIn: "08:01", timeOut: "16:11").save(flush:true, failOnError: true) def att3 = Attendance.findByEmployeeAndAttDate(emp1,new SimpleDateFormat("dd/MM/yyyy").parse("03/08/2017"))?:new Attendance(employee: emp1, attDate: new SimpleDateFormat("dd/MM/yyyy").parse("03/08/2017"), timeIn: "08:01", timeOut: "16:11").save(flush:true, failOnError: true) def att4 = Attendance.findByEmployeeAndAttDate(emp1,new SimpleDateFormat("dd/MM/yyyy").parse("04/08/2017"))?:new Attendance(employee: emp1, attDate: new SimpleDateFormat("dd/MM/yyyy").parse("04/08/2017"), timeIn: "08:01", timeOut: "16:11").save(flush:true, failOnError: true) def att5 = Attendance.findByEmployeeAndAttDate(emp1,new SimpleDateFormat("dd/MM/yyyy").parse("05/08/2017"))?:new Attendance(employee: emp1, attDate: new SimpleDateFormat("dd/MM/yyyy").parse("05/08/2017"), timeIn: "08:01", timeOut: "16:11").save(flush:true, failOnError: true) def att6 = Attendance.findByEmployeeAndAttDate(emp1,new SimpleDateFormat("dd/MM/yyyy").parse("06/08/2017"))?:new Attendance(employee: emp1, attDate: new SimpleDateFormat("dd/MM/yyyy").parse("06/08/2017"), timeIn: "08:01", timeOut: "16:11").save(flush:true, failOnError: true) def att7 = Attendance.findByEmployeeAndAttDate(emp1,new SimpleDateFormat("dd/MM/yyyy").parse("07/08/2017"))?:new Attendance(employee: emp1, attDate: new SimpleDateFormat("dd/MM/yyyy").parse("07/08/2017"), timeIn: "08:01", timeOut: "16:11").save(flush:true, failOnError: true) def att8 = Attendance.findByEmployeeAndAttDate(emp1,new SimpleDateFormat("dd/MM/yyyy").parse("08/08/2017"))?:new Attendance(employee: emp1, attDate: new SimpleDateFormat("dd/MM/yyyy").parse("08/08/2017")).save(flush:true, failOnError: true) def att9 = Attendance.findByEmployeeAndAttDate(emp1,new SimpleDateFormat("dd/MM/yyyy").parse("09/08/2017"))?:new Attendance(employee: emp1, attDate: new SimpleDateFormat("dd/MM/yyyy").parse("09/08/2017")).save(flush:true, failOnError: true) def att10 = Attendance.findByEmployeeAndAttDate(emp1,new SimpleDateFormat("dd/MM/yyyy").parse("10/08/2017"))?:new Attendance(employee: emp1, attDate: new SimpleDateFormat("dd/MM/yyyy").parse("10/08/2017"), timeIn: "08:01", timeOut: "16:11").save(flush:true, failOnError: true) def att11 = Attendance.findByEmployeeAndAttDate(emp1,new SimpleDateFormat("dd/MM/yyyy").parse("11/08/2017"))?:new Attendance(employee: emp1, attDate: new SimpleDateFormat("dd/MM/yyyy").parse("11/08/2017"), timeIn: "08:01", timeOut: "16:11").save(flush:true, failOnError: true) def att12 = Attendance.findByEmployeeAndAttDate(emp2,new SimpleDateFormat("dd/MM/yyyy").parse("01/08/2017"))?:new Attendance(employee: emp2, attDate: new SimpleDateFormat("dd/MM/yyyy").parse("01/08/2017"), timeIn: "08:01", timeOut: "16:11").save(flush:true, failOnError: true) def att13 = Attendance.findByEmployeeAndAttDate(emp2,new SimpleDateFormat("dd/MM/yyyy").parse("02/08/2017"))?:new Attendance(employee: emp2, attDate: new SimpleDateFormat("dd/MM/yyyy").parse("02/08/2017")).save(flush:true, failOnError: true) def att14 = Attendance.findByEmployeeAndAttDate(emp2,new SimpleDateFormat("dd/MM/yyyy").parse("03/08/2017"))?:new Attendance(employee: emp2, attDate: new SimpleDateFormat("dd/MM/yyyy").parse("03/08/2017"), timeIn: "08:01", timeOut: "16:11").save(flush:true, failOnError: true) def att15 = Attendance.findByEmployeeAndAttDate(emp2,new SimpleDateFormat("dd/MM/yyyy").parse("04/08/2017"))?:new Attendance(employee: emp2, attDate: new SimpleDateFormat("dd/MM/yyyy").parse("04/08/2017"), timeIn: "08:01", timeOut: "16:11").save(flush:true, failOnError: true) def att16 = Attendance.findByEmployeeAndAttDate(emp2,new SimpleDateFormat("dd/MM/yyyy").parse("05/08/2017"))?:new Attendance(employee: emp2, attDate: new SimpleDateFormat("dd/MM/yyyy").parse("05/08/2017"), timeIn: "08:01", timeOut: "16:11").save(flush:true, failOnError: true) def att17 = Attendance.findByEmployeeAndAttDate(emp2,new SimpleDateFormat("dd/MM/yyyy").parse("06/08/2017"))?:new Attendance(employee: emp2, attDate: new SimpleDateFormat("dd/MM/yyyy").parse("06/08/2017")).save(flush:true, failOnError: true) def att18 = Attendance.findByEmployeeAndAttDate(emp2,new SimpleDateFormat("dd/MM/yyyy").parse("07/08/2017"))?:new Attendance(employee: emp2, attDate: new SimpleDateFormat("dd/MM/yyyy").parse("07/08/2017"), timeIn: "08:01", timeOut: "16:11").save(flush:true, failOnError: true) def att19 = Attendance.findByEmployeeAndAttDate(emp2,new SimpleDateFormat("dd/MM/yyyy").parse("08/08/2017"))?:new Attendance(employee: emp2, attDate: new SimpleDateFormat("dd/MM/yyyy").parse("08/08/2017"), timeIn: "08:01", timeOut: "16:11").save(flush:true, failOnError: true) def att20 = Attendance.findByEmployeeAndAttDate(emp2,new SimpleDateFormat("dd/MM/yyyy").parse("09/08/2017"))?:new Attendance(employee: emp2, attDate: new SimpleDateFormat("dd/MM/yyyy").parse("09/08/2017"), timeIn: "08:01", timeOut: "16:11").save(flush:true, failOnError: true) def att21 = Attendance.findByEmployeeAndAttDate(emp2,new SimpleDateFormat("dd/MM/yyyy").parse("10/08/2017"))?:new Attendance(employee: emp2, attDate: new SimpleDateFormat("dd/MM/yyyy").parse("10/08/2017"), timeIn: "08:01", timeOut: "16:11").save(flush:true, failOnError: true) def att22 = Attendance.findByEmployeeAndAttDate(emp2,new SimpleDateFormat("dd/MM/yyyy").parse("11/08/2017"))?:new Attendance(employee: emp2, attDate: new SimpleDateFormat("dd/MM/yyyy").parse("11/08/2017"), timeIn: "08:01", timeOut: "16:11").save(flush:true, failOnError: true)

Now, run again the application and check on the MongoDB database, you should see those tables exist.

> use grails-mongodb switched to db grails-mongodb > show collections attendance attendance.next_id employee employee.next_id system.indexes



5. Create Controller for Display Attendance List and Export to Excel

Now, it's time to implement the export to excel. First, create a new controller for it by type this command.

create-controller Employee

That command will create a new `EmployeeController`. Open and edit `grails-app/controllers/grails3/excel/export/EmployeeController.groovy` then replace all codes with this.

package grails3.excel.export import java.text.SimpleDateFormat class EmployeeController { def exportService def index(Integer max) { params.max = Math.min(max ?: 10, 100) respond Employee.list(params), model:[employeeCount: Employee.count()] } def exportExcel() { params.exportFormat = "excel" params.extension = "xls" if(params.exportFormat && params.exportFormat != "html") { def employees = Employee.list(params) def results = [] employees.each { e -> def map = [:] map.put("employeeId",e.employeeId) map.put("employeeName",e.employeeName) def attendances = Attendance.findAllByEmployee(e, [sort: "attDate", order: "asc"]) attendances.each { a -> if(a.timeIn && a.timeOut) { map.put(new SimpleDateFormat("MMM dd, yyyy").format(a.attDate),a.timeIn+" - "+a.timeOut) } else { map.put(new SimpleDateFormat("MMM dd, yyyy").format(a.attDate),"-") } } results.add(map) } response.contentType = grailsApplication.config.grails.mime.types[params.exportFormat] response.setHeader("Content-disposition", "attachment; filename=attendance-"+new SimpleDateFormat("ddMMyyy").format(new Date())+".xls") List fields = [ "employeeId", "employeeName" ] Map labels = ["employeeId": "Employee ID", "employeeName": "Employee Name"] def atts = Attendance.findAllByEmployee(employees[0]) atts.each { a -> fields.add(new SimpleDateFormat("MMM dd, yyyy").format(a.attDate)) labels.put(new SimpleDateFormat("MMM dd, yyyy").format(a.attDate), new SimpleDateFormat("MMM dd, yyyy").format(a.attDate)) } Map formatters = [:] Map parameters = [:] exportService.export(params.exportFormat, response.outputStream, results, fields, labels, formatters, parameters) } } }

Now, create a new `grails-app/views/employee/index.gsp` as the view for `EmployeeController`. Open and edit that file then replace all HTML tags with this.

<!DOCTYPE html> <html> <head> <meta name="layout" content="main" /> <g:set var="entityName" value="${message(code: 'employee.label', default: 'Employee')}" /> <title><g:message code="default.list.label" args="[entityName]" /></title> </head> <body> <a href="#list-employee" class="skip" tabindex="-1"><g:message code="default.link.skip.label" default="Skip to content…"/></a> <div class="nav" role="navigation"> <ul> <li><a class="home" href="${createLink(uri: '/')}"><g:message code="default.home.label"/></a></li> <li><g:link class="create" action="exportExcel">Export to Excel</g:link></li> </ul> </div> <div id="list-employee" class="content scaffold-list" role="main"> <h1><g:message code="default.list.label" args="[entityName]" /></h1> <g:if test="${flash.message}"> <div class="message" role="status">${flash.message}</div> </g:if> <f:table collection="${employeeList}" properties="['employeeId', 'employeeName']" /> <div class="pagination"> <g:paginate total="${employeeCount ?: 0}" /> </div> </div> </body> </html>

That it's, now you can run again the Grails 3 application then open in the browser. Click the link of `EmployeeController` in the Available Controller and you should redirect to this page.

Now, you can click Export to Excel button and see the result of downloaded Excel file.

Please, leave the comment below for any suggestions, critics, and problems. If you need the full source code, you can find it on our GitHub.

Thanks!