신규로 전달(?) 받은 프로젝트가 코틀린 환경으로 되어있어서.. 하...
여튼 공부나 해볼겸해서 코틀린에서 엑셀 읽기를 대충대충 만들어 봤다. 개발환경부터 실행까지..
어렵네..ㅎㅎ ( java 였으면 말이지 그냥 쑥..)
우선 플젝을 만들어보자. 아래 DB관련 부분은 제거해도 된다.
엑셀 라이브러리 추가만 확인하자. fastexcel . fastexcel-reader
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("org.springframework.boot") version "2.4.5"
id("io.spring.dependency-management") version "1.0.11.RELEASE"
kotlin("jvm") version "1.4.32"
kotlin("plugin.spring") version "1.4.32"
kotlin("plugin.jpa") version "1.4.32"
}
group = "com.tistory.eclipse4j"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_11
configurations {
compileOnly {
extendsFrom(configurations.annotationProcessor.get())
}
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-webflux")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("io.projectreactor.kotlin:reactor-kotlin-extensions")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
implementation("org.dhatim:fastexcel:0.12.3")
implementation("org.dhatim:fastexcel-reader:0.12.3")
runtimeOnly("mysql:mysql-connector-java")
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("io.projectreactor:reactor-test")
}
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "11"
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
테스트 코드를 하나만들어서 엑셀 읽기 메소드를 추가한다.
@Test
fun parallelStreams() {
FileInputStream("excel-read-sample.xlsx").use { fis ->
val wb = ReadableWorkbook(fis)
val cellValues = wb.firstSheet.openStream().parallel()
.map { row: Row ->
// cell 을 data class로 변환한다.
rowCellsToDataClass(
row.stream() // parallel로 처리해도 된다.
)
}
.collect(Collectors.toList())
cellValues.forEach{o->println(o)}
}
}
하나의 row에 cells를 특정 data class에 매핑하도록 한다.
// stream을 활용하든 다른 header 맵퍼를 사용하든 알아서
private fun rowCellsToDataClass(stream: Stream<Cell>) : CellValue {
val cells = stream.toList()
return CellValue(cells[0].value.toString(), cells[1].value.toString(), cells[2].value.toString())
}
매핑될 data class
data class CellValue(var firstName: String, var secondName: String, var address : String)
실행결과
참고로 엑셀파일은 프로젝트 root path에 위치 시키도록 한다.
엑셀쓰기
package com.tistory.eclipse4j.kotlin.excel
import org.dhatim.fastexcel.Workbook
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.util.function.Consumer
// https://github.com/dhatim/fastexcel
// https://github.com/Floern/casting-csv-kt
class ExcelWriterTest {
@Throws(IOException::class)
fun writeWorkbook(consumer: Consumer<Workbook?>) {
val os = ByteArrayOutputStream( )
val wb = Workbook(os, "Test", "1.0")
consumer.accept(wb)
wb.finish()
os.writeTo(FileOutputStream(File("excel-write-sample.xlsx")))
//return os.toByteArray()
}
@Test
@DisplayName("정상적인 엑셀 생성")
fun parallelStreams() {
writeWorkbook { wb ->
val ws = wb!!.newWorksheet("Sheet 1")
getDatas().withIndex().map {
ws.value(it.index, 0, it.value.firstName)
ws.value(it.index, 1, it.value.secondName)
ws.value(it.index, 2, it.value.address)
ws.value(it.index, 3, it.value.message)
}
}
}
fun getDatas() : List<WriteCellValue> {
val writeCellValues: MutableList<WriteCellValue> = mutableListOf()
writeCellValues.add(WriteCellValue("Gil1", "Grissom1", "Addr1", "우리집1"))
writeCellValues.add(WriteCellValue("Gil2", "Grissom2", "Addr2", "우리집2"))
return writeCellValues
}
data class WriteCellValue(var firstName: String, var secondName: String, var address : String, var message : String)
}