Kotlin + Spring Boot + Apache Commons Export Data to CSV Example
Hello everyone, today we will learn how to export and download the data as a CSV file in a Kotlin + Spring Boot project. CSV stands for Comma-Separated-Values and it's a common format for doing a bulk data transfer between systems. For creating and parsing CSV files, we will use Apache Commons' 3rd-party library.
Project Directory:
Technologies used:
- Kotlin
- Spring Boot
- Apache Commons
- Spring Data JPA
- H2DB
- Maven
Maven[pom.xml]
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.knf.dev</groupId>
<artifactId>kotlin_springboot_apachecommans_exportcsv</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>kotlin_springboot_apachecommans_exportcsv</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<kotlin.version>1.3.72</kotlin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-kotlin</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.8</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<configuration>
<args>
<arg>-Xjsr305=strict</arg>
</args>
<compilerPlugins>
<plugin>spring</plugin>
</compilerPlugins>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
Creating the Document
package com.knf.dev.entity
import javax.persistence.*
@Entity
@Table(name = "employee")
class Employee {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
var id: Long = 0
var name: String? = null
var email: String? = null
var country: String? = null
var age = 0
var role: String? = null
constructor() : super() {}
constructor(
name: String?, email: String?, country: String?,
age: Int, role: String?
) : super() {
this.name = name
this.email = email
this.country = country
this.age = age
this.role = role
}
}
Creating the Repository
package com.knf.dev.repository
import com.knf.dev.entity.Employee
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository
@Repository
interface EmployeeRepository : JpaRepository<Employee, Long>
Creating the Service
package com.knf.dev.service
import java.io.ByteArrayInputStream
import com.knf.dev.entity.Employee
import com.knf.dev.helper.CSVHelper
import com.knf.dev.helper.CSVHelper.employeesToCSV
import com.knf.dev.repository.EmployeeRepository
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
@Service
class EmployeeService {
@Autowired
var employeeRepository: EmployeeRepository? = null
fun fetchAll(): List<Employee> {
return employeeRepository!!.findAll()
}
fun load(): ByteArrayInputStream {
//save Dummy Data
saveDummyEmployees()
val employees = fetchAll()
return CSVHelper.employeesToCSV(employees)
}
//save Dummy Data
fun saveDummyEmployees() {
val employees: MutableList<Employee> = ArrayList()
// create dummy employees
employees.add(
Employee(
"Dummy-1", "dummy1@example.com",
"India", 35, "Lead Tester"
)
)
employees.add(
Employee(
"Dummy-2", "dummy2@srovoki.me",
"USA", 25, "Tester"
)
)
employees.add(
Employee(
"Dummy-3", "dummy3@gmail.com",
"Japan", 29, "Sr.Tester"
)
)
employees.add(
Employee(
"Dummy-1", "dummy1@example.com",
"India", 35, "Lead Tester"
)
)
employees.add(
Employee(
"Dummy-2", "dummy2@srovoki.me",
"USA", 25, "Tester"
)
)
employees.add(
Employee(
"Dummy-3", "dummy3@gmail.com",
"Japan", 29, "Sr.Tester"
)
)
employees.add(
Employee(
"Dummy-1", "dummy1@example.com",
"India", 35, "Lead Tester"
)
)
employees.add(
Employee(
"Dummy-2", "dummy2@srovoki.me",
"USA", 25, "Tester"
)
)
employees.add(
Employee(
"Dummy-3", "dummy3@gmail.com",
"Japan", 29, "Sr.Tester"
)
)
employees.add(
Employee(
"Dummy-1", "dummy1@example.com",
"India", 35, "Lead Tester"
)
)
employees.add(
Employee(
"Dummy-2", "dummy2@srovoki.me",
"USA", 25, "Tester"
)
)
employees.add(
Employee(
"Dummy-3", "dummy3@gmail.com",
"Japan", 29, "Sr.Tester"
)
)
employees.add(
Employee(
"Dummy-1", "dummy1@example.com",
"India", 35, "Lead Tester"
)
)
employees.add(
Employee(
"Dummy-2", "dummy2@srovoki.me",
"USA", 25, "Tester"
)
)
employees.add(
Employee(
"Dummy-3", "dummy3@gmail.com",
"Japan", 29, "Sr.Tester"
)
)
employeeRepository?.saveAll(employees)
}
}
Creating the Helper
package com.knf.dev.helper
import java.io.IOException
import java.io.ByteArrayInputStream
import com.knf.dev.entity.Employee
import java.io.PrintWriter
import org.apache.commons.csv.CSVPrinter
import org.apache.commons.csv.CSVFormat
import java.io.ByteArrayOutputStream
import java.util.*
object CSVHelper {
fun employeesToCSV(employees: List<Employee>): ByteArrayInputStream {
val format = CSVFormat.DEFAULT.withHeader("ID", "Name", "Email",
"Age", "Country", "Role")
try {
ByteArrayOutputStream().use({ out ->
CSVPrinter(
PrintWriter(out),
format
).use { csvPrinter ->
for (emp in employees) {
val data: List<String?> = Arrays.asList(
emp.id.toString(),
emp.name, emp.email,
java.lang.String.valueOf(emp.age), emp.country,
emp.role
)
csvPrinter.printRecord(data)
}
csvPrinter.flush()
return ByteArrayInputStream(out.toByteArray())
}
})
} catch (e: IOException) {
throw RuntimeException(
"fail to import data to CSV file: "
+ e.message
)
}
}
}
Creating the Controller
package com.knf.dev.controller
import org.springframework.http.HttpHeaders
import org.springframework.http.ResponseEntity
import org.springframework.core.io.InputStreamResource
import javax.servlet.http.HttpServletResponse
import org.springframework.web.bind.annotation.GetMapping
import com.knf.dev.service.EmployeeService
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.MediaType
import org.springframework.stereotype.Controller
@Controller
class EmployeeController {
@Autowired
var employeeService: EmployeeService? = null
@GetMapping("/export-employees")
@Throws(Exception::class)
fun exportCSV(response: HttpServletResponse?):
ResponseEntity<InputStreamResource> {
val filename = "employees.csv"
val file = InputStreamResource(employeeService!!.load())
return ResponseEntity.ok().header(
HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=$filename"
)
.contentType(MediaType.parseMediaType("application/csv")).body(file)
}
}
Driver
package com.knf.dev
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class KotlinSpringbootApachecommansExportcsvApplication
fun main(args: Array<String>) {
runApplication<KotlinSpringbootApachecommansExportcsvApplication>(*args)
}