1. Apache POI란?
Apache POI(Poor Obfuscation Implementation)는 자바에서 MS Office 문서(Excel, Word, PowerPoint 등)를 읽고 쓸 수 있게 해주는 라이브러리다.
컴퓨터 앞에 앉아서 일하는 사람들중에 엑셀을 사용하지 않는 사람이 있을까?
나는 어디서 일하든 엑셀을 사용하지 못하면 일의 난이도가 굉장히 상승했었다.
개발자가 되면 엑셀을 사용하지 않을줄 알았지만 오히려 엑셀이라는 프로그램의 짜임새에 감탄하며 더 잘 사용하게 되었다. 특히 데이터를 다룰 때 많이 사용하게 된다.
코딩을 할 수 있다면 그런 excel을 더 효율적으로 활용할 수 있으며, excel과 관련된 기능을 만들 수도 있으니 굉장히 유용한 라이브러리라 할 수 있겠다.
2. Apache POI 세팅
2-1 버전 조회( Maven Repository)
POI를 사용하려면 의존성 추가가 필요하다.
버전 조회를 위해 `Maven Repository`에 접속한 뒤 poi를 검색했다.
5.4.0이 최신버전인 것 같으니 사용해주도록 하겠다.
`poi`와 `poi-ooxml`을 추가해주면 된다.
poi-ooxml의 경우 Excel 2007 이상 파일(. xlsx)을 지원하기 위해 사용한다고 한다.
2-2 maven 세팅(pom.xml)
<properties>
<poi.version>5.4.0</poi.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${poi.version}</version>
</dependency>
</dependencies>
2-3 Gradle 세팅(build.gradle)
ext {
poiVersion = "5.4.0"
}
dependencies {
implementation "org.apache.poi:poi:${poiVersion}"
implementation "org.apache.poi:poi-ooxml:${poiVersion}"
}
3. Apache POI 사용법
엑셀 파일을 읽고, 쓸 수 있다면 다 할 수 있을 것이라고 본다.
세부적인 기능이야 아주 풍부하겠지만 일하면서 쓰는 기능은 사실 이게 전부인 것 같다.
그 이상의 활용법은 그때 그때 상황별로 다르니 공식문서를 참조하도록 하자.
3-1 poi를 사용해 엑셀 파일을 생성해 보자.
엑셀 파일을 만들어 데이터를 입력하는 예제 코드이다.
poi로 엑셀을 다룰 때는 크게 `파일(Workbook)` > `시트(Sheet)` > `줄(Row)` > `칸(Cell)`을 기억해 주면 된다.
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class PoiCreateExcel {
public static void main(String[] args) {
// 1. 엑셀 Workbook 생성
Workbook workbook = new XSSFWorkbook();
// 2. Sheet 생성
Sheet sheet = workbook.createSheet("K-Pop Girl Groups");
// 3. 첫 번째 행(Row) - 헤더 생성
Row headerRow = sheet.createRow(0);
// 4. 헤더 셀 생성 및 값 설정 (인덱스, 그룹 이름, 인원수)
String[] columns = {"순번", "걸그룹 이름", "인원수"};
for (int i = 0; i < columns.length; i++) {
Cell cell = headerRow.createCell(i);
cell.setCellValue(columns[i]);
}
// 5. 걸그룹 데이터 추가 (순번, 이름, 인원수)
Object[][] girlGroups = {
{1, "BLACKPINK", 4},
{2, "TWICE", 9},
{3, "Red Velvet", 5},
{4, "ITZY", 5},
{5, "NewJeans", 5},
{6, "LE SSERAFIM", 5},
{7, "IVE", 6},
{8, "aespa", 4},
{9, "MAMAMOO", 4},
{10, "STAYC", 6}
};
int rowNum = 1;
for (Object[] group : girlGroups) {
Row row = sheet.createRow(rowNum++);
for (int i = 0; i < group.length; i++) {
Cell cell = row.createCell(i);
if (group[i] instanceof String) {
cell.setCellValue((String) group[i]);
} else if (group[i] instanceof Integer) {
cell.setCellValue((Integer) group[i]);
}
}
}
// 6. 파일 저장 경로 설정 (src/main/resources/excel/)
String filePath = "src/main/resources/excel/girl_groups.xlsx";
File file = new File(filePath);
// 7. 파일 저장
try (FileOutputStream fileOut = new FileOutputStream(file)) {
workbook.write(fileOut);
System.out.println("엑셀 파일이 생성되었습니다: " + file.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
// 8. Workbook 닫기
try {
workbook.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
1) 워크북 객체를 생성한다.
XSSFWorkbook은. xlsx형식의 엑셀 파일을 다룰 수 있는 클래스이다.
Workbook workbook = new XSSFWorkbook();
2) sheet를 생성한다.
이전에 생성한 workbook객체에 sheet를 생성한다.
시트이름을 인자로 넘길 수 있다.
빈 값을 경우 "Sheet1" 같은 기본 값으로 생성된다.
Sheet sheet = workbook.createSheet("K-Pop Girl Groups");
3) Row를 생성한다.
이전에 생성한 sheet에서 row를 생성한다.
인덱스는 0부터 시작한다.
가장 첫 번째 줄을 만들었다.
여기에 항목명을 기록해 줄 헤더로우를 만들 것이다.
Row headerRow = sheet.createRow(0);
4) Cell을 생성한다.
방금 생성한 row에 cell을 생성해 준 뒤에 해당 cell에 값을 입력해 준다.
생성은 `Row.createCell(i)`;
값 입력은 `Cell.setCellValue(value)`;
String[] columns = {"순번", "걸그룹 이름", "인원수"};
for (int i = 0; i < columns.length; i++) {
Cell cell = headerRow.createCell(i);
cell.setCellValue(columns[i]);
}
5) 파일을 저장한다.
생성된 파일을 저장할 경로와 파일명을 입력해 파일 객체를 생성한다.
그리고 위에서 작성한 workbook객체를 FileOutputStream을 이용해 파일로 저장한다.
String filePath = "src/main/resources/excel/girl_groups.xlsx";
File file = new File(filePath);
try (FileOutputStream fileOut = new FileOutputStream(file)) {
workbook.write(fileOut);
} catch (IOException e) {
e.printStackTrace();
}
6) workbook객체를 정리한다.
JVM이 알아서 해주겠지만 파일이 클 경우를 대비해 닫아주는 것이 좋다.
사실 `try-with-resources`를 사용하면 자동으로 닫아주기 때문에 사용하는 것이 훨씬 좋다.
다음 예제는 그렇게 해보도록 하자.
try {
workbook.close();
} catch (IOException e) {
e.printStackTrace();
}
girl_groups.xlsx 파일이 resources/excel/ 경로에 생성된 것을 확인할 수 있다.
엑셀이 깔려있다면 엑셀 아이콘이 보일 텐데, 개인 pc에 한셀이 깔려있어서 ? 박스가 표시된다.
입력 데이터들이 잘 들어가 있는 것을 확인할 수 있다.
3-2 poi를 사용해 엑셀 파일의 값을 읽어보자.
이번에는 방금 생성한 엑셀 파일을 읽어낸 뒤에 그 값을 이용해 insert 쿼리를 만들어 보겠다.
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class PoiReadExcel {
private static final String FILE_PATH = "src/main/resources/excel/girl_groups.xlsx"; // Excel 파일 경로
public static void main(String[] args) {
// 1. Excel 파일 읽기
try (FileInputStream fis = new FileInputStream(new File(FILE_PATH));
Workbook workbook = new XSSFWorkbook(fis)) {
Sheet sheet = workbook.getSheetAt(0); // 첫 번째 시트 가져오기
StringBuilder sqlBuilder = new StringBuilder(); // SQL 문자열을 저장할 StringBuilder
// 2. Excel 데이터 읽어서 SQL 쿼리 생성
for (Row row : sheet) {
if (row.getRowNum() == 0) continue; // 첫 번째 행(헤더) 건너뛰기
String name = row.getCell(1).getStringCellValue(); // 걸그룹 이름
int members = (int) row.getCell(2).getNumericCellValue(); // 인원수
// SQL 문자열 생성
String sql = String.format("INSERT INTO girl_groups (name, members) VALUES ('%s', %d);", name, members);
sqlBuilder.append(sql).append("\n");
}
// 3. 생성된 SQL 쿼리 출력
System.out.println(sqlBuilder.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
}
1) 파일 읽기
파일을 읽을 때는 FileInputStream을 사용하면 된다.
대상 파일 경로를 이용해 File객체를 생성한 뒤 FileInputStream의 생성자에 전달하여 객체를 생성한다.
try뒤의 괄호 안에서 객체를 선언하는 것을 `try-with-resources`라고 하는데 Java7 이상에서 사용가능 하다.
괄호 안 객체들인 자동으로 관리해 주기 때문에 close()를 신경 쓸 필요가 없다.
private static final String FILE_PATH = "src/main/resources/excel/girl_groups.xlsx"; // Excel 파일 경로
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream(new File(FILE_PATH));
Workbook workbook = new XSSFWorkbook(fis)) {
2) 데이터 읽기
향상된 for문을 사용해 해당 sheet의 모든 row를 읽어준다.
cell의 값을 가져오기 위해서는 해당값의 Cell 데이터 타입에 맞는 메서드를 사용하면 된다.
문자값은 `getStringCellValue();`
숫자값은 `getNumericCellValue();`
추가로 `getBooleanCellValue();` `getCellFormula();` 등을 사용할 수 있다.
❗데이터 타입에 맞지 않는 값을 가져오려고 할 경우 `IllegalStateException` 예외가 발생하니 주의하자.
for (Row row : sheet) {
if (row.getRowNum() == 0) continue; // 첫 번째 행(헤더) 건너뛰기
String name = row.getCell(1).getStringCellValue(); // 걸그룹 이름
int members = (int) row.getCell(2).getNumericCellValue(); // 인원수
// SQL 문자열 생성
String sql = String.format("INSERT INTO girl_groups (name, members) VALUES ('%s', %d);", name, members);
sqlBuilder.append(sql).append("\n");
}
콘솔창에 insert 쿼리문이 잘 생성되었다.
4. 마무리
보통 데이터를 다룰 때는 파이썬을 많이들 사용하는 것 같다.
하지만 자바에서도 충분히 가능하다.
바로 POI 덕분에 말이다.
데이터 관련 업무를 하게 되면 정말 많이 사용하기 때문에, 데이터를 처리해야 하는 자바 개발자라면 알아두면 좋을 것 같다.
엑셀의 굉장한 기능들을 java프로그램과 연계시키면 굉장히 시너지를 낼 수 있을 것이다.
'JAVA' 카테고리의 다른 글
[Java] IPinfo API 사용해 IP 위치 조회 기능 구현하기 (0) | 2025.02.23 |
---|---|
[Java] GeoLite2 사용해 IP 위치 조회 기능 구현하기 (0) | 2025.02.18 |
[Java] JVM(Java Virtual Machine)은 무엇이며 왜 좋은가? (0) | 2025.02.15 |
[Java] diamond operator is not supported 에러 (0) | 2025.02.14 |
[Java] Math.random()의 취약성과 시큐어 코딩 (0) | 2024.11.19 |