SpringBoot 엑셀 파일 읽기

아현·2022년 5월 17일
5

Spring

목록 보기
1/3

참고



1. POI


  • 마이크로소프트 오피스 파일 포맷(ex. xlsx, ppt ...)을 자바 언어로서 읽고 쓰는 기능을 제공해주는 라이브러리입니다.



의존성


SpringBoot에서 프로젝트를 만들 때 기본적으로 추가할 수 있는 의존성을 의미합니다

  • Web

  • Thymeleaf

  • Lombok



  1. 엑셀 파일을 읽기 위해 필요한 poi, poi-ooxml과

  2. 확장자를 가져오기 위해 필요한 commons-io를 추가해줍니다.


  • pom.xml

<dependency>
  <groupId>org.apache.poi</groupId>
  <artifactId>poi</artifactId>
  <version>3.11</version>
</dependency>
<dependency>
  <groupId>org.apache.poi</groupId>
  <artifactId>poi-ooxml</artifactId> <!-- 엑셀 2007 이상 버전에서 사용 -->
  <version>3.11</version>
</dependency>


<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>2.4</version>
</dependency>



2. 사용하기


파일 입력 폼


<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
  <head>
    <meta charset="UTF-8">
    <title>엑셀 업로드</title>
  </head>

  <body>
    <form th:action="@{/excel/read}" method="POST" enctype="multipart/form-data">
      <input type="file" th:name="file">
      <input th:type="submit" value="제출" />
    </form>
  </body>

</html>



객체 작성


  • 엑셀 데이터들을 넣어놓을 객체를 만들어줍니다.

    • 엑셀을 만들 때 순번, 이름, 이메일 항목이 있었기 때문에 다음과 같이 작성

  • ExcelData.java
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class ExcelData {

  private Integer num;

  private String name;

  private String email;
  
}



컨트롤러 작성


1) 엑셀 폼을 보여주는 매핑 메소드를 작성합니다.

2) @RequestParam을 이용해서 파일을 전달 받습니다. 자료형은 MultipartFile을 사용합니다.

3) 아까 추가해뒀던 commons-io에 있는 파일 확장자 가져오기 기능을 이용해서

  • 확장자를 가져오고 엑셀파일(xls, xlsx)이 아닌 경우에는 예외를 던집니다.

apache tika 사용해서 더 정교하게 파일 타입 검사하기

  • apache tika 라이브러리를 사용하면 파일 스트림의 앞에 매직 넘버를 읽어서 파일 타입을 유추하므로 확장자보다 좀 더 정확하게 읽을 수 있을 것 같습니다.

    • 의존성 추가 (build.gradle)
    • Tika 객체를 생성한 후에, detect(file)을 사용해서 MIME 타입 얻어내기 (ExcelController.java)
    • MIME 타입이 원하는 타입인지 확인 (ExcelUtils.java)

  • .txt 파일을 .xlsx로 속인 후에 올리면, 확장자만 가지고 비교하면 잡을 수 없지만, apache tika를 사용하게 되면 MIME 타입을 통해 가짜 파일을 필터링할 수 있다는 장점이 있습니다.

4) 행 개수만큼 반복문을 돌며 데이터를 가져옵니다.

  • getCell(열 번호)를 통해 가져올 수 있으며, 아래와 같은 메소드를 제공합니다.

  • getNumericCellValue() : 실수 데이터 가져오기

  • getStringCellValue() : 문자열 데이터 가져오기

  • getBooleanCellValue() : 논리 데이터 가져오기

5) 엑셀 데이터들을 넣어놓은 객체 리스트들을 반환합니다.


  • ExcelController.java
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.FilenameUtils;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

@Controller
public class ExcelController {

  @GetMapping("/excel")
  public String main() { // 1
    return "excel";
  }


  @PostMapping("/excel/read")
  public String readExcel(@RequestParam("file") MultipartFile file, Model model)
      throws IOException { // 2

    List<ExcelData> dataList = new ArrayList<>();

    String extension = FilenameUtils.getExtension(file.getOriginalFilename()); // 3

    if (!extension.equals("xlsx") && !extension.equals("xls")) {
      throw new IOException("엑셀파일만 업로드 해주세요.");
    }

    Workbook workbook = null;

    if (extension.equals("xlsx")) {
      workbook = new XSSFWorkbook(file.getInputStream());
    } else if (extension.equals("xls")) {
      workbook = new HSSFWorkbook(file.getInputStream());
    }

    Sheet worksheet = workbook.getSheetAt(0);

    for (int i = 1; i < worksheet.getPhysicalNumberOfRows(); i++) { // 4

      Row row = worksheet.getRow(i);

      ExcelData data = new ExcelData();

      data.setNum((int) row.getCell(0).getNumericCellValue());
      data.setName(row.getCell(1).getStringCellValue());
      data.setEmail(row.getCell(2).getStringCellValue());

      dataList.add(data);
    }

    model.addAttribute("datas", dataList); // 5

    return "excelList";

  }
}



리스트 작성


<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
</head>
<body>
  <table class="table table-striped">
    <thead>
    <tr>
      <th scope="col">#</th>
      <th scope="col">이름</th>
      <th scope="col">이메일</th>
    </tr>
    </thead>
    <tbody>
    <tr th:each="data : ${datas}" >
      <td scope="row" th:text="${data.num}"></td>
      <td th:text="${data.name}"></td>
      <td th:text="${data.email}"></td>
    </tr>
    </tbody>
  </table>
</body>
</html>



profile
Studying Computer Science

1개의 댓글

comment-user-thumbnail
2022년 5월 19일

엑셀 import만 나흘 동안 찾다가 겨우 발견했네요😭 생명의 은인이십니다
감사합니다

답글 달기