[Spring] SXSSFWorkbook + 데이터 페이징 처리를 통한 대용량 데이터 엑셀 파일 제작

김강욱·2024년 12월 23일
0

Spring

목록 보기
16/17
post-thumbnail

이번 포스팅에서는 이전 포스팅에 이어 Apache POI 라이브러리의 SXSSF를 이용하여 엑셀 파일을 생성하는 방법에 대해서 알아보려고 합니다.

[Spring] Apache POI를 사용하여 엑셀 데이터 처리하기

🔖 SXSSF란?

SXSSF는 Apach POI 라이브러리에서 제공하는 엑셀 스트리밍 API 중 하나입니다. 그럼 XSSF와의 차이점은 뭘까요?

XSSF는 메모리에 저장된 데이터를 사용하여 엑셀 문서를 생성하는 API로, 모든 엑셀 데이터를 메모리(RAM)에 올려놓고 작업을 하기 때문에 메모리 사용량이 많습니다.

반면, SXSSF는 데이터를 메모리에 올리지 않고 하드 디스크 등의 자원을 사용하여 임시 파일을 생성해 순차적으로 작업하기 때문에 메모리 사용량을 절감할 수 있습니다.

그렇기 때문에 SXSSF는 메모리 사용을 적게하면서 대용량 데이터를 처리할 수 있습니다.


🔖 임시 파일 저장 및 삭제

SXSSF가 임시 디렉토리에 임시 파일을 생성하여 작업을 하는 과정에 대해서 알아보도록 하겠습니다. 우선 SXSSF를 사용하면 엑셀 데이터를 기록할 때 임시 파일을 JVM의 기본 임시 디렉토리에 생성하게 됩니다.

즉, 아래 코드와 같이 SXSSFWorkbook를 생성하면 JVM의 기본 임시 디렉토리에 임시 파일로 저장하고 해당 파일에 엑셀 파일의 데이터를 누적하는 방식으로, 대규모 데이터 처리가 가능하도록 합니다.

  SXSSFWorkbook workbook = null;
try {
    workbook = new SXSSFWorkbook(defaultRowCount);
    // 워크북 작업 수행
} finally {
    if (workbook != null) {
        workbook.dispose(); // 임시 파일 삭제
    }
}

생성자에 defaultRowCount를 넣어서 한 번에 메모리에 유지되는 행(row)의 개수를 제한할 수 있습니다(기본값은 100행). 이 개수를 초과하면 기존 데이터를 임시 파일에 기록하고 메모리를 비웁니다.

Workbook 작업이 완료된 후, SXSSFWorkbook의 dispose() 메서드를 호출하면 생성했던 임시 파일이 자동으로 삭제되는 구조입니다. 이를 호출하지 않으면, JVM 종료 전까지 임시 파일이 남아 있을 수 있습니다.

하지만 dispose() 메서드는 현재 deprecated가 되었고 try-with-resources 문법을 통해 해결할 수 있습니다.

✔️ 참고
try-with-resources는 Java 7부터 자원을 자동으로 반납해주는 문법으로 자리 잡았습니다. AutoCloseable 인터페이스를 구현하고 있는 자원에 대해서만 적용이 가능합니다.


🧾 예시 코드

  @GetMapping("/엑셀다운로드배치")
    public void exportToExcelBatch(HttpServletResponse response) throws IOException {

        // 엑셀 파일의 컨텐츠 타입 및 헤더 설정
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Content-Disposition", "attachment; filename=place_export.xlsx");

        // 엑셀 워크북과 시트 생성
        try (SXSSFWorkbook workbook = new SXSSFWorkbook()) {

            Sheet sheet = workbook.createSheet("플레이스");
            // 1번째 줄: 메인 카테고리 헤더
            Row mainHeader = sheet.createRow(0);
            String[] mainHeaders = {"연번", "상호명", "기본정보"};
            int[] mainHeaderSpans = {1, 1, 34}; // 병합할 셀 개수

           
	          ... //헤더 생성

            // -------------------------- 데이터 쓰기 ----------------------
            int pageSize = 10; // 한 번에 가져올 데이터 수
            int rowIndex = 1; // 행 인덱스
            int page = 0;

            int rowNum = 3; // 데이터는 4번째 줄부터 시작

            while (true) {
                Pageable pageable = PageRequest.of(page, pageSize);
                Page<Place> placePage = placeRepository.findAll(pageable); // 페이징 조회

                if (placePage.isEmpty()) {
                    break; // 데이터가 없으면 종료
                }

								... // 셀 생성 및 스타일 주기
            

                page++; // 다음 페이지로 이동
            }


            workbook.write(response.getOutputStream());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

위의 코드에서는 while 문을 돌면서 해당하는 페이지 데이터를 DB에 조회해서 임시 파일에 누적시키고 while 문 이후에
workbook.write(response.getOutputStream()) 메서드를 통해 누적된 엑셀 데이터를 반환하는 작업을 수행합니다.

이처럼 대용량 데이터 처리를 할 때 XSSF보다 속도는 느리지만(하드웨어의 자원을 소모하기에) 메모리(RAM) 사용을 줄여 서버 자원 소모 부담을 줄이는 SXSSF를 이용하는 것이 효율적입니다.

profile
TO BE DEVELOPER

0개의 댓글

관련 채용 정보