본문 바로가기
TIL

Apache POI 및 엑셀 파일 생성 및 다운로드 예제

by jooany 2023. 10. 27.

Apache POI

사용자에게 요구 데이터를 보여 주는 방법은 여러가지가 있다. 보통은 웹 페이지의 화면으로 보여주는데 사용자의 요구사항에 따라 데이터를 엑셀 파일에 담아서 다운 받게 할 수 있다. 이를 위해 필요한 것이 Apache POI 라이브러리이다.

Apache POI 란?

Apache POI는 아파치 소프트웨어 재단에 의해 운영되는 오픈소스 프로젝트이다. 순수 자바 라이브러리로서 Microsoft Office의 Word, PowerPoint, Excel 형식의 파일을 읽고 쓸 수 있게 한다.

Apache POI 라이브러리 설치하기

maven 프로젝트의 pom.xml 파일에 poi와 poi--ooxml dependency 를 추가하여 POI 라이브러리를 설치한다.
https://mvnrepository.com/artifact/org.apache.poi/poi
https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml

        <!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>5.1.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>5.1.0</version>
        </dependency>

예제 ) POI를 이용하여 Excel 파일 생성 및 다운로드

예제에 들어가기 앞서 필자는 문서 화면에서 API를 테스트할 수 있는 Swagger 라이브러리를 사용하였다.

먼저, Swagger 라이브러리를 적용한 후, ExcelCtrlDoc.java 파일을 생성하여 Api 문서를 작성한다.

@Operation(summary = "메뉴 엑셀 다운로드")
  @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "성공", content = {
      @Content(mediaType = "application/json", schema = @Schema(implementation = MenuExcelDownloadResponse.class)) }), })
  abstract public void menuExcelDownload(HttpServletRequest request, HttpServletResponse response) throws Exception;

  public static class MenuExcelDownloadResponse extends ComResponseDto<Void> {
  }

이후 ExcelCtrlDoc.java를 상속받는 ExcelCtrl.java(컨트롤러)를 생성하여 context path에 /excel이 붙은 경로로 get 방식 http 통신을 할 메소드를 생성한다.

@GetMapping("/excel")
  public void menuExcelDownload(HttpServletRequest request, HttpServletResponse response) throws Exception {

  }

앞으로 이 메소드에 아래와 같은 API를 구현하기 위한 코드를 작성할 것이다.

 

엑셀 파일을 생성하여 시트/행/셀을 생성하고, 그 중 일부 셀은 병합한다. 각 셀에 데이터를 담고, 폰트 설정과 셀 스타일 설정을 한 다음, 브라우저에서 다운로드 할 수 있게 한다.

엑셀 파일 생성 및 데이터 추가

Excel의 기본적인 구성은 아래와 같다. 이를 알고 있으면 코드를 이해하기가 수월하다.

 

엑셀 파일 > 엑셀 시트 > 개별 행(Row) > 개별 셀(Cell)

 

  1. 워크북(액셀 파일)에 시트를 생성한다.
  2. 시트 안에 행, 행 안에 셀을 생성하고, 각 셀에 데이터를 담는다.
  3. 워크북을 엑셀 파일 형태로 저장한다.
@GetMapping("/excel")
    public void menuExcelDownload(HttpServletRequest request, HttpServletResponse response) throws Exception {
    /*--------(1)-------*/
        //  workbook 생성 (엑셀 파일 생성)
        SXSSFWorkbook workbook = new SXSSFWorkbook();

        // "시트이름" 이 이름인 시트를 생성한다.
        Sheet sheet = workbook.createSheet("시트이름");
    /*--------(2)-------*/
        // row는 열, 한 칸은 cell
        Row row = null;
        Cell cell = null;

        // 행은 8 행, 셀은 각 행에 총 4 칸씩 생성된다.
        for ( int i = 0; i < 8; i++) {
            row = sheet.createRow(i);

            for ( int j = 0 ; j < 4; j++) {
                cell = row.createCell(j);
        // i 행 j 칸에 "데이터"라는 값 추가
                cell.setCellValue("데이터");
            }
        }
    /*--------(3)-------*/
    // 엑셀 파일 형태로 저장하기
    //  HTTP 헤더 부분의 Content-Type을 이진 데이터로 정의한다.
        response.setContentType("application/octet-stream");
    // 브라우저에서 파일을 저장 또는 다름이름으로 저장 여부를 설정할 수 있게 하고, 파일 이름을 지정한다.
        response.setHeader("Content-Disposition","attachment; filename=\"menu.xlsx\"");

    //워크북을 생성된 menu.xlsx 엑셀 파일 형태로 저장
        workbook.write(response.getOutputStream());
    }
    • SXSSFWorkbook - 워크북(엑셀) 객체
    • Sheet - 시트 객체
    • Sheet createSheet(String sheetname) - 워크북(엑셀)에 sheetname을 이름으로 가지는 시트를 생성하는 메소드
    • Row - 행 객체
    • Cell - 셀 객체
    • Row createRow(int rownum) - 시트에 rownum 번째 행을 생성하는 메소드
    • Cell createCell(int column) - 행에 column 번째 셀을 생성하는 메소드
    • void setCellType(CellType cellType) - 셀에 "데이터" 값을 담는 메소드
    • void setContentType(String type) - HTTP 헤더 부분의 Content-Type을 정의하는 메소드 (실행 결과를 브라우저로 내보낼 때, HTML 브라우저로 전송하는 정보 타입을 정의하는 메소드)
    • application/octet-stream - 모든 이진 데이터(바이너리 데이터)를 전송하기 위한 8비트 단위의 MIME의 개별 타입
    • void setHeader(String name, String value) - name 헤더의 값을 value로 지정하는 메소드
    • "Content-Disposition","attachment; filename=\"menu.xlsx\"" - Content-Disposition 헤더의 값을 attachment 로 지정하면 해당 데이터를 수신받은 브라우저가 파일을 저장 또는 다른이름으로 저장 여부를 설정하게 할 수 있고, 컨텐츠를 로컬에서 다운로드 할 수 있다. filname 파라미터에 로컬에 저장되는 파일 이름을 지정해줄 수 있다.
    • write(OutputStream stream) - 워크북을 출력 스트림에 저장하는 메소드
    • OutputStream getOutputStream() - 출력 스트림을 얻는 메소드

스트림(stream)이란 데이터의 흐름이라고 할 수 있다.
우리는 스트림이라는 통로를 통해 원하는 데이터를 주고 받는 것이다.

  •  
  • 결과 이미지

셀 병합

셀 영역을 지정하여 병합하고, 병합한 셀 값에 "데이터 분류 명" 을 추가한다.

        for ( int i = 0; i < 8; i++) {
            row = sheet.createRow(i);

      // i(i=0)부터 i(i=0)행 까지 0번째 칸부터 3번째 칸까지 병합함.
            if(i==0) {
                sheet.addMergedRegion(new CellRangeAddress(i, i, 0, 3)); // 열시작, 열종료, 행시작, 행종료 
            }            
            for ( int j = 0 ; j < 4; j++) {
                cell = row.createCell(j);

                if(i==0) { //첫번째 행에 "데이터 분류 명" 셀 값 추가 
                    cell.setCellValue("데이터 분류 명");
                }else {
                    cell.setCellValue("데이터");
                }
            }
        }
  • int addMergedRegion(CellRangeAddress region) - 셀을 병합하는 메소드
  • CellRangeAddress(int firstRow, int lastRow, int firstCol, int lastCol) - 열시작, 열종료, 행시작, 행종료로 셀의 범위를 설정할 수 있는 객체

폰트 및 스타일 설정

셀 스타일 객체를 생성하고, 셀 스타일 설정 메소드를 사용하여 스타일 설정을 한다.
폰트 객체를 생성하고, 폰트 설정 메소드를 사용하여 폰트 설정을 담아서 스타일 객체에 폰트 객체를 적용시킨다.

 

<스타일 지정>
폰트 스타일 : bold, 14pt
셀 스타일 : 배경(노란색,가득찬 패턴), 테두리, 수평 및 수직 중앙 정렬
    // 스타일 객체 생성
        CellStyle titleStyle = workbook.createCellStyle();

        // 배경 색상 및 패턴
        titleStyle.setFillForegroundColor(IndexedColors.YELLOW.index);
        titleStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);

        // 아래,위,왼,오른쪽 테두리 적용  
        titleStyle.setBorderBottom(BorderStyle.THIN);
        titleStyle.setBorderTop(BorderStyle.THIN);
        titleStyle.setBorderLeft(BorderStyle.THIN);
        titleStyle.setBorderRight(BorderStyle.THIN);

        // 수평 중앙 정렬 
        titleStyle.setAlignment(HorizontalAlignment.CENTER);
        // 수직 중앙 정렬 
        titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);

    // 폰트 객체 생성
        Font titleFont = workbook.createFont();
        // 폰트 설정
        titleFont.setBold(true);
        titleFont.setFontHeightInPoints((short)14);
    // 폰트 스타일 적용
        titleStyle.setFont(titleFont);
  • CellStyle - 셀 스타일 객체
  • CellStyle createCellStyle() - 셀 스타일을 생성하고, 워크북의 스타일 테이블에 저장하는 메소드
  • void setFillForegroundColor(short bg) - 전경색을 지정하는 메소드
  • IndexedColors.YELLOW.index - 노란색
  • void setFillPattern(FillPatternType fp) - 셀을 전경색으로 채우기 위한 메소드
  • FillPatternType.SOLID_FOREGROUND - 전경을 채우기 위한 값
  • void setBorder[Bottom/Top/Left/Right] (BorderStyle border) - 셀의 아래 테두리/위 테두리/왼쪽 테두리/오른쪽 테두리를 설정할 수 있는 메소드
  • BorderStyle.THIN - 얇은 테두리
  • void setAlignment(HorizontalAlignment align) - 셀 수평 정렬 메소드
  • HorizontalAlignment.CENTER - 수평 중앙 정렬
  • void setVerticalAlignment(VerticalAlignment align) - 셀 수직 정렬 메소드
  • VerticalAlignment.CENTER - 수직 중앙 정렬
  • Font - 폰트 객체
  • void setBold(boolean bold) - 폰트 두께를 굵게(bold)로 설정하는 메소드
  • void setFontHeightInPoints(short height) - 폰트 크기를 설정하는 메소드
  • void setFont(Font font) - 셀 스타일에 폰트 설정을 담는 메소드

최종결과물 전체코드

@GetMapping("/excel")
    public void menuExcelDownload(HttpServletRequest request, HttpServletResponse response) throws Exception {

        SXSSFWorkbook workbook = new SXSSFWorkbook();
        Sheet sheet = workbook.createSheet("시트이름");
        Row row = null;
        Cell cell = null;

        Font titleFont = workbook.createFont();
        titleFont.setBold(true);
        titleFont.setFontHeightInPoints((short)14);

        CellStyle titleStyle = workbook.createCellStyle();
        titleStyle.setFont(titleFont);
        titleStyle.setFillForegroundColor(IndexedColors.YELLOW.index);
        titleStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);

        titleStyle.setBorderBottom(BorderStyle.THIN);
        titleStyle.setBorderTop(BorderStyle.THIN);
        titleStyle.setBorderLeft(BorderStyle.THIN);
        titleStyle.setBorderRight(BorderStyle.THIN);

        titleStyle.setAlignment(HorizontalAlignment.CENTER);
        titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);

        for ( int i = 0; i < 8; i++) {
            row = sheet.createRow(i);
            if(i==0) {
                sheet.addMergedRegion(new CellRangeAddress(i, i, 0, 3));
            }            
            for ( int j = 0 ; j < 4; j++) {
                cell = row.createCell(j);
                if(i==0) { //첫번째 ROW에만 STYLE 적용하기
                    cell.setCellValue("데이터 분류 명");
                    cell.setCellStyle(titleStyle);
                }else {
                    cell.setCellValue("데이터");
                }
            }
        }

        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition","attachment; filename=\"menu.xlsx\"");

        workbook.write(response.getOutputStream());
        workbook.close();

    }

 

 

더 많은 poi 라이브러리에 정의된 객체, 메소드, 설정값 등의 정보가 궁금하다면, 아래의 링크를 통해 찾아볼 수 있다.
https://poi.apache.org/apidocs/4.0/org/apache/poi/ss/usermodel