오늘 포스팅은 Springboot 기반 API 서버에서 엑셀 다운로드 기능 구현 예제에 대한 것이다.
springboot 3.2.3
kotlin
JDK21
apache.common-csv 1.10.0
엑셀 다운로드 기능 구현을 위해 apache.common-csv 1.10.0 를 사용했다.
@RestController
class UserController(
private val getMemberInfoUseCase: GetMemberInfoUseCase,
private val csvUtil: CsvUtil,
) {
@GetMapping("/csv")
fun dowonloadCsv(
response: HttpServletResponse,
request: HttpServletRequest
) {
val csvFileName = "excel/excel-${LocalDateTime.now()}.csv" // (1)
val memberInfo = this.getMemberInfoUseCase.getMemberInfoList() // (2)
val fileInputStream: InputStream // (3)
try {
val headers = listOf("no", "유저 닉네임", "유저 전화번호")
val data = memberInfo.map { listOf(it.userId, it.nickName, it.contact) }
csvUtil.write(csvFileName, headers, data) // (4)
fileInputStream = FileInputStream(csvFileName)
// (5)
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"$csvFileName\"")
response.setHeader("Content-Type", "application/octet-stream")
val outputStream = response.outputStream
var length: Int
val buffer = ByteArray(1024)
while ((fileInputStream.read(buffer).also { length = it }) != -1) {
outputStream.write(buffer, 0, length)
}
// (6)
outputStream.flush()
outputStream.close()
fileInputStream.close()
} catch (e: IOException) {
throw RuntimeException("csv 파일 생성 실패")
} finally { // (7)
val filePath = Paths.get(csvFileName)
val directoryPath = filePath.parent
if (Files.exists(directoryPath)) {
if (File(csvFileName).delete()) {
logger().info("========== 파일삭제 성공 ==========")
} else {
logger().info("========== 파일삭제 실패 ==========")
}
}
}
}
}
(1) 엑셀파일 다운로드 시, 파일명 정의
(2) 유저 정보 조회 usecase
(3) 파일 작성을 위해 InputStream 정의
(4) headers와 data로 엑셀 파일에 담을 내용 각각 정의 및 util 클래스로 파일 작성
(5) HttpServletResponse 에 Header 설정
stream 형태로 데이터 전송을 하기에 그에 대한 설정
(6) stream flush & close 처리
(7) api 호출 종료 시, 서버에 떨군 파일 찾아서 제거
@Component
class CsvUtil {
fun write(fileName: String, headers: List<String>, data: List<List<String?>>) {
val sw: FileWriter
val csvPrinter: CSVPrinter
try {
val filePath = Paths.get(fileName) // (1)
val directoryPath = filePath.parent // (2)
if (!Files.exists(directoryPath)) { // (3)
Files.createDirectories(directoryPath)
}
sw = FileWriter(fileName) // (4)
csvPrinter = CSVPrinter(sw, CSVFormat.DEFAULT.builder().setHeader(*headers.toTypedArray()).build()) // (5)
for (row in data) { // (6)
csvPrinter.printRecord(row)
}
sw.flush() // (7)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
*폴더에 파일을 떨구고, 지우는 작업을 하기에 작성된 코드이다. (1) ~ (3)
(1) 파일 이름으로부터 경로를 찾는다.
(2) 폴더 위치를 찾는다.
(3) 폴더가 존재하지 않으면, 새로 만들어준다.
(4) 파일 이름으로 파일생성기를 생성한다.
(5) 엑셀 파일 출력기를 생성한다. ( Controller에서 정의한 헤더를 format에 넣어서 생성한다. )
(6) record 데이터를 row 단위로 파일에 작성한다.
(6) 파일 생성기 flush
apache.common-csv 1.10.0 라이브러리를 이용해서 Csv 파일 생성하는 로직이다.
localhost:8080/csv GET 요청을 보내면, root 폴더 아래 /excel 위치에 엑셀파일이 생성된다.
실무에서 엑셀 파일 다운로드 기능을 구현하면서, 앞으로도 종종 사용될 수 있을 거 같아 sample 코드를 남겨두고자 작성했다.