2026년 4월 2일 작성
Apache POI Excel
Apache POI의 Excel 처리 기능은 Workbook, Sheet, Row, Cell 계층 구조를 기반으로 `.xlsx` file을 생성하고, header/data row 작성, column 너비 조정, cell formatting과 style 적용까지 수행합니다.
Apache POI Excel
- Apache POI는 Excel file을 생성하고 download하는 기능을 web application에서 구현하는 데 적합합니다.
- POI library는
.xlsformat과.xlsxformat을 모두 지원합니다.
- POI library는
| 주요 Class/Interface | 설명 |
|---|---|
| Workbook | Excel file 전체를 나타내는 최상위 interface |
| XSSFWorkbook | .xlsx format의 Excel file을 처리하는 class |
| HSSFWorkbook | .xls format의 Excel file을 처리하는 class |
| Sheet | Excel file 내의 개별 worksheet |
| Row | worksheet 내의 행 |
| Cell | worksheet 내의 개별 cell |
기본적인 사용 방법
- Apache POI는 Maven이나 Gradle을 통해 dependency를 추가하여 사용합니다.
- 의존성을 추가한 후,
XSSFWorkbook을 사용하여 Excel file을 생성하고,Sheet,Row,Cell을 사용하여 data를 삽입합니다.
- 의존성을 추가한 후,
Dependency 추가
- Maven project에서는
pom.xml에 Apache POI dependency를 추가합니다.
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.4</version>
</dependency>
- Gradle project에서는
build.gradle에 dependency를 추가합니다.
implementation 'org.apache.poi:poi:5.2.4'
implementation 'org.apache.poi:poi-ooxml:5.2.4'
Workbook 생성
XSSFWorkbook을 사용하여 새로운 Excel file을 생성합니다.
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class ExcelGenerator {
public Workbook createExcelFile() {
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("data 시트");
return workbook;
}
}
Header Row 생성
- 첫 번째 row에 column header를 생성합니다.
- cell style을 적용하여 header를 시각적으로 구분합니다.
private void createHeaderRow(Sheet sheet, String[] headers) {
Row headerRow = sheet.createRow(0);
CellStyle headerStyle = sheet.getWorkbook().createCellStyle();
Font headerFont = sheet.getWorkbook().createFont();
headerFont.setBold(true);
headerStyle.setFont(headerFont);
for (int i = 0; i < headers.length; i++) {
Cell cell = headerRow.createCell(i);
cell.setCellValue(headers[i]);
cell.setCellStyle(headerStyle);
}
}
Data Row 생성
- header row 다음부터 실제 data를 삽입합니다.
- 다양한 data type에 따라 적절한 method를 사용합니다.
private void createDataRows(Sheet sheet, List<DataObject> dataList) {
int rowNum = 1; // header row 다음부터 시작
for (DataObject data : dataList) {
Row row = sheet.createRow(rowNum++);
row.createCell(0).setCellValue(data.getName());
row.createCell(1).setCellValue(data.getAge());
row.createCell(2).setCellValue(data.getEmail());
row.createCell(3).setCellValue(data.getCreatedDate());
}
}
class DataObject {
private String name;
private int age;
private String email;
private Date createdDate;
// getters and setters
}
Column 너비 자동 조정
autoSizeColumn()으로 data 길이에 맞게 column 너비를 자동으로 조정합니다.
private void autoSizeColumns(Sheet sheet, int columnCount) {
for (int i = 0; i < columnCount; i++) {
sheet.autoSizeColumn(i);
}
}
Cell Formatting 및 Style 적용
CellStyle과DataFormat을 사용하여 숫자, 날짜 format과 color, border 등의 시각적 style을 cell 단위로 지정합니다.
숫자 Format 적용
- 숫자 data에 천 단위 구분자나 소수점 format을 적용합니다.
private void applyCellFormat(Workbook workbook, Cell cell, double value) {
CellStyle numberStyle = workbook.createCellStyle();
DataFormat format = workbook.createDataFormat();
numberStyle.setDataFormat(format.getFormat("#,##0.00"));
cell.setCellValue(value);
cell.setCellStyle(numberStyle);
}
날짜 Format 적용
- 날짜 data에 원하는 format을 적용합니다.
private void applyDateFormat(Workbook workbook, Cell cell, Date date) {
CellStyle dateStyle = workbook.createCellStyle();
CreationHelper createHelper = workbook.getCreationHelper();
dateStyle.setDataFormat(createHelper.createDataFormat().getFormat("yyyy-mm-dd"));
cell.setCellValue(date);
cell.setCellStyle(dateStyle);
}
Cell Color 및 Border 적용
- cell background color와 border를 설정합니다.
private CellStyle createStyledCell(Workbook workbook) {
CellStyle style = workbook.createCellStyle();
// background color 설정
style.setFillForegroundColor(IndexedColors.LIGHT_BLUE.getIndex());
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
// border 설정
style.setBorderTop(BorderStyle.THIN);
style.setBorderBottom(BorderStyle.THIN);
style.setBorderLeft(BorderStyle.THIN);
style.setBorderRight(BorderStyle.THIN);
return style;
}
Error 처리 및 최적화
Workbook은Closeable을 구현하므로 반드시close()를 호출해야 하며,CellStyle은 매번 생성하지 않고 cache하여 재사용해야 성능이 유지됩니다.
Exception 처리
IOException,InvalidFormatException등을 catch하고,finallyblock이나 try-with-resources로Workbook을 반드시 닫습니다.
public ResponseEntity<byte[]> safeDownloadExcel() {
try {
Workbook workbook = createExcelFile();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
workbook.write(outputStream);
workbook.close();
return createDownloadResponse(outputStream.toByteArray());
} catch (IOException e) {
logger.error("Excel file 생성 중 오류 발생", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
} catch (Exception e) {
logger.error("예상치 못한 오류 발생", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
Memory Leak 방지
Workbookresource를 반드시 해제하여 memory leak을 방지합니다.
public void createExcelWithProperResourceManagement() {
Workbook workbook = null;
try {
workbook = new XSSFWorkbook();
// Excel file 작업 수행
processExcelFile(workbook);
} catch (IOException e) {
logger.error("Excel 처리 중 오류", e);
} finally {
if (workbook != null) {
try {
workbook.close();
} catch (IOException e) {
logger.error("Workbook 종료 중 오류", e);
}
}
}
}
성능 최적화
CellStyle을 매번 생성하지 않고 cache하여 재사용하면 성능이 향상됩니다.
public class OptimizedExcelGenerator {
private final Map<String, CellStyle> styleCache = new HashMap<>();
private CellStyle getCachedStyle(Workbook workbook, String styleKey) {
return styleCache.computeIfAbsent(styleKey, key -> createCellStyle(workbook, key));
}
private CellStyle createCellStyle(Workbook workbook, String styleType) {
CellStyle style = workbook.createCellStyle();
switch (styleType) {
case "header":
Font headerFont = workbook.createFont();
headerFont.setBold(true);
style.setFont(headerFont);
break;
case "number":
DataFormat format = workbook.createDataFormat();
style.setDataFormat(format.getFormat("#,##0"));
break;
}
return style;
}
}