- Java 프로그래밍 언어를 사용하여 Microsoft Office 파일 형식을 읽고 쓸 수 있게 해주는 오픈소스 라이브러리입니다. 주로 Excel, Word, PowerPoint 등의 파일을 처리하는 데 사용됩니다.
기능
설명
다양한 Office 파일 형식 지원
.xls, .xlsx, .doc, .docx 등 Microsoft Office 파일 형식을 폭넓게 지원
플랫폼 독립성
순수 Java로 작성되어 모든 플랫폼에서 동일하게 동작
성능과 안정성
최적화된 성능과 안정적인 파일 처리 기능 제공
커뮤니티 지원
활발한 개발자 커뮤니티와 지속적인 업데이트 제공
1. 주요 기능
기능
설명
Excel 파일 업로드 및 데이터 읽기
사용자가 업로드한 Excel 파일의 내용을 읽어 시스템에서 활용할 수 있도록 처리하는 기능
새로운 Excel 파일 생성 및 데이터 쓰기
시스템에서 새로운 Excel 파일을 생성하고 데이터를 작성하여 저장하는 기능
템플릿 기반 Excel 파일 생성
미리 정의된 템플릿을 기반으로 데이터를 채워 Excel 파일을 생성하는 기능
대용량 Excel 파일 처리
SXSSF를 활용하여 대용량 데이터를 효율적으로 처리하는 기능
Excel 파일 다운로드
생성된 Excel 파일을 사용자가 다운로드할 수 있도록 제공하는 기능
2. Excel 확장자 종류
유형
설명
HSSF (Horrible SpreadSheet Format)
Excel 97-2003 (.xls) 파일 형식을 처리하기 위한 컴포넌트
XSSF (XML SpreadSheet Format)
Excel 2007 이상 버전의 (.xlsx) 파일 형식을 처리하기 위한 컴포넌트
SXSSF (Streaming XML SpreadSheet Format)
대용량 Excel 파일을 메모리 효율적으로 처리하기 위한 스트리밍 방식의 컴포넌트
CSV (Comma-Separated Values)
단순한 텍스트 기반의 데이터 형식으로, 쉼표(,)로 구분된 값들을 저장하는 형식. Apache POI는 OpenCSV 라이브러리와 함께 사용하여 CSV 파일도 처리 가능
2) Spring Boot 환경에서 Excel 다루기 -1 : 엑셀 업로드, 읽어오기
1. 의존성 추가
💡 의존성 추가
- 해당 기능을 구현하기 위해서 아래와 같은 의존성을 추가하였습니다. 금일 기준 가장 최신버전으로 적용하였습니다. - 해당 의존성을 위해서 xls, xlsx, csv 파일들에 대해서 읽어오고 활용할 수 있습니다. - 또한, 간단한 화면을 구현하기 위해 Thymeleaf를 이용하여서 간단한 화면을 구성하였습니다.
- 아래와 같이 resources/templates/pages 디렉터리 내에 excelUpload.html이라는 파일을 만들었습니다. - 해당 코드는 multipart/form-data의 전송 형태로 [POST] excel/upload 엔드포인트로 서버에 엑셀을 전달하도록 구성하였습니다. - 사용자는 파일을 선택하고 업로드 버튼을 누르면 서버로 전송되는 구조입니다.
- excelUpload() 메서드에서 이를 처리합니다. 이를 통해, 최초 파일정보를 출력하고, Excel 파일을 읽어와서 Header를 출력하고, Body에 해당하는 데이터들은 리스트 객체로 구성하여 출력을 합니다. - 최종적으로 다시 /excel/upload 엔드포인트로 반환을 합니다.
package com.blog.springbootexcelpoi;
import com.blog.springbootexcelpoi.dto.UserDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* 엑셀 처리를 위한 서비스
*
* @author : leejonghoon
* @fileName : ExcelService
* @since : 2025. 2. 11.
*/@Slf4j@ServicepublicclassExcelService{
/**
* 엑셀 업로드를 수행
*
* @param file
* @param model
* @return
*/public String excelUpload(MultipartFile file, Model model){
// 파일 정보 출력
log.debug("파일명: {}", file.getOriginalFilename());
log.debug("파일 크기: {} bytes", file.getSize());
try {
if (file.isEmpty()) {
model.addAttribute("message", "파일을 선택해주세요.");
return"/pages/excelUpload";
}
// 파일 확장자 검증
String filename = file.getOriginalFilename();
if (!filename.endsWith(".xlsx") && !filename.endsWith(".xls")) {
model.addAttribute("message", "Excel 파일만 업로드 가능합니다.");
return"/pages/excelUpload";
}
List<UserDto> userDtoList = new ArrayList<>();
// Excel 파일 처리
Workbook workbook = WorkbookFactory.create(file.getInputStream());
Sheet sheet = workbook.getSheetAt(0);
// 헤더 행 읽기
Row headerRow = sheet.getRow(0);
for (Cell cell : headerRow) {
log.debug("{}\\t", cell.getStringCellValue());
}
// 데이터 행 읽기for (int i = 1; i <= 10; i++) {
Row row = sheet.getRow(i);
// 행 들을 리스트 객체로 구성
userDtoList.add(UserDto.builder()
.number((int) row.getCell(0).getNumericCellValue()) // 순번
.name(row.getCell(1).getStringCellValue()) // 이름
.age((int) row.getCell(2).getNumericCellValue()) // 나이
.gender(row.getCell(3).getStringCellValue()) // 성별
.contact(row.getCell(4).getStringCellValue()) // 연락처
.build());
}
log.debug("구성한 리스트 객체 :: {}", userDtoList.toString());
log.debug("=================================================");
workbook.close();
model.addAttribute("message", "파일이 성공적으로 업로드되었습니다.");
} catch (IOException e) {
model.addAttribute("message", "파일 처리 중 오류가 발생했습니다: " + e.getMessage());
}
return"/pages/excelUpload";
}
}
5. 엑셀 파일 확인 및 결과 확인
5.1. 업로드 엑셀 파일
5.2. 결과 확인
💡 결과 확인
- 아래와 같이 파일에 대한 정보, 엑셀 Header, 객체화한 데이터들이 출력이 됨을 확인하였습니다.
3) Spring Boot 환경에서 Excel 다루기 -2 : 엑셀 생성 및 다운로드
1. 엑셀 다운로드 화면 구현
💡 엑셀 다운로드 화면 구현
- 이전 엑셀 업로드 화면에서 추가적으로 다운로드 화면을 추가하였습니다. - 해당 부분에서는 [POST] /excel/download 엔드포인트를 호출하는 download 버튼을 구성하였습니다.
💡 ExcelController - 위에서 구성한 엑셀 업로드 기능에 엑셀 다운로드 메서드를 구성하였습니다. - 해당 부분은 비즈니스 로직을 처리하는 ExcelService 내에 excelDownload()를 호출하여서 최종적으로 Resource라는 값을 출력받습니다. 이를 클라이언트에게 전달하며, header와 ContentType을 지정합니다.
1. Header : Content-Disposition: attachment; filename=userList.xlsx - 브라우저에게 이 응답을 다운로드할 파일로 처리하도록 지시합니다. - attachment: 파일을 다운로드하도록 지정합니다. - filename: 다운로드될 파일의 이름을 'userList.xlsx'로 지정합니다.
2. Content Type : Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet - 응답 본문의 미디어 타입을 지정합니다. - .xlsx 파일의 공식 MIME 타입으로 지정합니다. - 브라우저가 Excel 파일임을 인식하고 적절히 처리할 수 있도록 합니다.
💡 ExcelService - 엑셀 다운로드의 비즈니스를 처리하는 excelDownload() 함수입니다.
1. 시트 생성 : createSheet()으로 시트를 생성합니다. 2. 헤더 생성 : sheet 내에 createRow() 메서드를 통해서 헤더를 생성합니다. 3. 데이터 생성 : 헤더 아래에 createRow() 메서드를 통해 데이터를 생성합니다. 4. 열 너비 자동 설정 : autoSizeColumn() 메서드를 통해 열 너비를 자동으로 생성합니다. 5. 파일 생성 : 생성된 Excel workbook의 내용을 ByteArrayOutputStream에 작성합니다. 이를 통해 바이트 형태로 변환이 됩니다. 6. 시트 종료 : close()으로 시트를 종료합니다. 7. 리소스 구성 : 구성한 바이트 데이터를 HTTP 응답에 전달할 수 있는 ByteArrayResource로 구성하여 반환합니다.
package com.blog.springbootexcelpoi;
import com.blog.springbootexcelpoi.dto.UserDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* 엑셀 처리를 위한 서비스
*
* @author : leejonghoon
* @fileName : ExcelService
* @since : 2025. 2. 11.
*/@Slf4j@ServicepublicclassExcelService{
/**
* 엑셀 다운로드
*
* @param file
* @param model
* @return
*/public Resource excelDownload(Model model){
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("사용자 정보");
// 헤더 행 생성
Row headerRow = sheet.createRow(0);
String[] headers = {"순번", "이름", "나이", "성별", "연락처"};
for (int i = 0; i < headers.length; i++) {
Cell cell = headerRow.createCell(i);
cell.setCellValue(headers[i]);
}
// 데이터 행 생성
Object[][] data = {
{1, "한국인", 35, "남", "010-0000-0000"},
{2, "박원희", 11, "여", "010-1234-0000"},
{3, "이국한", 23, "여", "010-5678-0000"},
{4, "김명희", 27, "여", "010-9010-0000"},
{5, "김철민", 29, "남", "010-8888-0000"},
};
// Sheet 내에 헤더 / 데이터 행 구성for (int i = 0; i < data.length; i++) {
Row row = sheet.createRow(i + 1);
for (int j = 0; j < data[i].length; j++) {
Cell cell = row.createCell(j);
// 문자 처리if (data[i][j] instanceof String) {
cell.setCellValue((String) data[i][j]);
}
// 숫자 처리if (data[i][j] instanceof Integer) {
cell.setCellValue((Integer) data[i][j]);
}
}
}
// 열 너비 자동 조정for (int i = 0; i < headers.length; i++) {
sheet.autoSizeColumn(i);
}
// 파일 생성
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try {
workbook.write(outputStream);
workbook.close();
} catch (IOException e) {
thrownew RuntimeException(e);
}
ByteArrayResource resource = new ByteArrayResource(outputStream.toByteArray());
model.addAttribute("downloadMessage", "다운로드가 완료되었습니다.");
return resource;
}
}
4. 결과 확인
💡 결과 확인
- 아래와 같이 다운로드가 되어서 데이터 출력을 확인할 수 있습니다.
💡 [참고] 해당 소스코드는 아래의 Github Repository 내에서 확인이 가능합니다.